生成證書見:使用 openssl 生成證書html
#ifndef _CERT_H #define _CERT_H ///header files #include <stdio.h> #include <string.h> #include <openssl\rsa.h> #include <openssl\pem.h> #include <openssl\evp.h> #include <openssl/engine.h> #include <openssl\x509.h> enum CryptMode{ ENCRYPT_MODE, DECRYPT_MODE }; enum KeyType { FILE_TYPE, STRING_TYPE }; int EncryptOrDecryptByPublicKey(char *inData, int inLen, char **outData, int *outLen, CryptMode mode, char *pubKey, KeyType type); int EncryptOrDecryptByPrivateKey(char *inData, int inLen, char **outData, int *outLen, CryptMode mode, char *priKey, KeyType type); int EncryptOrDecryptByX509(char *inData, int inLen, char **outData, int *outLen, int mode, char *x509CertPath); int X509Verify(char *rootCAPath, char *verifyCertPath); #endif ///_CERT_H
Cert.cpp測試
#include "Cert.h" #define MAX_LENGTH 4096 static void FreeX509EnvirSpace(X509_STORE *x509Store, X509_STORE_CTX *x509StoreCTX); ///***********************************************/ /// encrypt or decrypt by public key and mode /// params: /// inData : input data to encrypt or decrypt /// inLen : input data length /// outData: encrypted or decrypted data /// outLen : output data length /// mode : ENCRPYT or DECRYPT /// pubKey : public key file path or public key string distinguished by type /// type : /// 返回值 : /// iRet=0 ,加密成功 /// iRet=-1,加密失敗 ///***********************************************/ int EncryptOrDecryptByPublicKey(char *inData, int inLen, char **outData, int *outLen, CryptMode mode, char *pubKey,KeyType type) { int iRet = -1; if (inData == NULL || strlen(inData) <= 0 || inLen <= 0 || pubKey == NULL || strlen(pubKey) <= 0) { return iRet; } RSA *RSAPubKey = NULL; int RSAPubKeyLen = 0;//祕鑰長度 FILE *fp = NULL; BIO *bio = NULL; switch (type) { case FILE_TYPE: ///1.打開祕鑰文件 if ((fp = fopen(pubKey, "rb")) == NULL) { return iRet; } //2.從文件中獲取公鑰 if ((RSAPubKey = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { //公鑰獲取失敗 fclose(fp); return iRet; } fclose(fp); break; case STRING_TYPE: ///1.新建BIO對象 bio = BIO_new_mem_buf(pubKey, strlen(pubKey)); if (bio == NULL) { return iRet; } ///從BIO中獲取公鑰 if ((RSAPubKey = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL)) == NULL) { ERR_print_errors_fp(stdout); BIO_free(bio); return iRet; } BIO_free(bio); break; default: return iRet; } //3.獲取公鑰的長度 RSAPubKeyLen = RSA_size(RSAPubKey); //4.爲加密或解密後的數據分配空間 (*outData) = (char *)malloc(RSAPubKeyLen + 1); memset(*outData, 0, RSAPubKeyLen + 1); if (*outData == NULL) { //空間分配失敗 if (pubKey != NULL) { RSA_free(RSAPubKey); } return iRet; } //5.加解密數據 switch (mode) { case ENCRYPT_MODE: if (RSA_public_encrypt(RSAPubKeyLen, (unsigned char *)inData, (unsigned char *)*outData, RSAPubKey, RSA_NO_PADDING) < 0) { //加密失敗 if (pubKey != NULL) { RSA_free(RSAPubKey); } if (*outData != NULL) { free(*outData); } return iRet; } *outLen = strlen(*outData); iRet = 0; break; case DECRYPT_MODE: if (RSA_public_decrypt(RSAPubKeyLen, (unsigned char *)inData, (unsigned char *)*outData, RSAPubKey, RSA_NO_PADDING) < 0) { //解密失敗 if (pubKey != NULL) { RSA_free(RSAPubKey); } if (*outData != NULL) { free(*outData); } return iRet; } *outLen = strlen(*outData); iRet = 0; break; default: ///模式錯誤 return iRet; } //6.釋放空間 RSA_free(RSAPubKey); return iRet; } ///************************************************/ /// 使用私鑰進行加密 /// 輸入參數: /// inData :待加密的數據 /// inLen :待加密數據長度 /// outData:加密後的數據 /// outLen :加密後數據長度 /// 返回值: /// iRet=-1,加密失敗 /// iRet=0 ,加密成功 ///************************************************/ int EncryptOrDecryptByPrivateKey(char *inData, int inLen, char **outData, int *outLen, CryptMode mode, char *priKey,KeyType type) { int iRet = -1; if (inData == NULL || inLen <= 0 || strlen(inData) <= 0 || priKey == NULL || strlen(priKey) <= 0) { return iRet; } RSA *RSAPriKey = NULL; int RSAPriKeyLen = 0; FILE *fp = NULL; BIO *bio = NULL; switch (type) { case FILE_TYPE: ///1.打開私鑰文件 if ((fp = fopen(priKey, "rb")) == NULL) { ///文件打開失敗 return iRet; } ///2.從文件中獲取私鑰 if ((RSAPriKey = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL)) == NULL) { ///獲取私鑰失敗 fclose(fp); return iRet; } fclose(fp); break; case STRING_TYPE: bio = BIO_new_mem_buf(priKey, strlen(priKey)); if (bio == NULL) { return iRet; } if ((RSAPriKey = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL)) == NULL) { BIO_free(bio); return iRet; } BIO_free(bio); break; default: return iRet; } ///3.獲取私鑰長度 RSAPriKeyLen = RSA_size(RSAPriKey); ///4.爲加密或解密的內容申請空間 (*outData) = (char *)malloc(RSAPriKeyLen + 1); if (*outData == NULL) { if (priKey != NULL) { RSA_free(RSAPriKey); } return iRet; } memset(*outData, 0, RSAPriKeyLen + 1); ///5.用私鑰加解密數據 switch (mode) { case ENCRYPT_MODE: if (RSA_private_encrypt(RSAPriKeyLen, (unsigned char*)inData, (unsigned char *)*outData, RSAPriKey, RSA_NO_PADDING) < 0) { ///加密失敗 if (priKey != NULL) { RSA_free(RSAPriKey); } if (*outData != NULL) { free(*outData); } return iRet; } *outLen = strlen(*outData); iRet = 0; break; case DECRYPT_MODE: if (RSA_private_decrypt(RSAPriKeyLen, (unsigned char *)inData, (unsigned char *)*outData, RSAPriKey, RSA_NO_PADDING) < 0) { ///解密失敗 if (*outData != NULL) { free(*outData); } if (priKey != NULL) { RSA_free(RSAPriKey); } return iRet; } *outLen = strlen(*outData); iRet = 0; break; default: return iRet; } ///6.釋放空間 RSA_free(RSAPriKey); return iRet; } ///*********************************************/ ///從X509證書中獲取RSA,用獲取的公鑰進行加解密 /// 輸入參數: /// inData : 明文 /// inLen : 明文長度 /// outData: 加密或解密的數據地址 /// outLen : 加密或解密的數據長度 /// mode : 模式,0表示加密,1表示解密 /// x509CertPath : 509證書地址 /// 返回值: /// iRet=0,加解密成功 /// iRet=-1,加解密失敗 ///*********************************************/ int EncryptOrDecryptByX509(char *inData, int inLen, char **outData, int *outLen, int mode, char *x509CertPath) { int iRet = -1; if (inData == NULL || inLen <= 0 || strlen(inData) <= 0) { ///待加密或解密數據爲NULL return iRet; } ///從509證書中獲取公鑰 X509 *x509 = NULL; unsigned char *x509Buf = (unsigned char *)malloc(MAX_LENGTH); unsigned long x509BufLen = 0; if (x509Buf == NULL) { ///內存分配失敗 return iRet; } ///1.讀取公鑰文件 FILE *fp = NULL; if ((fp = fopen(x509CertPath, "rb")) == NULL) { ///文件打開失敗 free(x509Buf); return iRet; } x509BufLen = fread(x509Buf, 1, MAX_LENGTH, fp); fclose(fp); ///2.將二進制格式的字符串轉化爲X509類型 const unsigned char *constX509Buf = x509Buf; if ((x509 = d2i_X509(NULL, &constX509Buf, x509BufLen)) == NULL) { ///證書轉換失敗 free(x509Buf); return iRet; } free(x509Buf); ///3.將X509中的公鑰提取到EVP_PKEY中 EVP_PKEY *ePKey = NULL; if ((ePKey = X509_get_pubkey(x509)) == NULL) { ///獲取公鑰失敗 X509_free(x509); } X509_free(x509); ///4.從EVP_PKEY中獲取RSA公鑰 RSA *pubKey = NULL; if ((pubKey = EVP_PKEY_get1_RSA(ePKey)) == NULL) { ///獲取失敗 X509_free(x509); EVP_PKEY_free(ePKey); return iRet; } EVP_PKEY_free(ePKey); ///使用公鑰加密或解密 /// mode=0 加密 /// mode=1 解密 ///5.獲取公鑰長度 int pubKeyLen = 0; pubKeyLen = RSA_size(pubKey); ///6.爲加密或解密後的數據分配空間 (*outData) = (char *)malloc(pubKeyLen + 1); if (*outData == NULL) { ///空間分配失敗 RSA_free(pubKey); return iRet; } memset(*outData, 0, pubKeyLen + 1); ///7.進行加密或解密 switch (mode) { case 0: if (RSA_public_encrypt(pubKeyLen, (unsigned char *)inData, (unsigned char *)*outData, pubKey, RSA_NO_PADDING) <= 0) { ///加密失敗 free(*outData); RSA_free(pubKey); return iRet; } *outLen = strlen(*outData); iRet = 0; break; case 1: if (RSA_public_decrypt(pubKeyLen, (unsigned char *)inData, (unsigned char *)*outData, pubKey, RSA_NO_PADDING) <= 0) { ///解密失敗 free(*outData); RSA_free(pubKey); return iRet; } *outLen = strlen(*outData); iRet = 0; break; default: ///模式錯誤 return iRet; } ///8.釋放空間 RSA_free(pubKey); return iRet; } ///*********************************************/ /// X509二進制證書驗證 /// 輸入參數: /// rootCAPath : CA證書路徑 /// verifyCertPath : 待驗證證書路徑 /// 返回值: /// iRet=0,驗證成功 /// iRet=-1,驗證失敗 ///*********************************************/ int X509Verify(char *rootCAPath,char *verifyCertPath) { int iRet = -1; int verifyResult = 0; if (rootCAPath == NULL || strlen(rootCAPath) <= 0) { return iRet; } ///1.初始化X509 FILE *fp = NULL; X509_STORE *x509Store = NULL; X509_STORE_CTX *x509StoreCTX = NULL; x509Store = X509_STORE_new(); ///證書庫,保存證書鏈 x509StoreCTX = X509_STORE_CTX_new(); ///證書上下文 ///2.從der(二進制)格式文件中讀取CA證書到buffer中。文本格式(PEM)證書,使用PEM_read_X509方法讀取。 X509 *ca = NULL; unsigned char *caDer = (unsigned char *)malloc(MAX_LENGTH); unsigned long caLen = 0; if (caDer == NULL) { FreeX509EnvirSpace(x509Store, x509StoreCTX); return iRet; } if ((fp = fopen(rootCAPath, "rb")) == NULL) { FreeX509EnvirSpace(x509Store, x509StoreCTX); free(caDer); return iRet; } caLen = fread(caDer, 1, 4096, fp); fclose(fp); ///3.將二進制格式(der編碼)CA證書轉化爲X509數據類型 const unsigned char *constCADer = caDer; if ((ca = d2i_X509(NULL, &constCADer, caLen)) == NULL) { ///der格式證書轉換爲X509失敗 FreeX509EnvirSpace(x509Store, x509StoreCTX); free(caDer); return iRet; } ///4.加入證書存儲庫 if (X509_STORE_add_cert(x509Store, ca) != 1) { ///證書庫添加失敗 FreeX509EnvirSpace(x509Store, x509StoreCTX); X509_free(ca); free(caDer); return iRet; } ///5.讀取二進制格式(der)待驗證證書 X509 *verifyCert = NULL; unsigned char *vcDer = (unsigned char *)malloc(MAX_LENGTH); unsigned long vcLen = 0; if ((fp = fopen(rootCAPath, "rb")) == NULL) { FreeX509EnvirSpace(x509Store, x509StoreCTX); X509_free(ca); free(caDer); return iRet; } vcLen = fread(vcDer, 1, 4096, fp); fclose(fp); ///6.同步驟3 const unsigned char *constVcDer = vcDer; if ((verifyCert = d2i_X509(NULL, &constVcDer, vcLen)) == NULL) { ///證書轉換失敗 FreeX509EnvirSpace(x509Store, x509StoreCTX); X509_free(ca); free(caDer); free(vcDer); return iRet; } ///7.初始化證書上下文環境 if (X509_STORE_CTX_init(x509StoreCTX, x509Store, verifyCert, NULL) != 1) { FreeX509EnvirSpace(x509Store, x509StoreCTX); X509_free(ca); free(caDer); free(vcDer); return iRet; } ///8.進行驗證 verifyResult = X509_verify_cert(x509StoreCTX); if (verifyResult != 1) { ///驗證失敗 long nCode = X509_STORE_CTX_get_error(x509StoreCTX); const char *pError = X509_verify_cert_error_string(nCode); //printf("[%s:%d] ErrorCode:%ld ErrorStr:%s\n", __FUNCTION__, __LINE__, nCode, pError); return iRet; } iRet = (verifyResult == 1 ? 0 : -1); ///9.釋放多餘空間 free(caDer); free(vcDer); X509_free(ca); X509_free(verifyCert); X509_STORE_free(x509Store); X509_STORE_CTX_free(x509StoreCTX); return iRet; } static void FreeX509EnvirSpace(X509_STORE *x509Store, X509_STORE_CTX *x509StoreCTX) { if (x509Store != NULL) { free(x509Store); } if (x509StoreCTX != NULL) { free(x509StoreCTX); } }
CertTest.cppui
#include "CertTest.h" #define PUB_KEY_PATH "rsa_public.key" #define PRI_KEY_PATH "rsa_private.key" #define DER_CERT_PATH "rsa.der" #define CER_CERT_PATH "rsa.cer" #define CRT_CERT_PATH "rsa.crt" #define PEM_CERT_PATH "rsa.pem" int TestCert() { char *data = "Hello,world!"; int dataLen = strlen(data); char *enData = NULL; int enLen = 0; char *base64EnData = NULL; int base64EnLen = 0; char *deData = NULL; int deLen = 0; ///文件模式 ///公鑰加密私鑰解密 EncryptOrDecryptByPublicKey(data, dataLen, &enData, &enLen, ENCRYPT_MODE, PUB_KEY_PATH, FILE_TYPE); Base64Encode(enData, enLen, &base64EnData, &base64EnLen); printf("%s\n", base64EnData); EncryptOrDecryptByPrivateKey(enData, enLen, &deData, &deLen, DECRYPT_MODE, PRI_KEY_PATH, FILE_TYPE); printf("%s\n", deData); printf("%d\n", strcmp(data, deData)); ///私鑰加密公鑰解密 EncryptOrDecryptByPrivateKey(data, dataLen, &enData, &enLen, ENCRYPT_MODE, PRI_KEY_PATH, FILE_TYPE); Base64Encode(enData, enLen, &base64EnData, &base64EnLen); printf("%s\n", base64EnData); EncryptOrDecryptByPublicKey(enData, enLen, &deData, &deLen, DECRYPT_MODE, PUB_KEY_PATH, FILE_TYPE); printf("%s\n", deData); printf("%d\n", strcmp(data, deData)); ///字符串加密 char priKeyStr[] = "-----BEGIN RSA PRIVATE KEY-----\n" "MIIEpQIBAAKCAQEAtMs6bXNIWoR3PhrP1NvShmFK0xSEFnhi/vnzlRU5BmNSzjP7" "B2HBA5qByPIu1TLCP6trpPBZrasdZNxkfJgaxeucipvZPrDgsZhEZdqZU3pB9fnG" "9wopx3dLP1VBV+0QA2cnte4fLtL6T3z4+sw+QQRgI59VEqWGtBYxmcE7HDgzciOt" "s4xUxhXGG0MVFBoJguvpCk+MT5ZQX/GnTHCrnIcsdjcLxEAIVbMqKecNVBWpE7k8" "hS2mK7QPwDvJEuPZ2k0pem00hyMPW2klvZhiHghRqSmZisg42WIVFR+PWMojNDPs" "jQerJmHh95FayCGEbs6bwLoSUeJ/oI5UVzee2QIDAQABAoIBAH93YaRVSUf4aRHy" "WWGb8pwn8FdN+arWCgX3OFN9+QyV7oXPhEc6Fplxz9tbVMWf2fCF7YkGpFObd0fr" "UzW9D/NHIMFhDBP1JRZRYrflHYELi4HfLvZxxe8KHpVyiHVzgHzFt+u/DWE4Ap8U" "X36DjcjNSvMSnSpeZdCGbUYYRJKppNKm2YmhVkUtG5Am1D7xC8k6dzpK6szRmVM6" "fcYx1l8WFG/wunlyikC5CbH5cCrf/uJWtypb3vDVeB4CWV3T9FhRORPozxSWsbld" "3gmcwEOc/LHkkmr1sGbNfzlfpmLiK4mSpYNy0WKjIrq4CAevIz97tzj2SiESsMJo" "mR5TVGECgYEA6TUWoruFEvBuKDpDYKIZfRTCiaRXWC7p0LNvxC9E321qeRQYpK3Q" "2OqOHre/Ua9yWIiTxKJuw1ZUznlyUkTqFg6XTVDZGnHjV39+u5kXCV36AtDtv9yI" "DVzqGPSJc9TQ1ibFhBu+iev+jeRS0Zx7j1gq0hXjh0EKP6ExYUGTgh0CgYEAxna9" "TeTxPXobyKqAUVFRUtpXmWnKp8pleyMg5Cmu+BeYm+cmBiQAsGRmggFHn238ieVe" "WU7My97BWSAUQH8eBTF08N29+IXGmmq/5p3CGoeJbNi8ioh0E3AokYwWad1v7gky" "iEb0gxjJwHrEobR6j0vxue3Hqq7RvxlzbI7wsu0CgYEAq+Vg2PSl407rs6U2kt0J" "MqSBvJkxdKOn3xjUcmRxPMtW5waEH6arQaiqt0Oztw8+lrmdShx8zmktO8BTHwcD" "EN0Sc3/7dz2pWI52qOrwCwyFQ1wjUv/IHSl2uIxPYNzmTmPnxTf6G4mjaY156l2Q" "yhkv/wj5XHH5jutPDaQbiZUCgYEAsq7jX4dZ/6y56SBBaXVaT8tPhUtvb0RVu9jz" "2xkAdFPiTbN+U5cEm8u5UyFN1+fRsGG3YZcF4iPLVrAAK9WHNMvDar1qNaBUIGEu" "J7cvtG0FON+mWN/kCkA39lr3Lxd0mA7l1TZ1HLcrpkWiVajFk9CfcXP5Cd5d7709" "Y6cKZT0CgYEAmyqqETroCLByAQ0fZCUa6VfDHl1YiTJGwjZlLJDtF+L6zyDDaZU5" "k9oxn7smlfxQu7aIyYHiFW8rkhCJa4vFZS0ivnOseLFH5dbXxwM0e7pjzZJsf8aO" "m3iWlOT3oT0DUkfOkOFvxSB9eW1BsWq2966xfLlM9OFJv8oAsWLsp74=" "\n-----END RSA PRIVATE KEY-----\n"; char pubKeyStr[] = "-----BEGIN PUBLIC KEY-----\n" "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtMs6bXNIWoR3PhrP1NvS\n" "hmFK0xSEFnhi/vnzlRU5BmNSzjP7B2HBA5qByPIu1TLCP6trpPBZrasdZNxkfJga\n" "xeucipvZPrDgsZhEZdqZU3pB9fnG9wopx3dLP1VBV+0QA2cnte4fLtL6T3z4+sw+\n" "QQRgI59VEqWGtBYxmcE7HDgzciOts4xUxhXGG0MVFBoJguvpCk+MT5ZQX/GnTHCr\n" "nIcsdjcLxEAIVbMqKecNVBWpE7k8hS2mK7QPwDvJEuPZ2k0pem00hyMPW2klvZhi\n" "HghRqSmZisg42WIVFR+PWMojNDPsjQerJmHh95FayCGEbs6bwLoSUeJ/oI5UVzee\n" "2QIDAQAB\n" "-----END PUBLIC KEY-----\n"; ///公鑰加密私鑰解密 EncryptOrDecryptByPublicKey(data, dataLen, &enData, &enLen, ENCRYPT_MODE, pubKeyStr, STRING_TYPE); Base64Encode(enData, enLen, &base64EnData, &base64EnLen); printf("%s\n", base64EnData); EncryptOrDecryptByPrivateKey(enData, enLen, &deData, &deLen, DECRYPT_MODE, priKeyStr, STRING_TYPE); printf("%s\n", deData); printf("%d\n", strcmp(data, deData)); ///私鑰機密公鑰解密 EncryptOrDecryptByPrivateKey(data, dataLen, &enData, &enLen, ENCRYPT_MODE, priKeyStr, STRING_TYPE); Base64Encode(enData, enLen, &base64EnData, &base64EnLen); printf("%s\n", base64EnData); EncryptOrDecryptByPublicKey(enData, enLen, &deData, &deLen, DECRYPT_MODE, pubKeyStr, STRING_TYPE); printf("%s\n", deData); printf("%d\n", strcmp(data, deData)); ///證書自校驗 int verifyResult = -1; verifyResult = X509Verify(DER_CERT_PATH, DER_CERT_PATH);///0表示校驗成功,1表示校驗失敗 printf("%d\n", verifyResult); return 0; }