Created
November 25, 2017 10:37
-
-
Save soxfmr/21606281118227abc63ce98f865d511e to your computer and use it in GitHub Desktop.
An example of using PEM encoded RSA private keys with CAPI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* An example of using PEM encoded RSA private keys with CAPI | |
* - Modified on March 29th 2014 to show how to use PEM encoded RSA public key | |
* | |
* Copyright (c) 2012 Mounir IDRASSI <[email protected]>. All rights reserved. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
* or FITNESS FOR A PARTICULAR PURPOSE. | |
* | |
*/ | |
#ifndef _WIN32_WINNT | |
#define _WIN32_WINNT 0x0501 | |
#endif | |
#include <windows.h> | |
#include <wincrypt.h> | |
#include <stdio.h> | |
const char* szPemPrivKey = | |
"-----BEGIN RSA PRIVATE KEY-----" | |
"MIICXAIBAAKBgQCf6YAJOSBYPve1jpYDzq+w++8YVoATI/YCi/RKZaQk+l2ZfoUQ" | |
"g0qrYrfkzeoOa/qd5VLjTTvHEgwXnlDXMfo+vSgxosUxDOZXMTBqJGOViv5K2QBv" | |
"k8A1wi4k8tuo/7OWya29HvcfavUk3YXaV2YFe8V6ssaZjNcVWmDdjqNkXwIDAQAB" | |
"AoGALrd+ijNAOcebglT3ioE1XpUbUpbir7TPyAqvAZUUESF7er41jY9tnwgmBRgL" | |
"Cs+M1dgLERCdKBkjozrDDzswifFQmq6PrmYrBkFFqCoLJwepSYdWnK1gbZ/d43rR" | |
"2sXzSGZngscx0CxO7KZ7xUkwENGd3+lKXV7J6/vgzJ4XnkECQQDTP6zWKT7YDckk" | |
"We04hbhHyBuNOW068NgUUvoZdBewerR74MJx6nz28Tp+DeNvc0EveiQxsEnbV8u+" | |
"NRkX5y0xAkEAwcnEAGBn5kJd6SpU0ALA9XEpUv7tHTAGQYgCRbfTT59hhOq6I22A" | |
"ivjOCNG9c6E7EB2kcPVGuCpYUhy7XBIGjwJAK5lavKCqncDKoLwGn8HJdNcyCIWv" | |
"q5iFoDw37gTt1ricg2yx9PzmabkDz3xiUmBBNeFJkw/FToXiQRGIakyGIQJAJIem" | |
"PPPvYgZssYFbT4LVYO8d/Rk1FWVyKHQ9CWtnmADRXz7oK7l+m7PfEuaGsf9YpOcR" | |
"koGJ/TluQLxNzUNQnQJBAImwr/yYFenIx3HQ6UX/fCt6qpGDv0VfOLyR64MNeegx" | |
"o7DhNxHbFkIGzk4lKhMKcHKDrawZbdJtS9ie2geSwVQ=" | |
"-----END RSA PRIVATE KEY-----"; | |
const char* szPemPubKey = | |
"-----BEGIN RSA PUBLIC KEY-----" | |
"MIGJAoGBAJ/pgAk5IFg+97WOlgPOr7D77xhWgBMj9gKL9EplpCT6XZl+hRCDSqti" | |
"t+TN6g5r+p3lUuNNO8cSDBeeUNcx+j69KDGixTEM5lcxMGokY5WK/krZAG+TwDXC" | |
"LiTy26j/s5bJrb0e9x9q9STdhdpXZgV7xXqyxpmM1xVaYN2Oo2RfAgMBAAE=" | |
"-----END RSA PUBLIC KEY-----"; | |
const char* szDataToSign = "Data to be signed by the private key"; | |
int main(int argc, char* argv[]) | |
{ | |
DWORD dwBufferLen = 0, cbKeyBlob = 0, cbSignature = 0,i; | |
LPBYTE pbBuffer = NULL, pbKeyBlob = NULL, pbSignature = NULL; | |
HCRYPTPROV hProv = NULL; | |
HCRYPTKEY hKey = NULL; | |
HCRYPTHASH hHash = NULL; | |
if (!CryptStringToBinaryA(szPemPrivKey, 0, CRYPT_STRING_BASE64HEADER, NULL, &dwBufferLen, NULL, NULL)) | |
{ | |
printf("Failed to convert BASE64 private key. Error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
pbBuffer = (LPBYTE) LocalAlloc(0, dwBufferLen); | |
if (!CryptStringToBinaryA(szPemPrivKey, 0, CRYPT_STRING_BASE64HEADER, pbBuffer, &dwBufferLen, NULL, NULL)) | |
{ | |
printf("Failed to convert BASE64 private key. Error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pbBuffer, dwBufferLen, 0, NULL, NULL, &cbKeyBlob)) | |
{ | |
printf("Failed to parse private key. Error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
pbKeyBlob = (LPBYTE) LocalAlloc(0, cbKeyBlob); | |
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pbBuffer, dwBufferLen, 0, NULL, pbKeyBlob, &cbKeyBlob)) | |
{ | |
printf("Failed to parse private key. Error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
// Create a temporary and volatile CSP context in order to import | |
// the key and use for signing | |
if (!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) | |
{ | |
printf("CryptAcquireContext failed with error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
if (!CryptImportKey(hProv, pbKeyBlob, cbKeyBlob, NULL, 0, &hKey)) | |
{ | |
printf("CryptImportKey for private key failed with error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
// Hash the data | |
if (!CryptCreateHash(hProv, CALG_SHA1, NULL, 0, &hHash)) | |
{ | |
printf("CryptCreateHash failed with error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
if (!CryptHashData(hHash, (LPCBYTE) szDataToSign, strlen(szDataToSign), 0)) | |
{ | |
printf("CryptHashData failed with error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
// Sign the hash using our imported key | |
if (!CryptSignHash(hHash, AT_KEYEXCHANGE, NULL, 0, NULL, &cbSignature)) | |
{ | |
printf("CryptSignHash failed with error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
pbSignature = (LPBYTE) LocalAlloc(0, cbSignature); | |
if (!CryptSignHash(hHash, AT_KEYEXCHANGE, NULL, 0, pbSignature, &cbSignature)) | |
{ | |
printf("CryptSignHash failed with error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
printf("Signature = "); | |
for (i = 0; i < cbSignature; i++) | |
{ | |
printf("%.2X", pbSignature[i]); | |
} | |
printf("\n\n"); | |
/*************************************************** | |
* Import the public key and verify the signature | |
***************************************************/ | |
if (!CryptStringToBinaryA(szPemPubKey, 0, CRYPT_STRING_BASE64HEADER, NULL, &dwBufferLen, NULL, NULL)) | |
{ | |
printf("Failed to convert BASE64 public key. Error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
LocalFree(pbBuffer); | |
pbBuffer = (LPBYTE) LocalAlloc(0, dwBufferLen); | |
if (!CryptStringToBinaryA(szPemPubKey, 0, CRYPT_STRING_BASE64HEADER, pbBuffer, &dwBufferLen, NULL, NULL)) | |
{ | |
printf("Failed to convert BASE64 public key. Error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pbBuffer, dwBufferLen, 0, NULL, NULL, &cbKeyBlob)) | |
{ | |
printf("Failed to parse public key. Error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
LocalFree(pbKeyBlob); | |
pbKeyBlob = (LPBYTE) LocalAlloc(0, cbKeyBlob); | |
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pbBuffer, dwBufferLen, 0, NULL, pbKeyBlob, &cbKeyBlob)) | |
{ | |
printf("Failed to parse public key. Error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
CryptDestroyHash(hHash); | |
CryptDestroyKey(hKey); | |
CryptReleaseContext(hProv, 0); | |
if (!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) | |
{ | |
printf("CryptAcquireContext failed with error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
if (!CryptImportKey(hProv, pbKeyBlob, cbKeyBlob, NULL, 0, &hKey)) | |
{ | |
printf("CryptImportKey for public key failed with error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
// Hash the data | |
if (!CryptCreateHash(hProv, CALG_SHA1, NULL, 0, &hHash)) | |
{ | |
printf("CryptCreateHash failed with error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
if (!CryptHashData(hHash, (LPCBYTE) szDataToSign, strlen(szDataToSign), 0)) | |
{ | |
printf("CryptHashData failed with error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
// Sign the hash using our imported key | |
if (!CryptVerifySignature(hHash, pbSignature, cbSignature, hKey, NULL, 0)) | |
{ | |
printf("Signature verification failed with error 0x%.8X\n", GetLastError()); | |
goto main_exit; | |
} | |
printf("Signature verified successfully!\n\n"); | |
main_exit: | |
if (pbBuffer) LocalFree(pbBuffer); | |
if (pbKeyBlob) LocalFree(pbKeyBlob); | |
if (pbSignature) LocalFree(pbSignature); | |
if (hHash) CryptDestroyHash(hHash); | |
if (hKey) CryptDestroyKey(hKey); | |
if (hProv) CryptReleaseContext(hProv, 0); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment