• openssl 非对称加密 RSA 加密解密以及签名验证签名


    1. 简介

       openssl  rsa.h 提供了密码学中公钥加密体系的一些接口,

       本文主要讨论利用rsa.h接口开发以下功能

    •      公钥私钥的生成
    •      公钥加密,私钥解密
    •      私钥加密,公钥解密
    •      签名:私钥签名
    •      验证签名:公钥验签

    2. 生成公钥私钥对

        主要接口,

    /* Deprecated version */
    DEPRECATEDIN_0_9_8(RSA *RSA_generate_key(int bits, unsigned long e, void
                                             (*callback) (int, int, void *),
                                             void *cb_arg))
    
    /* New version */
    int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);

      接口调用需要先生成一个大数,如下生成密钥对示例

        //生成密钥对
        RSA *r = RSA_new();
        int bits = 512;
        BIGNUM *e = BN_new();
        BN_set_word(e, 65537);
        RSA_generate_key_ex(r, bits, e, NULL);
        //打印密钥
        RSA_print_fp(stdout, r, 0);

     打印的密钥对结果:

    Private-Key: (512 bit)
    modulus:
        00:c0:53:6c:46:57:ed:4e:33:bb:71:ec:be:d6:21:
        78:bf:9b:be:4f:8b:fb:32:ae:f2:83:9c:e7:b8:63:
        a2:34:9c:98:cc:4a:a2:17:1d:31:03:c8:f6:e0:13:
        3a:29:40:c8:1a:d4:b7:88:38:07:4c:3b:2a:01:0b:
        17:45:36:4f:f9
    publicExponent: 65537 (0x10001)
    privateExponent:
        00:8f:59:9e:ca:8f:9f:01:3a:ed:eb:ec:5a:11:a0:
        c1:2f:90:16:39:94:4c:97:6a:6e:b8:4a:ab:2c:74:
        96:e2:3e:c8:aa:34:bb:99:9e:e5:60:86:b4:8f:55:
        49:80:dc:26:06:74:13:64:49:ac:31:f8:fe:4d:80:
        e1:e2:bf:fd:41
    prime1:
        00:fd:95:4d:f0:25:a0:87:5e:d1:c9:0e:b8:96:f9:
        ce:0a:ef:59:e7:a4:57:49:d8:fd:dd:e6:c4:59:24:
        dd:e6:33
    prime2:
        00:c2:28:a9:7b:c8:98:97:33:32:f0:52:9a:26:a2:
        0b:50:3b:86:c0:55:6d:c6:c7:d1:a1:43:1d:d3:7d:
        53:cd:23
    exponent1:
        6c:80:d8:2a:6b:4f:36:dd:21:92:90:13:f7:b5:c7:
        ad:f2:20:5b:f7:7b:ca:03:69:0c:eb:d3:13:f9:ac:
        60:f5
    exponent2:
        55:44:e2:5a:18:98:db:1e:83:2a:84:3c:6a:e7:13:
        ac:e2:d7:a5:34:5f:87:c3:4d:cf:52:d8:90:7f:24:
        04:9d
    coefficient:
        00:d7:0d:9b:e8:2f:3c:00:86:00:a0:b2:8b:00:1d:
        e2:b9:0f:9f:ca:b2:75:84:ea:c8:9d:5e:78:e5:e3:
        92:46:aa
    View Code

    3. 公钥加密,私钥解密

       主要接口

    int RSA_public_encrypt(int flen, const unsigned char *from,
                           unsigned char *to, RSA *rsa, int padding);
    int RSA_private_decrypt(int flen, const unsigned char *from,
                            unsigned char *to, RSA *rsa, int padding);

      由于较长数据需要分组加密,如下封装了一层

    //公钥加密
    int kkrsa_public_encrypt(char *inStr,char *outData,RSA *r)
    {
        int encRet = 0;
        unsigned long inLen = strlen(inStr);
        int pdBlock = RSA_size(r)-11;
        unsigned int eCount = (inLen / pdBlock) +1;
        //分组加密,可以看出outData最大不超过malloc[eCount*pdBlock]
        for (int i=0; i < eCount; i++) {
            RSA_public_encrypt(inLen > pdBlock?pdBlock:inLen, inStr, outData, r, RSA_PKCS1_PADDING);
            inStr += pdBlock;
            outData+=RSA_size(r);
            encRet+=RSA_size(r);
            inLen -= pdBlock;
        }
        return encRet;
    }
    //私钥解密
    int kkrsa_private_decrypt(char *inStr,char *outData,RSA *r)
    {
        int decRet = 0;
        unsigned long inLen = strlen(inStr);
        int pdBlock = RSA_size(r);
        unsigned int dCount = inLen / pdBlock;
        //分组解密
        for (int i=0; i < dCount; i++) {
            int ret = RSA_private_decrypt(pdBlock, inStr, outData, r, RSA_PKCS1_PADDING);
            inStr += pdBlock;
            outData+=ret;
            decRet+=ret;
        }
        return decRet;
    }

     测试例子,例子中的r,就是上面生成的RSA密钥对,

        //测试一
        printf("block:%d 
    ",RSA_size(r));
        char *src = "this is test encrypt data use RSA_PKCS1_PADDING";
        printf("src:%s  len=%d
    ",src,strlen(src));
        char *encDat = malloc(1024);
        //公钥加密
        int encRet = kkrsa_public_encrypt(src, encDat, r);
        printf("enc:%d
    ",encRet);
        
        char *decDat = malloc(1024);
        //私钥解密
        int decRet = kkrsa_private_decrypt(encDat, decDat, r);
        printf("dec:%s  len=%d
    ",decDat,decRet);
        
        free(encDat);
        free(decDat);
        

     打印结果:

    block:64 
    src:this is test encrypt data use RSA_PKCS1_PADDING  len=47
    enc:64
    dec:this is test encrypt data use RSA_PKCS1_PADDING  len=47
    
    test2
    src:this is test private encrypt data use RSA_PKCS1_PADDING  len=55
    enc:128
    dec:this is test private encrypt data use RSA_PKCS1_PADDI  len=53
    View Code

    4. 私钥加密,公钥解密

      主要接口

    int RSA_private_encrypt(int flen, const unsigned char *from,
                            unsigned char *to, RSA *rsa, int padding);
    int RSA_private_decrypt(int flen, const unsigned char *from,
                            unsigned char *to, RSA *rsa, int padding);

     同样如果数据较长需要进行分组加密,如下简单封装的接口

    //私钥加密
    int kkrsa_private_encrypt(char *inStr,char *outData,RSA *r)
    {
        int encRet = 0;
        unsigned long inLen = strlen(inStr);
        int pdBlock = RSA_size(r)-11;
        unsigned int eCount = (inLen / pdBlock) +1;
        //分组加密,可以看出outData最大不超过malloc[eCount*pdBlock]
        for (int i=0; i < eCount; i++) {
            RSA_private_encrypt(inLen > pdBlock?pdBlock:inLen, inStr, outData, r, RSA_PKCS1_PADDING);
            inStr += pdBlock;
            outData+=RSA_size(r);
            encRet+=RSA_size(r);
            inLen -= pdBlock;
        }
        return encRet;
    }
    //公钥解密
    int kkrsa_public_decrypt(char *inStr,char *outData,RSA *r)
    {
        int decRet = 0;
        unsigned long inLen = strlen(inStr);
        int pdBlock = RSA_size(r);
        unsigned int dCount = inLen / pdBlock;
        //分组解密
        for (int i=0; i < dCount; i++) {
            int ret = RSA_public_decrypt(pdBlock, inStr, outData, r, RSA_PKCS1_PADDING);
            inStr += pdBlock;
            outData+=ret;
            decRet+=ret;
        }
        return decRet;
    }

     调用示例:需要上面生成的密钥对RSA r

      //测试二
        printf("
    test2
    ");
        char *src2 = "this is test private encrypt data use RSA_PKCS1_PADDING";
        printf("src:%s  len=%d
    ",src2,strlen(src2));
        char *encDat2 = malloc(1024);
        //私钥加密
        int encRet2 = kkrsa_private_encrypt(src2, encDat2, r);
        printf("enc:%d
    ",encRet2);
        
        char *decDat2 = malloc(1024);
        //公钥解密
        int decRet2 = kkrsa_public_decrypt(encDat2, decDat2, r);
        printf("dec:%s  len=%d
    ",decDat2,decRet2);
        
        free(encDat2);
        free(decDat2);

     测试结果:

    test2
    src:this is test private encrypt data use RSA_PKCS1_PADDING  len=55
    enc:128
    dec:this is test private encrypt data use RSA_PKCS1_PADDING372314375۷GO304  len=55
    View Code

    5. 签名与验证签名

       主要接口

    int RSA_sign(int type, const unsigned char *m, unsigned int m_length,
                 unsigned char *sigret, unsigned int *siglen, RSA *rsa);
    int RSA_verify(int type, const unsigned char *m, unsigned int m_length,
                   const unsigned char *sigbuf, unsigned int siglen, RSA *rsa);

    测试示例,同样需要上面生成的RSA密钥对

        //签名
        printf("
    test sign and verify
    ");
        char *msg = "0123456789";
        char *sinDat = malloc(RSA_size(r));
        int sinLen = 0;
        RSA_sign(NID_sha1, msg,strlen(msg),sinDat,&sinLen, r);
        
        int vret = RSA_verify(NID_sha1, msg, strlen(msg), sinDat, sinLen, r);
        printf("sign_verify=%d
    ",vret);

    打印结果

    test sign and verify
    sign_verify=1
    View Code

    6. 总结

      上述RSA分组加密中使用了RSA_PKCS1_PADDING 的补位方式;当然还有如下

      不同的补位方式,在进行分组加密时,需要注意分组块的处理

    # define RSA_PKCS1_PADDING       1
    # define RSA_SSLV23_PADDING      2
    # define RSA_NO_PADDING          3
    # define RSA_PKCS1_OAEP_PADDING  4
    # define RSA_X931_PADDING        5
    /* EVP_PKEY_ only */
    # define RSA_PKCS1_PSS_PADDING   6
    
    # define RSA_PKCS1_PADDING_SIZE  11

    测试使用 openssl 1.1.0c

    参考:https://www.openssl.org/docs/man1.0.2/crypto/RSA_public_encrypt.html

    https://www.openssl.org/docs/manmaster/man3/RSA_verify.html

      

  • 相关阅读:
    UILabel 设置字体间的距离 和 行与行间的距离
    IB_DESIGNABLE 和 IBInspectable 的使用
    干货博客
    GitHub克隆速度太慢解决方案
    实时(RTC)时钟,系统时钟和CPU时钟
    折腾了好久的vscode配置c/c++语言环境(Windows环境下)
    c语言中的malloc函数
    记录一下关于在工具类中更新UI使用RunOnUiThread犯的极其愚蠢的错误
    记录关于Android多线程的一个坑
    Android中限制输入框最大输入长度
  • 原文地址:https://www.cnblogs.com/cocoajin/p/6126099.html
Copyright © 2020-2023  润新知