歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> CryptoAPI與OpenSSL RSA非對稱加密解密(PKCS1 PADDING)交互

CryptoAPI與OpenSSL RSA非對稱加密解密(PKCS1 PADDING)交互

日期:2017/3/1 10:12:03   编辑:Linux編程

(以下代碼中都只做測試用,有些地方沒有釋放內存...這個自己解決下)

1.RSA非對稱的,首先提供一個供測試用的證書和私鑰的數據

1)pem格式的證書和私鑰(公私鑰是對應的)的base64編碼

  1. void readPriKey(string &a){
  2. a = "-----BEGIN RSA PRIVATE KEY-----\n";
  3. a.append("MIICXQIBAAKBgQDTFPiHkUX279j7OnK2ToLrwD/QI9N/fL/XoMnW1sBYJdSWs/VP\n");
  4. a.append("5oywvy6yJ0KMpfYcbRCJh2oRbPw7T9IrSHKdOkhB9PF6qwn90xb3Bk22l1LYZNfw\n");
  5. a.append("IQKqRjAXctR8GSC5ULBQmZK2T6m50oD5vl6rD6lnmrQyQSZ3tNNRYbxx/QIDAQAB\n");
  6. a.append("AoGAVqzSzOAzaY3dfHPorMGacvHzgiVj8IKqSAHHP8fZHZkTLXrh7ZhPBzjKFO+Y\n");
  7. a.append("HSb843lJhB+tx1AIVtaVB57tKLHJSrAjFem6mHV+X+JhMeX358QS0QFbUiKfAK5e\n");
  8. a.append("AkM1UdihF/3BX47DZUe44ntRqhffwsNGuZs2tB5FPHIpnGUCQQDvuBumamo+4tff\n");
  9. a.append("oF9Z/iuMJTyDerPgrQbC85ZoHBULLKtnzSUt7pdSsPMMBfImDpquhkLntC+kFV5b\n");
  10. a.append("yXu2nC5bAkEA4Wr1na+izFxmOnppvOjs7eFnch2THvNsajJ+Yl/jnRGGS5CLccrd\n");
  11. a.append("JgUm+j91VUitl88XY/GXAUDIobGw/iAAhwJBANZziODekD/D5cVcDhFPDZwpb7Jb\n");
  12. a.append("ofHcOJFNIv/uJ3FAu/J3lsw5hsxmGnhmFVOwevaoi9AG5RvQNgK9A9zAacMCQQDT\n");
  13. a.append("PI4qVHp0k2nhBvGra4MLcBymXXyOloJUCjlRKpZ7i/6TNULXQcl3ZYCfJXRolRDH\n");
  14. a.append("n/NFXxGoxPK+Q2ue2JJlAkBw1Z/1q2f6JYJ8pLBvdBSmOmKvm+O7x5s0csN7DnXf\n");
  15. a.append("aK1D4/cyCbLdqgogbolQkOwIwUuXLkitW1ldh+MinTMz\n");
  16. a.append("-----END RSA PRIVATE KEY-----\n");
  17. }
  18. void readCert(string &a){
  19. a = "-----BEGIN CERTIFICATE-----\n";
  20. a.append("MIIGVTCCBT2gAwIBAgIKGCyzsAAAAAAAbjANBgkqhkiG9w0BAQUFADA9MRUwEwYK\n");
  21. a.append("CZImiZPyLGQBGRYFbG9jYWwxEzARBgoJkiaJk/IsZAEZFgNpc3MxDzANBgNVBAMT\n");
  22. a.append("BldIVUlTUzAeFw0xMjA0MTEwMTMxNThaFw0xMzA0MTEwMTMxNThaMHIxFTATBgoJ\n");
  23. a.append("kiaJk/IsZAEZFgVsb2NhbDETMBEGCgmSJomT8ixkARkWA2lzczEOMAwGA1UEAxMF\n");
  24. a.append("VXNlcnMxEjAQBgNVBAMMCeWRqOe7jeemuTEgMB4GCSqGSIb3DQEJARYRemhvdXl1\n");
  25. a.append("emh5QDEyNi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANMU+IeRRfbv\n");
  26. a.append("2Ps6crZOguvAP9Aj0398v9egydbWwFgl1Jaz9U/mjLC/LrInQoyl9hxtEImHahFs\n");
  27. a.append("/DtP0itIcp06SEH08XqrCf3TFvcGTbaXUthk1/AhAqpGMBdy1HwZILlQsFCZkrZP\n");
  28. a.append("qbnSgPm+XqsPqWeatDJBJne001FhvHH9AgMBAAGjggOkMIIDoDAdBgNVHQ4EFgQU\n");
  29. a.append("vjfBpRVvsUsaWnX4dC81QzXu5T4wHwYDVR0jBBgwFoAU++PzmmgpwxErxTVrbJp5\n");
  30. a.append("IzqO3RswggECBgNVHR8EgfowgfcwgfSggfGgge6GgbNsZGFwOi8vL0NOPVdIVUlT\n");
  31. a.append("UyxDTj16c3ktMDIxMWMxNWEyNTIsQ049Q0RQLENOPVB1YmxpYyUyMEtleSUyMFNl\n");
  32. a.append("cnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9aXNzLERDPWxv\n");
  33. a.append("Y2FsP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3Q/YmFzZT9vYmplY3RDbGFzcz1j\n");
  34. a.append("UkxEaXN0cmlidXRpb25Qb2ludIY2aHR0cDovL3pzeS0wMjExYzE1YTI1Mi5pc3Mu\n");
  35. a.append("bG9jYWwvQ2VydEVucm9sbC9XSFVJU1MuY3JsMIIBFgYIKwYBBQUHAQEEggEIMIIB\n");
  36. a.append("BDCBowYIKwYBBQUHMAKGgZZsZGFwOi8vL0NOPVdIVUlTUyxDTj1BSUEsQ049UHVi\n");
  37. a.append("bGljJTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlv\n");
  38. a.append("bixEQz1pc3MsREM9bG9jYWw/Y0FDZXJ0aWZpY2F0ZT9iYXNlP29iamVjdENsYXNz\n");
  39. a.append("PWNlcnRpZmljYXRpb25BdXRob3JpdHkwXAYIKwYBBQUHMAKGUGh0dHA6Ly96c3kt\n");
  40. a.append("MDIxMWMxNWEyNTIuaXNzLmxvY2FsL0NlcnRFbnJvbGwvenN5LTAyMTFjMTVhMjUy\n");
  41. a.append("Lmlzcy5sb2NhbF9XSFVJU1MuY3J0MAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgWg\n");
  42. a.append("MD4GCSsGAQQBgjcVBwQxMC8GJysGAQQBgjcVCIbd/wqC4JYWgbmLGoKIvT+HxNMh\n");
  43. a.append("gXGE+cJBg4yVdgIBZAIBBjApBgNVHSUEIjAgBggrBgEFBQcDAgYIKwYBBQUHAwQG\n");
  44. a.append("CisGAQQBgjcKAwQwNQYJKwYBBAGCNxUKBCgwJjAKBggrBgEFBQcDAjAKBggrBgEF\n");
  45. a.append("BQcDBDAMBgorBgEEAYI3CgMEMDsGA1UdEQQ0MDKgHQYKKwYBBAGCNxQCA6APDA16\n");
  46. a.append("c3lAaXNzLmxvY2FsgRF6aG91eXV6aHlAMTI2LmNvbTBEBgkqhkiG9w0BCQ8ENzA1\n");
  47. a.append("MA4GCCqGSIb3DQMCAgIAgDAOBggqhkiG9w0DBAICAIAwBwYFKw4DAgcwCgYIKoZI\n");
  48. a.append("hvcNAwcwDQYJKoZIhvcNAQEFBQADggEBABj0xXhayI5JdqbuyAbqNwzGZxt4X102\n");
  49. a.append("CFFeTU5jauspQjqEpar+/IQ+r3/vf162bY/lLHLpDarFLbZ9dAC6nqNfnE4gg9r7\n");
  50. a.append("p+dbkbzFyBuSTqrzHQ6JgRYSdjwaksHV+uZuP7dfP2HXw4F1T3Ch/7ZKW9+ZlVvd\n");
  51. a.append("QCygAu0z+TS2e7oRFb+swQLVKda8kPTM/b69+r/xdTHXY6+CkfVAk4oYBB56a9AD\n");
  52. a.append("t1XOoAUa42fJdit6+7ssLLTZkZLNsQl6qsuTdv64dIMda4C6NnUsKDfjWGa+0vs3\n");
  53. a.append("VjVNsUC5jo4qRc4XmBvJIx6e5M420sPj2Gi/+ssgmaXK+zUWzowIoMU=\n");
  54. a.append("-----END CERTIFICATE-----\n");
  55. }
2)CryptoAPI和openssl公私鑰保持一致,去掉pem頭尾直接用便是,沒有加密

證書的:

  1. void readCertBase64(string &a){
  2. a = "MIIGVTCCBT2gAwIBAgIKGCyzsAAAAAAAbjANBgkqhkiG9w0BAQUFADA9MRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxEzARBgoJkiaJk/IsZAEZFgNpc3MxDzANBgNVBAMTBldIVUlTUzAeFw0xMjA0MTEwMTMxNThaFw0xMzA0MTEwMTMxNThaMHIxFTATBgoJkiaJk/IsZAEZFgVsb2NhbDETMBEGCgmSJomT8ixkARkWA2lzczEOMAwGA1UEAxMFVXNlcnMxEjAQBgNVBAMMCeWRqOe7jeemuTEgMB4GCSqGSIb3DQEJARYRemhvdXl1emh5QDEyNi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANMU+IeRRfbv2Ps6crZOguvAP9Aj0398v9egydbWwFgl1Jaz9U/mjLC/LrInQoyl9hxtEImHahFs/DtP0itIcp06SEH08XqrCf3TFvcGTbaXUthk1/AhAqpGMBdy1HwZILlQsFCZkrZPqbnSgPm+XqsPqWeatDJBJne001FhvHH9AgMBAAGjggOkMIIDoDAdBgNVHQ4EFgQUvjfBpRVvsUsaWnX4dC81QzXu5T4wHwYDVR0jBBgwFoAU++PzmmgpwxErxTVrbJp5IzqO3RswggECBgNVHR8EgfowgfcwgfSggfGgge6GgbNsZGFwOi8vL0NOPVdIVUlTUyxDTj16c3ktMDIxMWMxNWEyNTIsQ049Q0RQLENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9aXNzLERDPWxvY2FsP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3Q/YmFzZT9vYmplY3RDbGFzcz1jUkxEaXN0cmlidXRpb25Qb2ludIY2aHR0cDovL3pzeS0wMjExYzE1YTI1Mi5pc3MubG9jYWwvQ2VydEVucm9sbC9XSFVJU1MuY3JsMIIBFgYIKwYBBQUHAQEEggEIMIIBBDCBowYIKwYBBQUHMAKGgZZsZGFwOi8vL0NOPVdIVUlTUyxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1pc3MsREM9bG9jYWw/Y0FDZXJ0aWZpY2F0ZT9iYXNlP29iamVjdENsYXNzPWNlcnRpZmljYXRpb25BdXRob3JpdHkwXAYIKwYBBQUHMAKGUGh0dHA6Ly96c3ktMDIxMWMxNWEyNTIuaXNzLmxvY2FsL0NlcnRFbnJvbGwvenN5LTAyMTFjMTVhMjUyLmlzcy5sb2NhbF9XSFVJU1MuY3J0MAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgWgMD4GCSsGAQQBgjcVBwQxMC8GJysGAQQBgjcVCIbd/wqC4JYWgbmLGoKIvT+HxNMhgXGE+cJBg4yVdgIBZAIBBjApBgNVHSUEIjAgBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwQwNQYJKwYBBAGCNxUKBCgwJjAKBggrBgEFBQcDAjAKBggrBgEFBQcDBDAMBgorBgEEAYI3CgMEMDsGA1UdEQQ0MDKgHQYKKwYBBAGCNxQCA6APDA16c3lAaXNzLmxvY2FsgRF6aG91eXV6aHlAMTI2LmNvbTBEBgkqhkiG9w0BCQ8ENzA1MA4GCCqGSIb3DQMCAgIAgDAOBggqhkiG9w0DBAICAIAwBwYFKw4DAgcwCgYIKoZIhvcNAwcwDQYJKoZIhvcNAQEFBQADggEBABj0xXhayI5JdqbuyAbqNwzGZxt4X102CFFeTU5jauspQjqEpar+/IQ+r3/vf162bY/lLHLpDarFLbZ9dAC6nqNfnE4gg9r7p+dbkbzFyBuSTqrzHQ6JgRYSdjwaksHV+uZuP7dfP2HXw4F1T3Ch/7ZKW9+ZlVvdQCygAu0z+TS2e7oRFb+swQLVKda8kPTM/b69+r/xdTHXY6+CkfVAk4oYBB56a9ADt1XOoAUa42fJdit6+7ssLLTZkZLNsQl6qsuTdv64dIMda4C6NnUsKDfjWGa+0vs3VjVNsUC5jo4qRc4XmBvJIx6e5M420sPj2Gi/+ssgmaXK+zUWzowIoMU=\n";
  3. }
因為嘗試私鑰沒有導入成功,暫且不管,關於這一點待會再說驗證交互成功的替換方案

2.先來看下openssl的RSA實現方案,openssl本身提供了許多的padding方式,

因為CryptoAPI只提供了PKCS1和OAEP兩種補齊方式,默認使用的PKCS1,那這裡就用PKCS1來驗證吧

1)首先需要導入證書和私鑰,用於後續加密解密,這裡就直接采用通過Base64碼來導入

  1. EVP_PKEY * importKey(){
  2. OpenSSL_add_all_algorithms();
  3. EVP_PKEY *prikey;
  4. string a = "";
  5. readPriKey(a);//獲取私鑰的base64碼
  6. const char* sPriKey = a.c_str();
  7. BIO* bio = BIO_new_mem_buf((void*)sPriKey,strlen(sPriKey));//通過BIO放入內存
  8. prikey = PEM_read_bio_PrivateKey(bio,NULL,NULL,NULL);//讀取bio,獲取私鑰對象
  9. BYTE* sign_value = (BYTE*)malloc(1024);
  10. unsigned int len;
  11. return prikey;
  12. }
  13. EVP_PKEY * importCert(){
  14. X509* cert;
  15. OpenSSL_add_all_algorithms();
  16. string a = "";
  17. readCert(a);//證書的base64碼
  18. const char* sCert = a.c_str();
  19. BIO* bio = BIO_new_mem_buf((void*)sCert,strlen(sCert));//存到內存
  20. cert = PEM_read_bio_X509(bio,NULL,NULL,NULL);//讀取bio,獲取證書對象
  21. EVP_PKEY* evp_pubKey =X509_get_pubkey(cert);//獲取證書的公鑰
  22. int len;
  23. if(evp_pubKey){
  24. return evp_pubKey;
  25. }
  26. else
  27. cout << "evp_pubKey == NULL" << endl;
  28. return NULL;
  29. }
2)有了公鑰,私鑰對象,接下來做非對稱加密和解密就簡單些了

這裡得提下補齊方式,因為和CryptoAPI的補齊方式要保持一致,折騰了許多時間

CryptoAPI的默認補齊方式是PKCS1,我先以為就是NO_PADDING,結果發現CryptoAPI貌似就沒有對NO_PADDING的支持

openssl有NO_PADDING的支持,如果使用這個方式,最好自己將剩余位全部補上規律的數據,便於解密後容易獲取到要的明文

NO_PADDING就必須明文和密鑰大小一樣了,1024位RSA對應128字節明文

PKCS1的得減去11字節存儲PKCS1自己的數據,1024位RSA只能加密117字節明文

OAEP則得減去41字節,只能加密87字節明文

如果超過大小,當然可以自己去分節處理,這裡就不予討論了

  1. void evelop(EVP_PKEY* evp_pubKey/*公鑰對象*/,BYTE** out/*加密結果*/,unsigned int &cOut/*加密結果大小*/,const BYTE* in/*明文*/,unsigned int cIn/*明文大小*/){
  2. OpenSSL_add_all_algorithms();
  3. bool hasErr = true;
  4. EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(evp_pubKey,NULL);
  5. if(!ctx)
  6. goto err;
  7. if(EVP_PKEY_encrypt_init(ctx)<=0)
  8. goto err;
  9. if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)//設置補齊方式
  10. goto err;
  11. if(EVP_PKEY_encrypt(ctx,NULL,&cOut,in,cIn)<=0)//得到加密的長度,一般都是跟密鑰一樣長,1024位的RSA密鑰就是128字節
  12. goto err;
  13. *out =(BYTE*) OPENSSL_malloc(cOut);
  14. if(!out)
  15. goto err;
  16. if(EVP_PKEY_encrypt(ctx,*out,&cOut,in,cIn)<=0)//得到加密結果
  17. goto err;
  18. cout << "加密成功!" << endl;
  19. hasErr = false;
  20. err:
  21. EVP_PKEY_CTX_free(ctx);
  22. if(!hasErr)
  23. return;
  24. return;
  25. }
  26. void develop(EVP_PKEY* priKey,BYTE** out,unsigned int &cOut, BYTE* data,unsigned int cData){
  27. OpenSSL_add_all_algorithms();
  28. bool hasErr = true;
  29. EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(priKey,NULL);
  30. if(!ctx)
  31. goto err;
  32. if (EVP_PKEY_decrypt_init(ctx) <= 0)
  33. goto err;
  34. if(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)//與加密同樣的PKCS1補齊
  35. goto err;
  36. if (EVP_PKEY_decrypt(ctx, NULL, &cOut, data, cData) <= 0)//解密結果大小
  37. goto err;
  38. *out =(BYTE*) OPENSSL_malloc(cOut);//分配內存
  39. if (!out)
  40. goto err;
  41. if (EVP_PKEY_decrypt(ctx, *out, &cOut, data, cData) <= 0)//得到解密結果
  42. goto err;
  43. hasErr = false;
  44. err://輸出一些錯誤信息,偶爾錯誤信息得不到,只得到一些文件名和所在行,就跑到源代碼去找...麻煩死了,如果有好的方案求回復~
  45. EVP_PKEY_CTX_free(ctx);
  46. if(!hasErr)
  47. return;
  48. cout << "err in develop" << endl;
  49. const char*file,*data1,*efunc,*elib,*ereason,*p;
  50. int line,flags;
  51. unsigned long errn;
  52. errn=ERR_peek_error_line_data(&file,&line,&data1,&flags);
  53. printf("ERR_peek_error_line_data err : %ld,file :%s,line :%d,data :%s\n",errn,file,line,data1);
  54. }
3)自己測試下上面的代碼吧,應該是沒問題的
Copyright © Linux教程網 All Rights Reserved