From Grandville.net

OpenSSL: Rsa-cryptoapi-openssl

Les structures de stockage de Microsoft ont la particularité de ne pas être chiffrées et d'être au format little-endian contrairement à OpenSSL qui travaille en big-endian. Le résultat est que toutes les structures doivent être inversées lors du passage d'un monde à l'autre, heureusement depuis la version 0.9.8h des options non documentées ont été ajoutées aux commandes OpenSSL pour faciliter l'interopérabilité.

Quelques exemples d'utilisation des librairies CryptoAPI

création d'une clé asymétrique

// longueur de la clé 1024 = 1024 << 16 
#define KEYLENGTH 0x04000000

void dump(TCHAR *dest,BYTE* pBuffer,DWORD& dwSize)
{
        FILE* file;
        file = _tfopen(dest,TEXT("wb"));
        fwrite(pBuffer,sizeof(BYTE),dwSize,file);
        fclose(file);
}


int cipherdecipher()
{
        DWORD dwFlags = 0;
        HCRYPTPROV hProv=NULL;
        HCRYPTKEY hPrivateKey;
        BYTE* pbPublicKeyBlob=NULL,*pbPrivateKeyBlob=NULL;
        DWORD dwPublicKeyBlobLen=0,dwPrivateKeyBlobLen=0;
        DWORD dwBlockLen=0,dwBlockSize=0;
        DWORD dwDataLen;
        BYTE *pbBuffer;
        DWORD dwBufferSize;


        CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, dwFlags);
        // create RSA keys
        CryptGenKey(hProv, CALG_RSA_KEYX,  KEYLENGTH | CRYPT_EXPORTABLE, &hPrivateKey);

        //export public key
        CryptExportKey(hPrivateKey, NULL, PUBLICKEYBLOB, 0, NULL, &dwPublicKeyBlobLen);
        pbPublicKeyBlob = (BYTE*) malloc(dwPublicKeyBlobLen);
        CryptExportKey(hPrivateKey, NULL, PUBLICKEYBLOB, 0, pbPublicKeyBlob, &dwPublicKeyBlobLen);
        dump(_T("c:\\tmp\\pub.rsa"),pbPublicKeyBlob,dwPublicKeyBlobLen);

        //export private key
        CryptExportKey(hPrivateKey, NULL, PRIVATEKEYBLOB, 0, NULL, &dwPrivateKeyBlobLen);
        pbPrivateKeyBlob = (BYTE*) malloc(dwPrivateKeyBlobLen);
        CryptExportKey(hPrivateKey, NULL, PRIVATEKEYBLOB, 0, pbPrivateKeyBlob, &dwPrivateKeyBlobLen);
        dump(_T("c:\\tmp\\priv.rsa"),pbPrivateKeyBlob,dwPrivateKeyBlobLen);

        // get the cipher block length
        dwDataLen=sizeof(dwBlockLen);
        CryptGetKeyParam(hPrivateKey, KP_BLOCKLEN, (LPBYTE)&dwBlockLen,&dwDataLen,0);
        dwBlockSize = dwBlockLen/8;

        pbBuffer = (BYTE*) malloc(dwBlockSize);
        dwBufferSize = dwBlockSize-11; //padding PKCS #1 v1.5
        for(UINT i =0; i<dwBufferSize; i++){pbBuffer[i] = i+32;}

        CryptEncrypt(hPrivateKey, NULL, FALSE, 0, pbBuffer, &dwBufferSize, dwBlockSize);
        dump(_T("c:\\tmp\\cipher.bin"),pbBuffer,dwBufferSize);
        CryptDecrypt(hPrivateKey, NULL, FALSE, 0, (BYTE *)pbBuffer, &dwBufferSize);

        free(pbBuffer);
        free(pbPrivateKeyBlob);
        free(pbPublicKeyBlob);
        CryptDestroyKey(hPrivateKey);
        CryptReleaseContext(hProv,0);

        return 0;
}

Trois fichiers ont été créés: pub.rsa, priv.rsa et cipher.bin.

La clef privée est capable de coder/décoder.

Les fichiers devront être transformés en base64 pour être réintroduits dans les codes par la commande ci-dessous

openssl base64 -in priv.rsa -A -e
BgIAAACkAABSU0ExAAQAAAEAAQCxDs+RugWaFnQVMdZhirCBxQ5b2bpJtk24B6nediR933O2x9GynHDJ/WUPDnBuPcsw1JCZhsb0P2QUs9KU+iV2P7rJn2dREEjOJ82bN/Y6t4mp65JrOXdFhgtJPG9YbRcOQKNftnqr/OrwxjQcok9T63vaTgR+7JXuir3KFB5PrA==

chiffrement avec la clé publique

int simplecipher()
{
        TCHAR szPub[]=_T("BgIAAACkAABSU0ExAAQAAAEAAQCxDs+RugWaFnQVMdZhirCBxQ5b2bpJtk24B6nediR933O2x9GynHDJ/WUPDn\
BuPcsw1JCZhsb0P2QUs9KU+iV2P7rJn2dREEjOJ82bN/Y6t4mp65JrOXdFhgtJPG9YbRcOQKNftnqr/OrwxjQcok9T63vaTgR+7JXuir3KFB5PrA=="
);
        DWORD dwFlags = 0;
        HCRYPTPROV hProv=NULL;
        HCRYPTKEY hPublicKey;
        DWORD dwPubKeySize=0;
        BYTE* pbPubKey;
        DWORD dwBlockLen=0,dwDataLen=0;
        BYTE *pbBuffer;
        DWORD dwBufferSize;
        DWORD dwBlockSize=0;


        CryptStringToBinary(szPub,0,CRYPT_STRING_BASE64,NULL,&dwPubKeySize,0,0);
        pbPubKey = (BYTE*)malloc(dwPubKeySize);
        CryptStringToBinary(szPub,0,CRYPT_STRING_BASE64,pbPubKey,&dwPubKeySize,0,0);

        CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, dwFlags);
        CryptImportKey(hProv,pbPubKey,dwPubKeySize,0,CRYPT_EXPORTABLE,&hPublicKey);

        dwDataLen=sizeof(dwBlockLen);
        CryptGetKeyParam(hPublicKey, KP_BLOCKLEN, (LPBYTE)&dwBlockLen,&dwDataLen,0);

        dwBlockSize = dwBlockLen/8;
        pbBuffer = (BYTE*) malloc(dwBlockSize);
        dwBufferSize = dwBlockSize-11; //padding PKCS #1 v1.5
        for(UINT i =0; i<dwBufferSize; i++){pbBuffer[i] = i+32;}

        CryptEncrypt(hPublicKey, NULL, FALSE, 0, pbBuffer, &dwBufferSize, dwBlockSize);
        dump(_T("c:\\tmp\\cipher.bin"),pbBuffer,dwBufferSize);

        free(pbPubKey);
        free(pbBuffer);
        CryptDestroyKey(hPublicKey);
        CryptReleaseContext(hProv,0);

        return 0;
}

déchiffrement avec la clef privée

int simpledecipher()
{
        TCHAR szPriv[]=_T("BwIAAACkAABSU0EyAAQAAAEAAQB3yEczW8w8N5/YC5cfOrhGAxRAmCl1uN0BzTei\
CAXuCQNjY2LEhx1Vits2GeSVqtn7m774ta2+3WnIHhZByJjH4a5ad2KYqZOVAne/\
jhKByD3XApgT1ocACdb6md3Whbf7n5miUFsHVVY8wqVIh1HpDR3tnhtSoTYMVJFg\
A7ILx4Hr8XQC2t7q6uD3UY0622kmqR3jQ0kmOvek6qWr0o9sB+aPbisjUh4RKdMC\
w+4JWvgF9Vbnk9HlH7lHuMxJyP73D5FNRmmjLMFNQ4Dk23gS8h4C0x0x0AeK6USZ\
ZG/EXiWTFy8Jvwb/sdgzBngiw+GHa+SgnixtVl0DMDBnN//HAcYXWHGVmCwaQEFY\
PoARWH1PVfZQ8/pCdHb1ju8O/5jTETtBuj3b3J1aP2QxL07zmsi//RWXXmLnd0d8\
aIQhKdeOOibcvSLKCZcvOrv+SSSaZPhSQZ2uYYCENu93gLm5q57j3iuzxwUagKXA\
HRIcBU0LR3kw52V89YG+To2TFlq77KYZS98otYMqEYy+1dyL3mWLK7Y3X61Op9pU\
1hdaVOLMgNhvYmoV71oHUIF368lOHR7LUNu2vufyGClFcQpZAQJW5+VGQ8iJfBfQ\
NA8LDhlcCO30LkGriG4lmHkHj6gxjFhRwsZA3h/HvWAZDUYX3+syF+m8KQ1ZWEwo\
KhGbvFu486whDGAbHSQ2fHmZbAN3kPodkl/DMrqEFiXePpjzRC2aYRpKFfWK/tVQ\
Yvs0eGZOd/U0epXgMJp7NOyhHzQ="
);
        TCHAR szCipher[]=_T("GV5v/edRWPFxuK0vG8UP0/vZ2m8U62xrvJLHLnuMuxbs6RumLqspT2dnU38HXjWSRaAH/EWoUWwkdMyUq3/fAsmO+vef6Xf0yUcg50Vy2wFkZdWpw3+htJ3eJaOo8nV1aXyRghR38C7/fRoDfmReIHH/cB+Udx7AgEY4LMCZiWM=");

        HCRYPTPROV hProv=NULL;
        HCRYPTKEY hPrivateKey;
        DWORD dwPrivateKeySize;
        BYTE *pbPrivateKey;
        DWORD dwCipherSize;
        BYTE* pbCipher;
        DWORD dwFlags=0;

        CryptStringToBinary(szPriv,0,CRYPT_STRING_BASE64,NULL,&dwPrivateKeySize,0,0);
        pbPrivateKey = (BYTE*)malloc(dwPrivateKeySize);
        CryptStringToBinary(szPriv,0,CRYPT_STRING_BASE64,pbPrivateKey,&dwPrivateKeySize,0,0);

        CryptStringToBinary(szCipher,0,CRYPT_STRING_BASE64,NULL,&dwCipherSize,0,0);
        pbCipher = (BYTE*)malloc(dwCipherSize);
        CryptStringToBinary(szCipher,0,CRYPT_STRING_BASE64,pbCipher,&dwCipherSize,0,0);

        CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, dwFlags);
        CryptImportKey(hProv,pbPrivateKey,dwPrivateKeySize,0,CRYPT_EXPORTABLE,&hPrivateKey);

        CryptDecrypt(hPrivateKey, NULL, FALSE, 0, (BYTE *)pbCipher, &dwCipherSize);


        return 0;


}

Comme dit plus haut, OpenSSL est capable d'interpréter nativement les structures spécifiques de Microsoft grâce à un nouveau format de certificat le MS, n'oublions pas non plus d'inverser le flux chiffré par la commande -rev et voici le résultat:

openssl rsautl -in cipher.bin -inkey priv.rsa -keyform MS -decrypt -rev
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôö

Retrieved from http://www.grandville.net?n=OpenSSL.Rsa-cryptoapi-openssl
Page last modified on June 12, 2010, at 06:20 PM