STATUS_INVALID_PARAMETER error import diffie hellman public key using BCryptImportKeyPair

681 views Asked by At

I am trying to add a public key into diffie Hellman implementation of Bcrypt. example suggested to create and export a public key. In my case I already got the public key from the client. I am trying to use that public key to generate shared session key. I get STATUS_INVALID_PARAMETER when i try to use BCryptImportKeyPair. I created PBCRYPT_DH_KEY_BLOB and added the values manually. Is there any other way to do this? an example of importing public key into BCrypt from string would be appreciated.

Thanks in Advance. Please check the code below.

KeyLength = 1024;//bits
const int sz = 1024;
char * shared_public_key = "48DE15D8E46B857B387E315D518B7D9EDDA1FCA6661CFC9C066B3A352E8644A30BFBB7F84C93818F67B7037235D11A5B0F31E15BCB344C2A7C13E339ED98939CF3F092E64C0DEA28A150404432E3B7077DE3E4D40E421EA88FFAF4D7AD53851912389674B24C80E5FD05D1C60344535159E7A4CAF9F9DCAF712C2A41EF524632";
char * prime      = "CBBD1F895B751A803674B4CF6178DAFF87E3AADD017B96CA0D536215091AC55C0D777ADB6206581E7681C5059BEFF7990E4B3DD074266B608800CF7110BE99B861D189A82A26D569CAA2F314E8E79838AEE8DA96380BDFA55B34CA43866B24C0A822947E669C9AA037A8FA765F637663AB4103A9251C70000A689796CE42A2A3";
BYTE OakleyGroup1P[sz /8];
int fld_sz = sz / 8;
string s_prime(prime, fld_sz*2);
transform(s_prime.begin(), s_prime.end(), s_prime.begin(), ::tolower);
string res = "";
for (int i = 0; i < s_prime.size(); i += 2) {
  res += s_prime.substr(i, 2);
  res += " ";
}
std::istringstream hex_chars_stream(res);

unsigned int c;
int i = 0;
while (hex_chars_stream >> std::hex >> c)
{
  OakleyGroup1P[i++] = c;
}
cout << "size of OakleyGroup1P :" << i << endl;
/*for (unsigned char x : OakleyGroup1P) {
  cout << ((x >> 4) & 0x0F) << " " << (x & 0x0F) << endl;
}*/

PBYTE PubBlobA2 = new BYTE[sz/8];
string s_shared(shared_public_key, fld_sz * 2);
transform(s_shared.begin(), s_shared.end(), s_shared.begin(), ::tolower);
string temp = "";
for (int i = 0; i < s_shared.size(); i += 2) {
  temp += s_shared.substr(i, 2);
  temp += " ";
}
std::istringstream hex_chars_stream2(temp);

i = 0;
while (hex_chars_stream2 >> std::hex >> c)
{
  PubBlobA2[i++] = c;
}
cout << "size of PubBlobA2 :" << i << endl;
for (int j = 0; j < i; j++) {
  cout << ((*(PubBlobA2 + j) >> 4) & 0x0F) << " " << (*(PubBlobA2 + j) & 0x0F) << endl;
}

//
// Construct the DH parameter blob. this is the only supported
// method for DH in CNG.
//
// Calculate size of param blob and allocate memory

DhParamBlobLength = sizeof(BCRYPT_DH_PARAMETER_HEADER) + 
                sizeof(OakleyGroup1G) + 
                sizeof(OakleyGroup1P);

DhParamBlob = (PBYTE)HeapAlloc (
                                    GetProcessHeap (), 
                                    0, 
                                    DhParamBlobLength);
if( NULL == DhParamBlob )
{
    Status = STATUS_NO_MEMORY;
    ReportError(Status);
    goto cleanup;
}

DhParamHdrPointer  = (BCRYPT_DH_PARAMETER_HEADER *)DhParamBlob;

//
// Set header properties on param blob
//

DhParamHdrPointer->cbLength      = DhParamBlobLength;
DhParamHdrPointer->cbKeyLength   = KeyLength/8;//bytes
DhParamHdrPointer->dwMagic       = BCRYPT_DH_PARAMETERS_MAGIC;

//
// Set prime
//

memcpy(DhParamBlob + sizeof(BCRYPT_DH_PARAMETER_HEADER),
        OakleyGroup1P,
        sizeof(OakleyGroup1P));

//
// Set generator
//

memcpy(DhParamBlob + sizeof(BCRYPT_DH_PARAMETER_HEADER) + sizeof(OakleyGroup1P),
       OakleyGroup1G,
       sizeof(OakleyGroup1G));


//
// Open alg provider handle
//

Status = BCryptOpenAlgorithmProvider(
                                    &ExchAlgHandleB, 
                                    BCRYPT_DH_ALGORITHM, 
                                    NULL, 
                                    0);
if( !NT_SUCCESS(Status) )
{
    ReportError(Status);
    goto cleanup;
}



//
// B generates a private key
// 

Status = BCryptGenerateKeyPair(
                                    ExchAlgHandleB,             // Algorithm handle
                                    &PrivKeyHandleB,            // Key handle - will be created
                                    KeyLength,                  // Length of the key - in bits
                                    0);                         // Flags
if( !NT_SUCCESS(Status) )
{
    ReportError(Status);
    goto cleanup;
}

Status = BCryptSetProperty(
                                    PrivKeyHandleB,
                                    BCRYPT_DH_PARAMETERS,
                                    DhParamBlob,
                                    DhParamBlobLength,
                                    0);
if( !NT_SUCCESS(Status) )
{
    ReportError(Status);
    goto cleanup;
}

Status = BCryptFinalizeKeyPair(
                                    PrivKeyHandleB,             // Key handle
                                    0);                         // Flags
if( !NT_SUCCESS(Status) )
{
    ReportError(Status);
    goto cleanup;
}

//
// B exports DH public key
//

Status = BCryptExportKey(
                                    PrivKeyHandleB,             // Handle of the key to export
                                    NULL,                       // Handle of the key used to wrap the exported key
                                    BCRYPT_DH_PUBLIC_BLOB,      // Blob type (null terminated unicode string)
                                    NULL,                       // Buffer that recieves the key blob
                                    0,                          // Buffer length (in bytes)
                                    &PubBlobLengthB,            // Number of bytes copied to the buffer
                                    0);                         // Flags
if( !NT_SUCCESS(Status) )
{
    ReportError(Status);
    goto cleanup;
}

PubBlobB = (PBYTE)HeapAlloc (
                                    GetProcessHeap (), 
                                    0, 
                                    PubBlobLengthB);
if( NULL == PubBlobB )
{
    Status = STATUS_NO_MEMORY;
    ReportError(Status);
    goto cleanup;
}


Status = BCryptExportKey(
                                    PrivKeyHandleB,             // Handle of the key to export
                                    NULL,                       // Handle of the key used to wrap the exported key
                                    BCRYPT_DH_PUBLIC_BLOB,      // Blob type (null terminated unicode string)
                                    PubBlobB,                   // Buffer that recieves the key blob
                                    PubBlobLengthB,             // Buffer length (in bytes)
                                    &PubBlobLengthB,            // Number of bytes copied to the buffer
                                    0);                         // Flags
if( !NT_SUCCESS(Status) )
{
    ReportError(Status);
    goto cleanup;
}


//
// Build KDF parameter list
//

//specify hash algorithm, SHA1 if null

//specify secret to append
BufferArray[0].BufferType = KDF_TLS_PRF_SEED;
BufferArray[0].cbBuffer = sizeof(rgbrgbTlsSeed);
BufferArray[0].pvBuffer = (PVOID)rgbrgbTlsSeed;

//specify secret to prepend
BufferArray[1].BufferType = KDF_TLS_PRF_LABEL;
BufferArray[1].cbBuffer = (DWORD)((wcslen(Label) + 1) * sizeof(WCHAR));
BufferArray[1].pvBuffer = (PVOID)Label;

ParameterList.cBuffers  = 2;
ParameterList.pBuffers  = BufferArray;
ParameterList.ulVersion = BCRYPTBUFFER_VERSION;

//
// B imports A's public key
//
// dh public key blob structure
PBCRYPT_DH_KEY_BLOB p_dh_pub_key_blob = (PBCRYPT_DH_KEY_BLOB)HeapAlloc(
  GetProcessHeap(),
  0,
  sizeof(BCRYPT_DH_KEY_BLOB));
p_dh_pub_key_blob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC;
p_dh_pub_key_blob->cbKey = sz/8;
DWORD df_pub_key_data_length = sizeof(BCRYPT_DH_KEY_BLOB) + sz / 8;

PBYTE p_df_pub_key_data = (PBYTE)HeapAlloc(
  GetProcessHeap(),
  0,
  df_pub_key_data_length);
memcpy(p_df_pub_key_data,
  p_dh_pub_key_blob,
  sizeof(BCRYPT_DH_KEY_BLOB));
memcpy(p_df_pub_key_data + sizeof(BCRYPT_DH_KEY_BLOB),
  PubBlobA2,
  sz/8);
Status = BCryptImportKeyPair(
  ExchAlgHandleB,             // Alg handle
  NULL,                       // Parameter not used
  BCRYPT_DH_PUBLIC_BLOB,      // Blob type (Null terminated unicode string)
  &PubKeyHandleB,             // Key handle that will be recieved
  p_df_pub_key_data,            // Buffer than points to the key blob
  df_pub_key_data_length,     // Buffer length in bytes
  0);    
0

There are 0 answers