openssl rsa加密,解密以及X509证书的使用

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;
    }
原文地址:https://www.cnblogs.com/Black-Cobra/p/10383309.html