Interaction between CryptoAPI and OpenSSL RSA asymmetric encryption and decryption (PKCS1 padding)

Source: Internet
Author: User
Tags begin rsa private key cdata openssl rsa asymmetric encryption

(The following code is only used for testing. In some cases, the memory is not released. solve this problem by yourself)

1. RSA is asymmetric. First, a certificate and private key for testing are provided.

1) base64 encoding of certificates and private keys in PEM format (private and private keys are corresponding)

void readPriKey(string &a){a =  "-----BEGIN RSA PRIVATE KEY-----\n";a.append("MIICXQIBAAKBgQDTFPiHkUX279j7OnK2ToLrwD/QI9N/fL/XoMnW1sBYJdSWs/VP\n");a.append("5oywvy6yJ0KMpfYcbRCJh2oRbPw7T9IrSHKdOkhB9PF6qwn90xb3Bk22l1LYZNfw\n");a.append("IQKqRjAXctR8GSC5ULBQmZK2T6m50oD5vl6rD6lnmrQyQSZ3tNNRYbxx/QIDAQAB\n");a.append("AoGAVqzSzOAzaY3dfHPorMGacvHzgiVj8IKqSAHHP8fZHZkTLXrh7ZhPBzjKFO+Y\n");a.append("HSb843lJhB+tx1AIVtaVB57tKLHJSrAjFem6mHV+X+JhMeX358QS0QFbUiKfAK5e\n");a.append("AkM1UdihF/3BX47DZUe44ntRqhffwsNGuZs2tB5FPHIpnGUCQQDvuBumamo+4tff\n");a.append("oF9Z/iuMJTyDerPgrQbC85ZoHBULLKtnzSUt7pdSsPMMBfImDpquhkLntC+kFV5b\n");a.append("yXu2nC5bAkEA4Wr1na+izFxmOnppvOjs7eFnch2THvNsajJ+Yl/jnRGGS5CLccrd\n");a.append("JgUm+j91VUitl88XY/GXAUDIobGw/iAAhwJBANZziODekD/D5cVcDhFPDZwpb7Jb\n");a.append("ofHcOJFNIv/uJ3FAu/J3lsw5hsxmGnhmFVOwevaoi9AG5RvQNgK9A9zAacMCQQDT\n");a.append("PI4qVHp0k2nhBvGra4MLcBymXXyOloJUCjlRKpZ7i/6TNULXQcl3ZYCfJXRolRDH\n");a.append("n/NFXxGoxPK+Q2ue2JJlAkBw1Z/1q2f6JYJ8pLBvdBSmOmKvm+O7x5s0csN7DnXf\n");a.append("aK1D4/cyCbLdqgogbolQkOwIwUuXLkitW1ldh+MinTMz\n");a.append("-----END RSA PRIVATE KEY-----\n");}void readCert(string &a){a = "-----BEGIN CERTIFICATE-----\n";a.append("MIIGVTCCBT2gAwIBAgIKGCyzsAAAAAAAbjANBgkqhkiG9w0BAQUFADA9MRUwEwYK\n");a.append("CZImiZPyLGQBGRYFbG9jYWwxEzARBgoJkiaJk/IsZAEZFgNpc3MxDzANBgNVBAMT\n");a.append("BldIVUlTUzAeFw0xMjA0MTEwMTMxNThaFw0xMzA0MTEwMTMxNThaMHIxFTATBgoJ\n");a.append("kiaJk/IsZAEZFgVsb2NhbDETMBEGCgmSJomT8ixkARkWA2lzczEOMAwGA1UEAxMF\n");a.append("VXNlcnMxEjAQBgNVBAMMCeWRqOe7jeemuTEgMB4GCSqGSIb3DQEJARYRemhvdXl1\n");a.append("emh5QDEyNi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANMU+IeRRfbv\n");a.append("2Ps6crZOguvAP9Aj0398v9egydbWwFgl1Jaz9U/mjLC/LrInQoyl9hxtEImHahFs\n");a.append("/DtP0itIcp06SEH08XqrCf3TFvcGTbaXUthk1/AhAqpGMBdy1HwZILlQsFCZkrZP\n");a.append("qbnSgPm+XqsPqWeatDJBJne001FhvHH9AgMBAAGjggOkMIIDoDAdBgNVHQ4EFgQU\n");a.append("vjfBpRVvsUsaWnX4dC81QzXu5T4wHwYDVR0jBBgwFoAU++PzmmgpwxErxTVrbJp5\n");a.append("IzqO3RswggECBgNVHR8EgfowgfcwgfSggfGgge6GgbNsZGFwOi8vL0NOPVdIVUlT\n");a.append("UyxDTj16c3ktMDIxMWMxNWEyNTIsQ049Q0RQLENOPVB1YmxpYyUyMEtleSUyMFNl\n");a.append("cnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9aXNzLERDPWxv\n");a.append("Y2FsP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3Q/YmFzZT9vYmplY3RDbGFzcz1j\n");a.append("UkxEaXN0cmlidXRpb25Qb2ludIY2aHR0cDovL3pzeS0wMjExYzE1YTI1Mi5pc3Mu\n");a.append("bG9jYWwvQ2VydEVucm9sbC9XSFVJU1MuY3JsMIIBFgYIKwYBBQUHAQEEggEIMIIB\n");a.append("BDCBowYIKwYBBQUHMAKGgZZsZGFwOi8vL0NOPVdIVUlTUyxDTj1BSUEsQ049UHVi\n");a.append("bGljJTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlv\n");a.append("bixEQz1pc3MsREM9bG9jYWw/Y0FDZXJ0aWZpY2F0ZT9iYXNlP29iamVjdENsYXNz\n");a.append("PWNlcnRpZmljYXRpb25BdXRob3JpdHkwXAYIKwYBBQUHMAKGUGh0dHA6Ly96c3kt\n");a.append("MDIxMWMxNWEyNTIuaXNzLmxvY2FsL0NlcnRFbnJvbGwvenN5LTAyMTFjMTVhMjUy\n");a.append("Lmlzcy5sb2NhbF9XSFVJU1MuY3J0MAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgWg\n");a.append("MD4GCSsGAQQBgjcVBwQxMC8GJysGAQQBgjcVCIbd/wqC4JYWgbmLGoKIvT+HxNMh\n");a.append("gXGE+cJBg4yVdgIBZAIBBjApBgNVHSUEIjAgBggrBgEFBQcDAgYIKwYBBQUHAwQG\n");a.append("CisGAQQBgjcKAwQwNQYJKwYBBAGCNxUKBCgwJjAKBggrBgEFBQcDAjAKBggrBgEF\n");a.append("BQcDBDAMBgorBgEEAYI3CgMEMDsGA1UdEQQ0MDKgHQYKKwYBBAGCNxQCA6APDA16\n");a.append("c3lAaXNzLmxvY2FsgRF6aG91eXV6aHlAMTI2LmNvbTBEBgkqhkiG9w0BCQ8ENzA1\n");a.append("MA4GCCqGSIb3DQMCAgIAgDAOBggqhkiG9w0DBAICAIAwBwYFKw4DAgcwCgYIKoZI\n");a.append("hvcNAwcwDQYJKoZIhvcNAQEFBQADggEBABj0xXhayI5JdqbuyAbqNwzGZxt4X102\n");a.append("CFFeTU5jauspQjqEpar+/IQ+r3/vf162bY/lLHLpDarFLbZ9dAC6nqNfnE4gg9r7\n");a.append("p+dbkbzFyBuSTqrzHQ6JgRYSdjwaksHV+uZuP7dfP2HXw4F1T3Ch/7ZKW9+ZlVvd\n");a.append("QCygAu0z+TS2e7oRFb+swQLVKda8kPTM/b69+r/xdTHXY6+CkfVAk4oYBB56a9AD\n");a.append("t1XOoAUa42fJdit6+7ssLLTZkZLNsQl6qsuTdv64dIMda4C6NnUsKDfjWGa+0vs3\n");a.append("VjVNsUC5jo4qRc4XmBvJIx6e5M420sPj2Gi/+ssgmaXK+zUWzowIoMU=\n");a.append("-----END CERTIFICATE-----\n");}

2) the CryptoAPI is consistent with the OpenSSL public/private key. If you remove the PEM header and tail, you can directly use it without encryption.

Certificate:

void readCertBase64(string &a){a = "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\n";}


This is because the attempt to import the private key has not been successful, and it does not matter for the time being. The replacement scheme for verifying the successful interaction will be discussed later.


2. Let's take a look at the RSA implementation scheme of OpenSSL. OpenSSL provides many padding methods,

Because CryptoAPI only provides PKCS1 and OAEP filling methods. PKCS1 is used by default, so PKCS1 is used for verification.

1) first, you need to import the certificate and private key for subsequent encryption and decryption. Here, the base64 code is used directly for import.

Evp_pkey * importkey () {openssl_add_all_algorithms (); evp_pkey * prikey; string a = ""; readprikey (a); // obtain the base64 code const char * sprikey =. c_str (); Bio * bio = bio_new_mem_buf (void *) sprikey, strlen (sprikey); // put the memory prikey = pem_read_bio_privatekey (Bio, null, null, null); // read bio, get the private key object byte * sign_value = (byte *) malloc (1024); unsigned int Len; return prikey;} evp_pkey * importcert () {X509 * Cert; openssl_add_all_algorithms (); string a = ""; readcert (a); // base64 const char * scert =. c_str (); Bio * bio = bio_new_mem_buf (void *) scert, strlen (scert); // save to memory Cert = pem_read_bio_x509 (Bio, null ); // read bio and obtain the certificate object evp_pkey * evp_pubkey = x509_get_pubkey (CERT); // obtain the certificate's public key int Len; If (evp_pubkey) {return evp_pubkey ;} elsecout <"evp_pubkey = NULL" <Endl; return NULL ;}

2) with the public key and private key object, asymmetric encryption and decryption will be simpler.

Here we have to mention the completion method, because it is consistent with the completion method of CryptoAPI, and it takes a lot of time

The default Filling Method of CryptoAPI is PKCS1. I thought it was no_padding. It turns out that CryptoAPI does not seem to support no_padding.

OpenSSL supports no_padding. If you use this method, you 'd better add all the remaining bits to the regular data so that you can easily obtain the desired plaintext after decryption.

No_padding must have the same plaintext and key size. The 1024-bit RSA corresponds to the 128-byte plaintext.

PKCS1 minus 11 bytes to store PKCS1's own data. The 1024-bit RSA can only encrypt 117 bytes of plaintext.

OAEP must subtract 41 bytes and only 87 bytes of plaintext can be encrypted.

If the size is exceeded, You can subscribe it by yourself. We will not discuss it here.


Void evelop (evp_pkey * evp_pubkey/* Public Key object */, byte ** out/* encryption result */, unsigned Int & cout/* encryption result size */, const byte * In/* plaintext */, unsigned int CIN/* plaintext size */) {openssl_add_all_algorithms (); bool haserr = true; evp_pkey_ctx * CTX = evp_pkey_ctx_new (evp_pubkey, null); If (! CTX) goto err; If (evp_pkey_encrypt_init (CTX) <= 0) goto err; If (completion (CTX, rsa_pkcs1_padding) <= 0) // you can specify the completion mode goto err; if (evp_pkey_encrypt (CTX, null, & cout, In, CIN) <= 0) // The encrypted length is generally the same as the key length, the 1024-bit RSA key is the 128-byte goto err; * out = (byte *) openssl_malloc (cout); If (! Out) goto err; If (evp_pkey_encrypt (CTX, * Out, & cout, In, CIN) <= 0) // get the encryption result goto err; cout <"encrypted successfully! "<Endl; haserr = false; err: evp_pkey_ctx_free (CTX); If (! Haserr) return;} void develop (evp_pkey * prikey, byte ** out, unsigned Int & cout, byte * data, unsigned int CDATA) {openssl_add_all_algorithms (); bool haserr = true; evp_pkey_ctx * CTX = evp_pkey_ctx_new (prikey, null); If (! CTX) goto err; If (evp_pkey_decrypt_init (CTX) <= 0) goto err; If (evp_pkey_ctx_set_rsa_padding (CTX, rsa_pkcs1_padding) <= 0) // complete goto err with the same PKCS1 as encrypted; If (evp_pkey_decrypt (CTX, null, & cout, Data, CDATA) <= 0) // decrypt the result size goto err; * Out = (byte *) openssl_malloc (cout); // allocate the memory if (! Out) goto err; If (evp_pkey_decrypt (CTX, * Out, & cout, Data, CDATA) <= 0) // obtain the decryption result goto err; haserr = false; err: // output some error information, and occasionally the error information is not available. Only get some file names and lines, and then go to the source code to find... if you have a good solution, please reply ~ Evp_pkey_ctx_free (CTX); If (! Haserr) return; cout <"err in develop" <Endl; const char * file, * data1, * efunc, * elib, * ereason, * P; int line, flags; unsigned long errn; errn = err_peek_error_line_data (& file, & line, & data1, & flags); printf ("err_peek_error_line_data err: % lD, file: % s, line: % d, data: % s \ n ", errn, file, line, data1 );}

3) Test the above Code by yourself. It should be okay.

2. RSA asymmetric encryption of CryptoAPI

1) First, it is still a public/private key data issue.

Let's take a look at importing certificates through base64 first. The private key issue is discussed in the third part.

Pccert_context importcryptocert (string base64cert) {pccert_context pcertcontext = NULL; int Len; byte * certencoded = base64: base64_decode (base64cert, Len); // base64 decoding, many methods, the code in the previous blog post is if (pcertcontext = certcreatecertificatecontext (x509_asn_encoding | pkcs_7_asn_encoding, certencoded, Len )) // import the certificate context object {printf ("a new certificate has been created. \ n ");} else {printf (" a new certificate cocould not be created. \ n ") ;}return pcertcontext ;}

2) public key encryption: the encryption of the public key of CryptoAPI is also encapsulated. If you don't notice it, you have to wait for a long time.

I use cryptencrypt, And the encrypted result isLittle-Endian 
Array of bytes. OpenSSL is the opposite.

For the description of CryptoAPI, the last sentence of remark is very small ....

Void encryptbypubkey (hcryptprov hprov, pccert_context cert, byte * Text, unsigned long & Len) {hcryptkey hkey; inclupubkeyinfo = cert-> pcertinfo-> subjectpublickeyinfo; // get the public key information if (! Cryptimppubpublickeyinfoex (hprov, publish, & pubkeyinfo, calg_rsa_keyx, 0, null, & hkey) // import to obtain the public key object {printf ("cryptimppubpublickeyinfoex error: 0x % x. \ n ", getlasterror (); return;} If (! Cryptencrypt (hkey, null, true, 0, text, & Len, 128) // encryption. the padding parameter is 0, which is PKCS1 by default, the last parameter is 128. For a 1024-bit RSA key, 128 bytes must be allocated for plaintext text {printf ("cryptencrypt error: 0x % x. \ n ", getlasterror (); Return ;}// the ciphertext is in reverse order below. If you reverse the order in OpenSSL, you will not need to use it here, anyway, the arrangement of CryptoAPI and OpenSSL is reverse for (INT I = 0; I <Len/2; I ++) {byte temp = text [I]; text [I] = text [Len-I-1]; text [Len-I-1] = temp;} printbyte (text, Len );}

3) Try to encrypt this part. It will be okay if it can be decrypted by OpenSSL.

3. The above only tried to encrypt OpenSSL Encryption Through CryptoAPI, because the private key is not successfully imported, and there is no time to try again. Now I will try another alternative solution.

If CryptoAPI decrypts the encryption of CryptoAPI, This is equivalent. You can directly obtain the public/private key from the Windows keystore and use CryptoAPI for encryption and decryption.

This article does not discuss how to obtain the certificate from the Windows library. Check the Private Key decryption section.

Void decryptbyprikey (pccert_context cert, byte * enctext, unsigned long Len) {// reverse the result once for CryptoAPI self-decryption for (INT I = 0; I <Len/2; I ++) {byte temp = enctext [I]; enctext [I] = enctext [Len-I-1]; enctext [Len-I-1] = temp ;} hcryptprov_or_ncrypt_key_handle hkeyprov; DWORD * dwkeytype; bool bfreekeyprov = false; If (! Cryptacquirecertificateprivatekey (CERT, 0, 0, & hkeyprov, dwkeytype, & bfreekeyprov) // obtain the private key handle {printf ("Certificate error: 0x % x. \ n ", getlasterror (); return;} hcryptkey hkey; If (! Cryptgetuserkey (hkeyprov, at_keyexchange, & hkey) // obtain the private key object {printf ("cryptgetuserkey error: 0x % x. \ n ", getlasterror (); return;} If (! Cryptdecrypt (hkey, null, true, 0, enctext, & Len) {// decryption, you can also change the padding parameter to crypt_decrypt_rsa_no_padding_checkprintf ("cryptdecrypt error: 0x % x. \ n ", getlasterror (); return;} printbyte (enctext, Len );}


If there is no problem at this point, the entire interaction will be completed.

The previous article mentioned AES and discussed it again next time with a different signature.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.