I need to sign some data with the SHA256withRSA
algorithm (RSASSA-PKCS1-V1_5-SIGN
with SHA-256
hash function) in Windows (and with Delphi or in c++). How can I do this? I want to use the Windows CryptoAPI.
This is how I do to verify a signature :
function ALVerifyRSA256Signature(const aData: AnsiString; // bytes string
const aSignature: AnsiString; // bytes string
const aBase64PubKeyModulus: ansiString;
Const aBase64PubKeyExponent: ansiString): boolean;
{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
procedure _bigEndianToLittleEndian(var aArr: TBytes);
var B: Byte;
i,j: integer;
begin
J := Length(aArr) - 1;
i := low(aArr);
while i < J do begin
B := aArr[i];
aArr[i] := aArr[j];
aArr[j] := B;
Dec(j);
inc(i);
end;
end;
var pModulus: TBytes;
cbModulus: DWORD;
pExponent: TBytes;
cbExponent: DWORD;
dwExponent: Dword;
hProv: HCRYPTPROV;
cbKeyBlob: DWord;
pKeyBlob: Tbytes;
pPublicKey: PUBLICKEYSTRUC;
pRsaPubKey: RSAPUBKEY;
hRSAKey: HCRYPTKEY;
hHash: HCRYPTHASH;
pSignature: TBytes;
begin
//init pModulus / cbModulus
if not CryptStringToBinaryA(
PansiChar(aBase64PubKeyModulus), // pszString: LPCSTR;
length(aBase64PubKeyModulus), // cchString: DWORD;
CRYPT_STRING_BASE64, // dwFlags: DWORD;
nil, // pbBinary: pByte;
@cbModulus, // pcbBinary: PDWORD;
nil, // pdwSkip: PDWORD;
nil) then raiseLastOsError; // pdwFlags: PDWORD
setlength(pModulus, cbModulus);
if not CryptStringToBinaryA(
PansiChar(aBase64PubKeyModulus), // pszString: LPCSTR;
length(aBase64PubKeyModulus), // cchString: DWORD;
CRYPT_STRING_BASE64, // dwFlags: DWORD;
@pModulus[0], // pbBinary: pByte;
@cbModulus, // pcbBinary: PDWORD;
nil, // pdwSkip: PDWORD;
nil) then raiseLastOsError; // pdwFlags: PDWORD
_bigEndianToLittleEndian(pModulus);
//init pExponent / cbExponent
if not CryptStringToBinaryA(
PansiChar(aBase64PubKeyExponent), // pszString: LPCSTR;
length(aBase64PubKeyExponent), // cchString: DWORD;
CRYPT_STRING_BASE64, // dwFlags: DWORD;
nil, // pbBinary: pByte;
@cbExponent, // pcbBinary: PDWORD;
nil, // pdwSkip: PDWORD;
nil) then raiseLastOsError; // pdwFlags: PDWORD
setlength(pExponent, cbExponent);
if not CryptStringToBinaryA(
PansiChar(aBase64PubKeyExponent), // pszString: LPCSTR;
length(aBase64PubKeyExponent), // cchString: DWORD;
CRYPT_STRING_BASE64, // dwFlags: DWORD;
@pExponent[0], // pbBinary: pByte;
@cbExponent, // pcbBinary: PDWORD;
nil, // pdwSkip: PDWORD;
nil) then raiseLastOsError; // pdwFlags: PDWORD
_bigEndianToLittleEndian(pExponent);
if cbExponent > sizeof(dwExponent) then
raise Exception.CreateFmt('Wrong exponent (%s)',[aBase64PubKeyExponent]);
dwExponent := 0;
move(pExponent[0], dwExponent, cbExponent);
//acquire a handle to a particular key container
if (not CryptAcquireContextA(@hProv, // phProv: PHCRYPTPROV;
nil, // pszContainer: PAnsiChar;
nil, // pszProvider: PAnsiChar;
PROV_RSA_AES, // dwProvType: DWORD;
CRYPT_VERIFYCONTEXT)) then raiselastOsError; // dwFlags: DWORD
try
// create the pKeyBlob
// The data format is: PUBLICKEYSTRUC + RSAPUBKEY + key
cbKeyBlob := sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + cbModulus;
setlength(pKeyBlob, cbKeyBlob);
// Fill in the PUBLICKEYSTRUC
pPublicKey.bType := PUBLICKEYBLOB;
pPublicKey.bVersion := CUR_BLOB_VERSION; // Always use this value.
pPublicKey.reserved := 0; // Must be zero.
pPublicKey.aiKeyAlg := CALG_RSA_KEYX; // RSA public-key key exchange.
Move(pPublicKey,pKeyBlob[0],sizeof(PUBLICKEYSTRUC));
// Fill in the RSAPUBKEY
pRsaPubKey.magic := RSA1; // Public key.
pRsaPubKey.bitlen := cbModulus * 8; // Number of bits in the modulus.
pRsaPubKey.pubexp := dwExponent; // Exponent.
Move(pRsaPubKey,pKeyBlob[sizeof(PUBLICKEYSTRUC)],sizeof(RSAPUBKEY));
// Fill in the modulus
Move(pModulus[0],pKeyBlob[sizeof(PUBLICKEYSTRUC)+sizeof(RSAPUBKEY)],cbModulus);
// Now import the key.
if not CryptImportKey(hProv, // hProv: HCRYPTPROV;
@pKeyBlob[0], // const pbData: PBYTE;
cbKeyBlob, // dwDataLen: DWORD;
0, // hPubKey: HCRYPTKEY;
0, // dwFlags: DWORD;
@hRSAKey) then raiseLastOsError; // phKey: PHCRYPTKEY
try
//initiates the hashing of a stream of data.
if not (CryptCreateHash(hProv, // hProv: HCRYPTPROV;
CALG_SHA_256, // Algid: ALG_ID;
0, // hKey: HCRYPTKEY;
0, // dwFlags: DWORD;
@hHash)) then raiseLastOsError;
try
//adds data to a specified hash object.
if not (CryptHashData(hHash, // hHash: HCRYPTHASH;
pbyte(aData), // const pbData: PBYTE;
length(aData), // dwDataLen: DWORD;
0)) then raiseLastOsError; // dwFlags: DWORD
//verifies the signature
setlength(pSignature, length(aSignature));
Move(Pointer(aSignature)^, Pointer(pSignature)^, Length(aSignature));
_bigEndianToLittleEndian(pSignature);
if not CryptVerifySignatureA(hHash, // hHash: HCRYPTHASH;
@pSignature[0], // const pbSignature: PBYTE;
length(pSignature), // dwSigLen: DWORD;
hRSAKey, // hPubKey: HCRYPTKEY;
nil, // const sDescription: LPCSTR;
0) then begin // dwFlags: DWORD)
if HRESULT(GetLastError) = NTE_BAD_SIGNATURE then exit(False)
else raiseLastOsError;
end;
//everything is ok
Result := True;
finally
if not CryptDestroyHash(hHash) then raiseLastOsError;
end;
finally
if not CryptDestroyKey(hRSAKey) then raiseLastOsError;
end;
finally
if not CryptReleaseContext(hProv,0) then raiseLastOsError;
end;
end;
However in my case I need to sign some data using this private_key :
"-----BEGIN PRIVATE KEY-----\xxxxxxxxxxxxxxxxxxx\n-----END PRIVATE KEY-----\n"
How I can do?