From Grandville.net

OpenSSL: Rsa-cryptoapi-openssl-sign

La signature avec des clefs asymétriques est presque identique au chiffrement sauf que l'utilisation des clefs est inversée (la clef privée signe et la clef publique vérifie) et que windows n'accepte de chiffrer qu'un hash.

création des clefs

C:\>openssl genrsa -out privateKey.pem 1024
Loading 'screen' into random state - done
Generating RSA private key, 1024 bit long modulus
...................++++++
....................++++++
e is 65537 (0x10001)

C:\>openssl rsa -in privateKey.pem -outform M -out privateKeyMS.bin
writing RSA key

C:\>openssl rsa -in privateKey.pem -outform M -out publicKeyMS.bin -pubout

writing RSA key

Les fichiers privateKeyMS.bin et publicKeyMS.bin transformés en Base64 deviennent respectivement les variables PVK et PUB du code ci-dessous.

génération et vérification de la signature


void reverse(LPBYTE pBuffer,DWORD& dwLen) {
        DWORD i;
        BYTE ctmp;
        for(i = 0; i < dwLen/2; i++) {
                ctmp = pBuffer[i];
                pBuffer[i] = pBuffer[dwLen - 1 - i];
                pBuffer[dwLen - 1 - i] = ctmp;
        }
}

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

int signcheck()
{

        TCHAR szPub[]=
                _T("BgIAAACkAABSU0ExAAQAAAEAAQClA7b53n9m6jzweqDdYBS+HekcQmc1QIW/tgKzma8Z0WWiMEkw7UQH")
                _T("OAnqcFY1sjLMt2q3plFkEnN+7udIkBbkEgMSJDgF/jAwmKPe6cNf6+69r/OlkTfrNC2lq9+ArOvsAtti")
                _T("nZNp5njq3nubWacKGZGiSPQVqENmWMQktD2dwg==");
        TCHAR szPriv[]=
                _T("BwIAAACkAABSU0EyAAQAAAEAAQClA7b53n9m6jzweqDdYBS+HekcQmc1QIW/tgKzma8Z0WWiMEkw7UQH")
                _T("OAnqcFY1sjLMt2q3plFkEnN+7udIkBbkEgMSJDgF/jAwmKPe6cNf6+69r/OlkTfrNC2lq9+ArOvsAtti")
                _T("nZNp5njq3nubWacKGZGiSPQVqENmWMQktD2dwoFf41MHhZV8MER35ap07lff1WgdBrLN8zh2SuAxJdMw")
                _T("69FsFqR9SFUno/b79MUMZCllI+MQealbJT2pHLnP2OMlNrQ9/S64L1maPshFQplacjSY8kuUoPq8iBtl")
                _T("Dqlq49L5OliRDp5kBh0Fqs0RX7DxOSbDvFpJZ0mRpqLyOKnaAdVbIHLGIwpFSMKN2C4hSfKlLsPPpNwt")
                _T("mbS12f/UgPu6eR29jEbkRvEPXQG9Z+LnKn7ju9jne6CHotUEG9QB0TmpI+4K9dMGQn46Wf1AFl7vE+s2")
                _T("MFN4BzVHEIGme/cvrI0prez5C/apixGQB0o+Ge1GznRs7o+8G1xZfFimWh1jPwboiZPpsdk6Y9tbkOA+")
                _T("GJ8FtEn9bgHIv5joIbElhBz5amMSbYI9cdYzhPFBWJOVubBWyRhMt3ph4uRY1xgfAWpxrq0yal7Vc4Zd")
                _T("MAD85Rw7x2XUeoMWidxfpeQtdChLOTdbVkm1ZFbEFY5TjFQs/EkBfBG5puKtNnW6wqrLoBhScFzC6M6q")
                _T("5mG5oqH0GlsD7dXD6kYaC2Osl64tfvkSY8LfvNsnjQs3MUrhXA9+f0X4DS7fKvjX0AD/7jsU8ls=");

        HCRYPTPROV hProv=NULL;
        HCRYPTKEY hPublicKey,hPrivateKey;
        DWORD dwPublicKeySize=0,dwPrivateKeySize=0;
        BYTE *pbPublicKey,*pbPrivateKey;
        DWORD dwSignSize=0;
        BYTE *pbSign;
        HCRYPTHASH hHash;
        DWORD dwFlags=0;

        CryptStringToBinary(szPub,0,CRYPT_STRING_BASE64,NULL,&dwPublicKeySize,0,0);
        pbPublicKey = (BYTE*)malloc(dwPublicKeySize);
        CryptStringToBinary(szPub,0,CRYPT_STRING_BASE64,pbPublicKey,&dwPublicKeySize,0,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);

        BYTE* pbStream=(BYTE*)"here is the text you would like to sign";
        DWORD dwStreamSize=strlen((char*)pbStream);


        CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, dwFlags);

        CryptCreateHash(hProv,CALG_SHA1, 0, 0, &hHash);
        CryptHashData(hHash,pbStream,dwStreamSize,0);
        BYTE bHash[20]={0};
        DWORD dwHashLength = 20;
        CryptGetHashParam(hHash,HP_HASHVAL,bHash,&dwHashLength ,0);

        CryptImportKey(hProv,pbPrivateKey,dwPrivateKeySize,0,CRYPT_EXPORTABLE,&hPrivateKey);


        if(!CryptSignHash(hHash,AT_KEYEXCHANGE, NULL,0, NULL, &dwSignSize))
                goto checksignend;
        pbSign = (BYTE*)malloc(dwSignSize);
        CryptSignHash(hHash,AT_KEYEXCHANGE, NULL,CRYPT_NOHASHOID, pbSign, &dwSignSize);


        reverse(pbSign,dwSignSize);
        dump(_T("C:\\text.sign"),pbSign,dwSignSize);
        reverse(pbSign,dwSignSize);




        // let's do a check

        CryptImportKey(hProv,pbPublicKey,dwPublicKeySize,0,CRYPT_EXPORTABLE,&hPublicKey);
        if(!CryptVerifySignature(hHash, pbSign, dwSignSize,hPublicKey,NULL,0))
                goto checksignend;

        printf("OK");

checksignend:
        if(hHash)
                CryptDestroyHash(hHash);
        if(hProv)
                CryptReleaseContext(hProv, 0);
        if(pbSign)
                delete pbSign;
        if(pbPrivateKey)
                delete pbPrivateKey;
        if(pbPublicKey)
                delete pbPublicKey;

        return 0;

}
 

le fichier text.sign contient la signature du message pbStream, vérifions cela

C:\>openssl rsautl -in text.sign -inkey publicKeyMS.bin -keyform MS -verify -pubin -hexdump
Loading 'screen' into random state - done
0000 - ba 68 93 b5 cc 99 60 69-f0 15 c2 52 2d ce d5 7f .h....`i...R-...
0010 - 0c d0 34 d7 ..4.

Ce qui correspond bien au SHA1 de ce fichier contenant les mêmes données

C:\Dev\java>openssl dgst -sha1 -hex text.txt
SHA1(text.txt)= ba6893b5cc996069f015c2522dced57f0cd034d7

Une méthode est spécialement prévue pour checker une signature, mais elle ne semble pas fonctionner avec openssl 1.0.0

openssl dgst -sha -verify publicKeyMS.bin -keyform MS -signature text.sign text.txt
Verification Failure

Retrieved from http://www.grandville.net?n=OpenSSL.Rsa-cryptoapi-openssl-sign
Page last modified on June 02, 2010, at 03:22 PM