Openssl的相关使用
生成证书
- 生成证书见:使用 openssl 生成证书
代码实现
Cert.h
#ifndef _CERT_H
#define _CERT_H
///header files
#include <stdio.h>
#include <string.h>
#include <openssl
sa.h>
#include <opensslpem.h>
#include <opensslevp.h>
#include <openssl/engine.h>
#include <opensslx509.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
", __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.cpp
#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
", base64EnData);
EncryptOrDecryptByPrivateKey(enData, enLen, &deData, &deLen, DECRYPT_MODE, PRI_KEY_PATH, FILE_TYPE);
printf("%s
", deData);
printf("%d
", strcmp(data, deData));
///私钥加密公钥解密
EncryptOrDecryptByPrivateKey(data, dataLen, &enData, &enLen, ENCRYPT_MODE, PRI_KEY_PATH, FILE_TYPE);
Base64Encode(enData, enLen, &base64EnData, &base64EnLen);
printf("%s
", base64EnData);
EncryptOrDecryptByPublicKey(enData, enLen, &deData, &deLen, DECRYPT_MODE, PUB_KEY_PATH, FILE_TYPE);
printf("%s
", deData);
printf("%d
", strcmp(data, deData));
///字符串加密
char priKeyStr[] = "-----BEGIN RSA PRIVATE KEY-----
"
"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="
"
-----END RSA PRIVATE KEY-----
";
char pubKeyStr[] = "-----BEGIN PUBLIC KEY-----
"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtMs6bXNIWoR3PhrP1NvS
"
"hmFK0xSEFnhi/vnzlRU5BmNSzjP7B2HBA5qByPIu1TLCP6trpPBZrasdZNxkfJga
"
"xeucipvZPrDgsZhEZdqZU3pB9fnG9wopx3dLP1VBV+0QA2cnte4fLtL6T3z4+sw+
"
"QQRgI59VEqWGtBYxmcE7HDgzciOts4xUxhXGG0MVFBoJguvpCk+MT5ZQX/GnTHCr
"
"nIcsdjcLxEAIVbMqKecNVBWpE7k8hS2mK7QPwDvJEuPZ2k0pem00hyMPW2klvZhi
"
"HghRqSmZisg42WIVFR+PWMojNDPsjQerJmHh95FayCGEbs6bwLoSUeJ/oI5UVzee
"
"2QIDAQAB
"
"-----END PUBLIC KEY-----
";
///公钥加密私钥解密
EncryptOrDecryptByPublicKey(data, dataLen, &enData, &enLen, ENCRYPT_MODE, pubKeyStr, STRING_TYPE);
Base64Encode(enData, enLen, &base64EnData, &base64EnLen);
printf("%s
", base64EnData);
EncryptOrDecryptByPrivateKey(enData, enLen, &deData, &deLen, DECRYPT_MODE, priKeyStr, STRING_TYPE);
printf("%s
", deData);
printf("%d
", strcmp(data, deData));
///私钥机密公钥解密
EncryptOrDecryptByPrivateKey(data, dataLen, &enData, &enLen, ENCRYPT_MODE, priKeyStr, STRING_TYPE);
Base64Encode(enData, enLen, &base64EnData, &base64EnLen);
printf("%s
", base64EnData);
EncryptOrDecryptByPublicKey(enData, enLen, &deData, &deLen, DECRYPT_MODE, pubKeyStr, STRING_TYPE);
printf("%s
", deData);
printf("%d
", strcmp(data, deData));
///证书自校验
int verifyResult = -1;
verifyResult = X509Verify(DER_CERT_PATH, DER_CERT_PATH);///0表示校验成功,1表示校验失败
printf("%d
", verifyResult);
return 0;
}