2017-06-01 8 views
0

J'ai lu dans this question sur Importer une clé publique à partir de composants natifs. J'ai essayé de faire la même chose pour la clé privée basée sur la documentation BLOB, mais j'obtiens une erreur NTE_BAD_DATA.C++ Importer une clé privée RSA dans CAPI/CNG à partir de xml

Est-ce que mon idée est faisable? Si oui, pouvez-vous m'aider?

Mon Essayez:

void old_RSA_decrypt(PBYTE blob, DWORD blobSize) 
{ 
    HCRYPTPROV hCryptProv = NULL; 
    HCRYPTKEY hKey = NULL; 
    DWORD dwDecryptedLen = 0; 
    DWORD length; 
    std::ifstream f; 
    f.open("c:\\Programming\\encrypted.txt", std::ios::binary); 
    if (!f.is_open()) 
    { 
     std::cout << "Error on open file: " << GetLastError() << std::endl; 
     return; 
    } 

    f.seekg(0, f.end); 
    length = f.tellg(); 
    f.seekg(0, f.beg); 

    char * buffer = new char[length]; 
    f.read(buffer, length); 

    if (!f) 
     std::cout << "error: only " << f.gcount() << " could be read" << std::endl; 
    f.close(); 

    PBYTE bBuffer = (PBYTE)buffer; 

    //now to get the decryption thing going 

    if (!CryptAcquireContext(
     &hCryptProv, 
     NULL, 
     MS_STRONG_PROV, 
     PROV_RSA_FULL, 
     CRYPT_VERIFYCONTEXT)) 

    { 
     std::cout << "Error on CryptAcquireContext " << GetLastError() << std::endl; 
     return; 
    } 
    if (!CryptImportKey(
     hCryptProv, 
     blob, 
     blobSize, 
     NULL, 
     0, 
     &hKey)) 
    { 
     std::cout << "Error on CryptImportKey " << GetLastError() << std::endl; 
     return; 
    } 
    if (!CryptDecrypt(hKey, NULL, TRUE, 0, NULL, &dwDecryptedLen)) 
    { 
     std::cout << "Error on CryptDecrypt (First Pass) " << GetLastError() << std::endl; 
     return; 
    } 
    PBYTE decBuffer = new BYTE[dwDecryptedLen]; 
    for(int i = 0; i < length ; ++i) 
     decBuffer[i] = bBuffer[i]; 

    if (!CryptDecrypt(hKey, NULL, TRUE, 0, decBuffer, &length)) 
    { 
     std::cout << "Error on CryptDecrypt (Second Pass) " << GetLastError() << std::endl; 
     return; 
    } 
    std::cout << "Yurika2!" << std::endl; 
    std::ofstream of; 
    of.open("c:\\Programming\\decrypted.txt", std::ios::binary); 
    if (!of.is_open()) 
    { 
     std::cout << "Error on open write file: " << GetLastError() << std::endl; 
     return; 
    } 
    string sDecMsg = string(reinterpret_cast<char*>(decBuffer), length); 
    of << sDecMsg << std::endl; 
    of.close(); 
cleanup: 
    delete[] buffer; 
    delete[] decBuffer; 

} 

void do_decrypt() 
{ 
    string modStr = "yVUndgQFuB5Z5FgC0/WgWCg6Y8VuB582avGjQDdeoJDa1+RBKCyXo700sAMSGjM/bVakOlFqvCsVFNBysx1CH731CDb2DR1a0bsmYmDQ9d0ZHX+AOohVDIx9mc7bkDQZoEFpe9NqFsu95Y9yktpl1JKPmKyLOFgufGJYYvQyoOM="; 
    string expStr = "AQAB"; 
    string PStr = "/JydNn89lSWjgWOG1XRJm1qTWDekzzoLfTQU+GK+h8DGQ6gkUbgqGosLGo+eAxbO/ETZV3ibbBuIdvL4UxC5Qw=="; 
    string QStr = "zAh23Gc8Oqz/Uh2wh+yt8DqUesVLwMn2koc9CbyF9/Z5Qe8OIR4yygJtuYruRC1x/KYj85l6DGzstUZOtYmv4Q=="; 
    string DPStr ="+1INj1SUPjjOLUKJuQAS4z7/7PqfO5RyLcSNQHltOb5vAozcZXkmWnYPPAO6nzQoBg+xdDcH2kyiPkWJDYtL5Q=="; 
    string DQStr = "cbYh8HJEufrijTRox0hcJG+xgr7kmjy1BDMFDKEaFPkz2VBPEpwO+FDkMC1C35JoXcOGc+RMhhJK1jip8zkaYQ=="; 
    string InverseQStr = "3PAXzlAXgvLVrbOEygjA2zhJEYALBEi6VTKqfDKlnv8/D9QUkC39bEDIRLG0wMFFxN8NlLx5zTiiVswxnMy8Mw=="; 
    string DStr = "KKBSyKkyID+bowyxcWUAuJlRgv19YPNbL0RYTWZ+5UalqmfoT/uDk+pjndrYxcmulFkl5ZC1SYgmBl+zrXoLc/Ei86BtNiuwfcqHlUDp0fdP+fyYN45wh/251HQ3UM1zBpMP8XeYB6zjpCU/s3/wCBE6WpJWN9fKcG0W5PLq8eE="; 

    //FROM STRINGS TO BYTE VECTORS! 
    vector<BYTE> modBinMSB = base64_decode(modStr); 
    vector<BYTE> expBinMSB = base64_decode(expStr); 
    vector<BYTE> PBinMSB = base64_decode(PStr); 
    vector<BYTE> QBinMSB = base64_decode(QStr); 
    vector<BYTE> DPBinMSB = base64_decode(DPStr); 
    vector<BYTE> DQBinMSB = base64_decode(DQStr); 
    vector<BYTE> InverseQBinMSB = base64_decode(InverseQStr); 
    vector<BYTE> DBinMSB = base64_decode(DStr); 

    //TURN MSB TO LSB 

    DWORD offset = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY); // to keep track of things 
    const DWORD modulusLengthInBytes = 128; 
    DWORD keyBlobLength = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + (modulusLengthInBytes * 4) + (modulusLengthInBytes/2); 
    BYTE* keyBlob = (PBYTE)malloc(keyBlobLength); 
    BLOBHEADER* blobheader = (BLOBHEADER*)keyBlob; 
    blobheader->bType = PRIVATEKEYBLOB; 
    blobheader->bVersion = CUR_BLOB_VERSION; 
    blobheader->reserved = 0; 
    blobheader->aiKeyAlg = CALG_RSA_KEYX; 
    RSAPUBKEY* rsapubkey = (RSAPUBKEY*)(keyBlob + sizeof(BLOBHEADER)); 
    rsapubkey->magic = 0x31415352; 
    rsapubkey->bitlen = modulusLengthInBytes * 8 *4 + modulusLengthInBytes*4; 
    rsapubkey->pubexp = MSBByteVectorToDword(expBinMSB); 

    BYTE* modulus = keyBlob + offset; 
    copyReversed(modBinMSB, modulus); 
    offset += modulusLengthInBytes; 
    BYTE* prime1 = keyBlob + offset ; 
    copyReversed(PBinMSB, prime1); 
    offset += modulusLengthInBytes/2; 
    BYTE* prime2 = keyBlob + offset; 
    copyReversed(QBinMSB, prime2); 
    offset += (modulusLengthInBytes/2); 
    BYTE* exponent1 = keyBlob + offset; 
    copyReversed(DPBinMSB, exponent1); 
    offset += (modulusLengthInBytes/2); 
    BYTE* exponent2 = keyBlob + offset; 
    copyReversed(DQBinMSB, exponent2); 
    offset += (modulusLengthInBytes/2); 
    BYTE* coefficient = keyBlob + offset; 
    copyReversed(InverseQBinMSB, coefficient); 
    offset += modulusLengthInBytes/2; 
    BYTE* privateExponent = keyBlob + offset; 
    copyReversed(DBinMSB, privateExponent); 

    old_RSA_decrypt(keyBlob, keyBlobLength); 
} 

Répondre

0

Il est certainement possible de le faire. Vous avez mentionné les deux piles crypto de Windows, et il y a quelques différences:

  • Encoding:
    • CAPI: tous les champs de longueur variable sont peu endian. CNG: tous les champs de longueur variable sont big-endian.
  • Rigidité:
    • CAPI: le module et D doivent avoir la même longueur. De même, P, Q, DP, DQ, InverseQ ont tous la même longueur (qui doit être la moitié (arrondie à la hausse) de la longueur du module). CNG: les clés privées ne demandent que n, e, p et q ... et vous spécifiez la longueur de chaque champ séparément.

Je vois une erreur évidente dans votre code:

rsapubkey->bitlen = modulusLengthInBytes * 8 *4 + modulusLengthInBytes*4; 

par the documentation:

bitlen

Nombre de bits dans le module. En pratique, cela doit toujours être un multiple de huit.

Alors que

rsapubkey->bitlen = modulusLengthInBytes * 8; 

Votre réglage de la valeur dwMagic semble être trop incorrect,.

rsapubkey->magic = 0x31415352; 

0x31415352 est RSA_PUB_MAGIC, vous vous appelez donc une clé publique. Vous voulez RSA_PRIV_MAGIC (et utiliser la constante).

rsapubkey->magic = RSA_PRIV_MAGIC; 

Comparer à l'http://source.dot.net/#System.Security.Cryptography.Csp/System/Security/Cryptography/CapiHelper.Shared.cs,b7bc764e6deb34f5, qui est un écrivain travaillant blob en C#.

+0

Essayé votre avis, aucun effet perceptible. D'autres idées? –

+0

Votre valeur pour 'magic' semble également suspecte. Mise à jour de la réponse, et inclus un lien vers le blob écrivain .NET. – bartonjs

+0

Cela a fait l'affaire, merci. Pour référence future, la magie devrait être 0x32415352, comme indiqué ici: https://msdn.microsoft.com/en-us/library/windows/desktop/aa375601(v=vs.85).aspx#priv_BLOB –