我需要使用c ++创建服务器和客户端,到目前为止,xchange diffie hellman公共密钥和使用AES 256进行加密,我正在使用MSDN示例进行DH公共密钥创建https://docs.microsoft.com/en-us/windows/win32/seccrypto/diffie-hellman-keys,并且在两端都使用RC4可以很好地使用它(客户端和服务器) ),但是如果我将hSessionKey转换为AES 256,我会在客户端的EncryptDecrypt API上收到错误0x80090005(NET_BAD_DATA),但是如果客户端和服务器都在同一台计算机上运行(不是同一操作系统),结果就可以了!我真的迷路了。
任何帮助将不胜感激。
服务器端:
#define WIN32_LEAN_AND_MEAN
# define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <Windows.h>
#include <wincrypt.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
//#pragma comment(lib, "Msvsock.lib")
#pragma comment (lib , "AdvApi32.lib")
#pragma comment(lib, "crypt32.lib")
// The key size, in bits.
#define DHKEYSIZE 512
#define DEFAULT_BUFLEN 1024
// Prime in little-endian format.
static const BYTE g_rgbPrime[] =
{
0x91, 0x02, 0xc8, 0x31, 0xee, 0x36, 0x07, 0xec,
0xc2, 0x24, 0x37, 0xf8, 0xfb, 0x3d, 0x69, 0x49,
0xac, 0x7a, 0xab, 0x32, 0xac, 0xad, 0xe9, 0xc2,
0xaf, 0x0e, 0x21, 0xb7, 0xc5, 0x2f, 0x76, 0xd0,
0xe5, 0x82, 0x78, 0x0d, 0x4f, 0x32, 0xb8, 0xcb,
0xf7, 0x0c, 0x8d, 0xfb, 0x3a, 0xd8, 0xc0, 0xea,
0xcb, 0x69, 0x68, 0xb0, 0x9b, 0x75, 0x25, 0x3d,
0xaa, 0x76, 0x22, 0x49, 0x94, 0xa4, 0xf2, 0x8d
};
// Generator in little-endian format.
static BYTE g_rgbGenerator[] =
{
0x02, 0x88, 0xd7, 0xe6, 0x53, 0xaf, 0x72, 0xc5,
0x8c, 0x08, 0x4b, 0x46, 0x6f, 0x9f, 0x2e, 0xc4,
0x9c, 0x5c, 0x92, 0x21, 0x95, 0xb7, 0xe5, 0x58,
0xbf, 0xba, 0x24, 0xfa, 0xe5, 0x9d, 0xcb, 0x71,
0x2e, 0x2c, 0xce, 0x99, 0xf3, 0x10, 0xff, 0x3b,
0xcb, 0xef, 0x6c, 0x95, 0x22, 0x55, 0x9d, 0x29,
0x00, 0xb5, 0x4c, 0x5b, 0xa5, 0x63, 0x31, 0x41,
0x13, 0x0a, 0xea, 0x39, 0x78, 0x02, 0x6d, 0x62
};
BYTE g_rgbData[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
int main()
{
WSADATA wsaData;
SOCKET ListenSocket;
struct sockaddr_in client;
int iResult;
char * binaryBuffer = NULL;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup failed with error: %d\n", iResult);
return 0;
}
BYTE* pubKeyBuffer;
pubKeyBuffer = (BYTE*)malloc(1024);
ZeroMemory(pubKeyBuffer, 1024);
BOOL fReturn;
HCRYPTPROV hProvParty1 = NULL;
HCRYPTPROV hCryptProv = NULL;
DATA_BLOB P;
DATA_BLOB G;
HCRYPTKEY hPrivateKey1 = NULL;
//HCRYPTKEY hPrivateKey2 = NULL;
PBYTE pbKeyBlob1 = NULL;
PBYTE pbKeyBlob2 = NULL;
HCRYPTKEY hKey = NULL;
HCRYPTKEY hSessionKey2 = NULL;
PBYTE pbData = NULL;
HCRYPTHASH hHash = NULL;
/************************
Construct data BLOBs for the prime and generator. The P and G
values, represented by the g_rgbPrime and g_rgbGenerator arrays
respectively, are shared values that have been agreed to by both
parties.
************************/
P.cbData = DHKEYSIZE / 8;
P.pbData = (BYTE*)(g_rgbPrime);
G.cbData = DHKEYSIZE / 8;
G.pbData = (BYTE*)(g_rgbGenerator);
/************************
Create the private Diffie-Hellman key for party 1.
************************/
// Acquire a provider handle for party 1.
fReturn = CryptAcquireContext(&hProvParty1, NULL,MS_ENH_DSS_DH_PROV,PROV_DSS_DH,CRYPT_VERIFYCONTEXT);
if (!fReturn)
{
return 0;
}
// Create an ephemeral private key for party 1.
fReturn = CryptGenKey(hProvParty1, CALG_DH_EPHEM, DHKEYSIZE << 16 | CRYPT_EXPORTABLE | CRYPT_PREGEN, &hPrivateKey1);
if (!fReturn)
{
return 0;
}
// Set the prime for party 1's private key.
fReturn = CryptSetKeyParam( hPrivateKey1,KP_P,(PBYTE)&P,0);
if (!fReturn)
{
return 0;
}
// Set the generator for party 1's private key.
fReturn = CryptSetKeyParam( hPrivateKey1,KP_G,(PBYTE)&G,0);
if (!fReturn)
{
return 0;
}
// Generate the secret values for party 1's private key.
fReturn = CryptSetKeyParam(hPrivateKey1,KP_X,NULL, 0);
if (!fReturn)
{
return 0;
}
DWORD dwDataLen1;
// Get the size for the key BLOB.
fReturn = CryptExportKey( hPrivateKey1,NULL, PUBLICKEYBLOB, 0, NULL, &dwDataLen1);
if (!fReturn)
{
return 0;
}
// Allocate the memory for the key BLOB.
if (!(pbKeyBlob1 = (PBYTE)malloc(dwDataLen1)))
{
return 0;
}
// Get the key BLOB.
fReturn = CryptExportKey(hPrivateKey1, 0,PUBLICKEYBLOB,0,pbKeyBlob1,&dwDataLen1);
if (!fReturn)
{
return 0;
}
//memcpy_s(pubKeyBuffer, 1024, &dwDataLen1, sizeof(DWORD));
memcpy_s(pubKeyBuffer , 1024, pbKeyBlob1, dwDataLen1);
struct addrinfo* result = NULL,
*ptr = NULL;
char keyBuffer[1024] = { 0 };
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in serverHint;
serverHint.sin_addr.S_un.S_addr = ADDR_ANY; // Us any IP address available on the machine
serverHint.sin_family = AF_INET; // Address format is IPv4
serverHint.sin_port = htons(13000); // Convert from little to big endian
if (bind(ListenSocket, (sockaddr*)&serverHint, sizeof(serverHint)) == SOCKET_ERROR)
{
wprintf(L"bind failed with error %d\n", WSAGetLastError());
//cout << "Can't bind socket! " << WSAGetLastError() << endl;
return 0;
}
listen(ListenSocket, 2);
int c;
int quitreceived = 0;
c = sizeof(struct sockaddr_in);
SOCKET newsocket = accept(ListenSocket, (SOCKADDR *)&client, (socklen_t *)&c);
//int ires = recv(newsocket, recvbuf, DEFAULT_BUFLEN, 0);
int ires1 = recv(newsocket, keyBuffer, DEFAULT_BUFLEN, 0);
iResult = send(newsocket, (const char*)pubKeyBuffer, 1024, 0);
if (iResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(newsocket);
WSACleanup();
return 0;
}
DWORD dwDataLen2;
memcpy_s(&dwDataLen2, 4, keyBuffer, 4);
// Allocate the memory for the key BLOB.
if (!(pbKeyBlob2 = (PBYTE)malloc(1024)))
{
return 0;
}
memcpy_s(pbKeyBlob2, 1024, keyBuffer , 1024);
DWORD err;
fReturn = CryptImportKey(hProvParty1,pbKeyBlob2,dwDataLen2, hPrivateKey1,0, &hSessionKey2);
if (!fReturn)
{
err = GetLastError();
return 0;
}
DWORD dwpassLength = 32;// (DWORD)strlen(szPassword);
fReturn = CryptAcquireContext( &hCryptProv,NULL, MS_ENH_RSA_AES_PROV,PROV_RSA_AES,0);
if (!fReturn)
{
return 0;
}
fReturn = CryptCreateHash( hCryptProv, CALG_SHA_256,0, 0, &hHash);
if (!fReturn)
{
return 0;
}
fReturn = CryptHashData(hHash, (BYTE*)hSessionKey2,dwpassLength,0);
if (!fReturn)
{
return 0;
}
hKey = (HCRYPTKEY )(malloc(100));
fReturn = CryptDeriveKey(hCryptProv,CALG_AES_128,hHash, CRYPT_EXPORTABLE,
&hKey);
if (!fReturn)
{
return 0;
}
DWORD dwLength = sizeof(g_rgbData);
fReturn = CryptEncrypt( hKey,0,TRUE,0,NULL, &dwLength,sizeof(g_rgbData));
if (!fReturn)
{
DWORD error12 = GetLastError();
return 0;
//return false;
}
DWORD dwpbdataLength = dwLength;
BYTE * pbEncryptedData = (PBYTE)malloc(dwpbdataLength);
memset(pbEncryptedData, 0, dwpbdataLength);
if (!pbEncryptedData)
{
return 0;
}
memcpy(pbEncryptedData, g_rgbData, sizeof(g_rgbData));
dwLength = sizeof(g_rgbData);
//iResult = send(newsocket, (const char*)&dwpbdataLength, sizeof(DWORD), 0);
fReturn = CryptEncrypt( hKey,NULL, TRUE,0, pbEncryptedData,&dwLength, dwpbdataLength);
if (!fReturn)
{
DWORD error12 = GetLastError();
return 0;
}
iResult = send(newsocket, (const char*)pbEncryptedData, dwLength, 0);
if (iResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(newsocket);
WSACleanup();
return 0;
}
/*fReturn = CryptDecrypt( hKey,0, TRUE,0, pbEncryptedData,&dwLength);
if (!fReturn)
{
DWORD err12 = GetLastError();
return 0;
}*/
if (hProvParty1)
{
CryptReleaseContext(hProvParty1, 0);
hProvParty1 = NULL;
}
closesocket(ListenSocket);
WSACleanup();
return 0;
}
客户:
#define WIN32_LEAN_AND_MEAN
#include <tchar.h>
#include <windows.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <wincrypt.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment (lib , "AdvApi32.lib")
#pragma comment(lib, "crypt32.lib")
#define DEFAULT_PORT "13000"
#define DHKEYSIZE 512
#define DEFAULT_BUFLEN 1024
BOOL Connect_To_Server(PCSTR remote_IP_Add, SOCKET* connection_socket);
static const BYTE g_rgbPrime[] =
{
0x91, 0x02, 0xc8, 0x31, 0xee, 0x36, 0x07, 0xec,
0xc2, 0x24, 0x37, 0xf8, 0xfb, 0x3d, 0x69, 0x49,
0xac, 0x7a, 0xab, 0x32, 0xac, 0xad, 0xe9, 0xc2,
0xaf, 0x0e, 0x21, 0xb7, 0xc5, 0x2f, 0x76, 0xd0,
0xe5, 0x82, 0x78, 0x0d, 0x4f, 0x32, 0xb8, 0xcb,
0xf7, 0x0c, 0x8d, 0xfb, 0x3a, 0xd8, 0xc0, 0xea,
0xcb, 0x69, 0x68, 0xb0, 0x9b, 0x75, 0x25, 0x3d,
0xaa, 0x76, 0x22, 0x49, 0x94, 0xa4, 0xf2, 0x8d
};
static BYTE g_rgbGenerator[] =
{
0x02, 0x88, 0xd7, 0xe6, 0x53, 0xaf, 0x72, 0xc5,
0x8c, 0x08, 0x4b, 0x46, 0x6f, 0x9f, 0x2e, 0xc4,
0x9c, 0x5c, 0x92, 0x21, 0x95, 0xb7, 0xe5, 0x58,
0xbf, 0xba, 0x24, 0xfa, 0xe5, 0x9d, 0xcb, 0x71,
0x2e, 0x2c, 0xce, 0x99, 0xf3, 0x10, 0xff, 0x3b,
0xcb, 0xef, 0x6c, 0x95, 0x22, 0x55, 0x9d, 0x29,
0x00, 0xb5, 0x4c, 0x5b, 0xa5, 0x63, 0x31, 0x41,
0x13, 0x0a, 0xea, 0x39, 0x78, 0x02, 0x6d, 0x62
};
//BYTE g_rgbData[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
int _tmain(int argc, _TCHAR* argv[])
{
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
int iResult;
//int breacktheloop = 0;
char * binaryBuffer = NULL;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup failed with error: %d\n", iResult);
return 0;
}
BYTE* pubKeyBuffer;
pubKeyBuffer = (BYTE*)malloc(1024);
ZeroMemory(pubKeyBuffer, 1024);
BOOL fReturn;
HCRYPTPROV hProvParty1 = NULL;
HCRYPTPROV hCryptProv = NULL;
DATA_BLOB P;
DATA_BLOB G;
HCRYPTKEY hPrivateKey1 = NULL;
//HCRYPTKEY hPrivateKey2 = NULL;
PBYTE pbKeyBlob1 = NULL;
PBYTE pbKeyBlob2 = NULL;
HCRYPTKEY hKey = NULL;
HCRYPTKEY hSessionKey2 = NULL;
//PBYTE pbData = NULL;
HCRYPTHASH hHash = NULL;
P.cbData = DHKEYSIZE / 8;
P.pbData = (BYTE*)(g_rgbPrime);
G.cbData = DHKEYSIZE / 8;
G.pbData = (BYTE*)(g_rgbGenerator);
fReturn = CryptAcquireContext(&hProvParty1, NULL, MS_ENH_DSS_DH_PROV, PROV_DSS_DH,CRYPT_VERIFYCONTEXT);
if (!fReturn)
{
return 0;
}
fReturn = CryptGenKey(hProvParty1, CALG_DH_EPHEM, DHKEYSIZE << 16 | CRYPT_EXPORTABLE | CRYPT_PREGEN, &hPrivateKey1);
if (!fReturn)
{
return 0;
}
fReturn = CryptSetKeyParam( hPrivateKey1,KP_P,(PBYTE)&P,0);
if (!fReturn)
{
return 0;
}
fReturn = CryptSetKeyParam( hPrivateKey1,KP_G,(PBYTE)&G,0);
if (!fReturn)
{
return 0;
}
fReturn = CryptSetKeyParam( hPrivateKey1,KP_X, NULL,0);
if (!fReturn)
{
return 0;
}
DWORD dwDataLen1;
fReturn = CryptExportKey(hPrivateKey1, NULL,PUBLICKEYBLOB, 0,NULL, &dwDataLen1);
if (!fReturn)
{
return 0;
}
if (!(pbKeyBlob1 = (PBYTE)malloc(dwDataLen1)))
{
return 0;
}
fReturn = CryptExportKey(hPrivateKey1, 0,PUBLICKEYBLOB,0, pbKeyBlob1, &dwDataLen1);
if (!fReturn)
{
return 0;
}
//memcpy_s(pubKeyBuffer, 1024, &dwDataLen1, sizeof(DWORD));
memcpy_s(pubKeyBuffer , 1024, pbKeyBlob1, dwDataLen1);
struct addrinfo* result = NULL,
*ptr = NULL;
char recvbuf[1026] = { 0 };
char keyBuffer[1024] = { 0 };
int recvbuflen = DEFAULT_BUFLEN;
BOOL res = Connect_To_Server("192.168.224.1", &ConnectSocket);//192.168.224.144
iResult = send(ConnectSocket, (const char*)pubKeyBuffer, 1024, 0);
if (iResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
int ires1 = recv(ConnectSocket, keyBuffer, DEFAULT_BUFLEN, 0);
DWORD dwDataLen2;
memcpy_s(&dwDataLen2, 4, keyBuffer, 4);
if (!(pbKeyBlob2 = (PBYTE)malloc(1024)))
{
return 0;
}
memcpy_s(pbKeyBlob2, 1024, keyBuffer , 1024);
DWORD err;
fReturn = CryptImportKey(hProvParty1,pbKeyBlob2,dwDataLen2, hPrivateKey1,0, &hSessionKey2);
if (!fReturn)
{
err = GetLastError();
return 0;
}
/////////////////////
//char sizeBuffer[sizeof(DWORD)] = { 0 };
// ires1 = recv(ConnectSocket, sizeBuffer, sizeof(DWORD), 0);
// int sizeofbytes = strtoul(sizeBuffer, L'\0', 0);
BYTE * pbEncryptedData = (PBYTE)malloc(1024);
memset(pbEncryptedData, 0, 1024);
if (!pbEncryptedData)
{
return 0;
}
ires1 = recv(ConnectSocket, (char *)pbEncryptedData, DEFAULT_BUFLEN, 0);
//DWORD dwDataLen2;
DWORD dwpassLength = 32;// (DWORD)strlen(szPassword);
fReturn = CryptAcquireContext(&hCryptProv,NULL, MS_ENH_RSA_AES_PROV,PROV_RSA_AES,0);
if (!fReturn)
{
return 0;
}
fReturn = CryptCreateHash(hCryptProv,CALG_SHA_256,0,0,&hHash);
if (!fReturn)
{
return 0;
}
fReturn = CryptHashData(hHash,(BYTE*)hSessionKey2,dwpassLength, 0);
if (!fReturn)
{
return 0;
}
fReturn = CryptDeriveKey(hCryptProv,CALG_AES_256,hHash, CRYPT_EXPORTABLE,&hKey);
if (!fReturn)
{
return 0;
}
DWORD dlength = 16;
fReturn = CryptDecrypt( hKey,0, TRUE,0, pbEncryptedData,&dlength);
if (!fReturn)
{
err = GetLastError();
return 0;
}
if (hPrivateKey1)
{
CryptDestroyKey(hPrivateKey1);
hPrivateKey1 = NULL;
}
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
BOOL Connect_To_Server(PCSTR remote_IP_Add, SOCKET * connection_socket)
{
int iResult;
struct addrinfo* result = NULL, *ptr = NULL, hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo(remote_IP_Add, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
return false;
}
// Attempt to connect to an address until one succeeds
for (ptr = result; ptr != NULL; ptr = ptr->ai_next)
{
// Create a SOCKET for connecting to server
*connection_socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (*connection_socket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
return false;
}
// Connect to server.
iResult = connect(*connection_socket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(*connection_socket);
*connection_socket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (*connection_socket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return false;
}
return true;
}
根据页面https://docs.microsoft.com/en-us/windows/win32/seccrypto/base-provider-algorithms,此调用不支持CALG_AES_256。