OpenSSL中的大数接口与基于其的自用RSA加密接口设计

本文详述了如何使用OpenSSL的大数接口构建自用RSA加密接口,包括大整数操作、素数判断、RSA密钥生成、随机密钥产生和加密解密过程。通过实例演示了Alice和Bob之间的RSA加密通信。
摘要由CSDN通过智能技术生成

本文记录了初次接触OpenSSL中的大数模块,重温了RSA加密流程,使用OpenSSL的接口包装成自用RSA加密接口,并且利用自己的接口演示了Alice与Bob通过RSA加密进行通讯的一个示例。

概览

自己的库中需要包含的功能有:

  • 构造和对一个大整数对象赋值 (至少支持到2^65536-1)
  • 大整数的加法、乘法、取模、加速乘方等基本算术运算
  • 判断这个大整数是否是素数
  • 通过两个大素数构造RSA公钥(n,e)和私钥d
  • 随机生成80位,128位,256位,512位对称密钥
  • 对不同长度的对称密钥进行加密(包括padding技术)
  • 解密得到不同长度的对称密钥

Part 0 环境准备

由于macOS自带openssl(不自带也可以brew安装)

$ brew info openssl
openssl: stable 1.0.2k (bottled) [keg-only]
SSL/TLS cryptography library
https://openssl.org/
/usr/local/Cellar/openssl/1.0.2k (1,696 files, 12MB)
  Poured from bottle on 2017-04-18 at 10:34:32
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/openssl.rb
==> Dependencies
Build: makedepend ✘
==> Options
--without-test
    Skip build-time tests (not recommended)
==> Caveats
A CA file has been bootstrapped using certificates from the SystemRoots
keychain. To add additional certificates (e.g. the certificates added in
the System keychain), place .pem files in
  /usr/local/etc/openssl/certs

and run
  /usr/local/opt/openssl/bin/c_rehash

This formula is keg-only, which means it was not symlinked into /usr/local,
because Apple has deprecated use of OpenSSL in favor of its own TLS and crypto libraries.

If you need to have this software first in your PATH run:
  echo 'export PATH="/usr/local/opt/openssl/bin:$PATH"' >> ~/.zshrc

For compilers to find this software you may need to set:
    LDFLAGS:  -L/usr/local/opt/openssl/lib
    CPPFLAGS: -I/usr/local/opt/openssl/include
For pkg-config to find this software you may need to set:
    PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig

测试库,书写Makefile

CC = gcc
LDFLAGS =  -L/usr/local/opt/openssl/lib
CPPFLAGS = -I/usr/local/opt/openssl/include

all:test

test:test.c
     $(CC) test.c -o test -lssl -lcrypto $(LDFLAGS) $(CPPFLAGS)
clean:
    rm test

可以成功编译,环境配成完成。

Part 1 构造和对一个大整数对象赋值 (至少支持到2^65536-1)

构造和对一个大整数对象赋值 (至少支持到2^65536-1)

OpenSSL库中所有的大数对象均在bn.h中进行定义。

OpenSSL中的大数结构体如下

#  define BN_ULONG        unsigned int
struct bignum_st {
    BN_ULONG *d;                /* Pointer to an array of 'BN_BITS2' bit
                                 * chunks. */
    int top;                    /* Index of last used d +1. */
    /* The next are internal book keeping for bn_expand. */
    int dmax;                   /* Size of the d array. */
    int neg;                    /* one if the number is negative */
    int flags;
};
  • 很容易发现,OpenSSL中对于大数的处理是用一个BN_ULONG的数组来存的(不过这也是最正常不过的想法)。但是这样的大数是倒放的。

  • 由于是不定长的,所以要一个top 的数来表明大数的长度。

  • dmax保存着最大长度。

  • flags用来标记一些属性

    
    # define BN_FLG_MALLOCED         0x01
    
    
    # define BN_FLG_STATIC_DATA      0x02
    

OpenSSL提供的一些大数的工具有:

  • 生成随机数

    int BN_rand(BIGNUM *rnd, int bits, int top, int bottom);
    int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom);
    int BN_rand_range(BIGNUM *rnd, const BIGNUM *range);
    int BN_pseudo_rand_range(BIGNUM *rnd, const BIGNUM *range);
  • 大数复制

    BIGNUM *BN_dup(const BIGNUM *a);
  • 生成素数

    BIGNUM *BN_generate_prime(BIGNUM *ret, int bits, int safe,
                            const BIGNUM *add, const BIGNUM *rem,
                            void (*callback) (int, int, void *), void *cb_arg);
  • 将内存中的数据转换为大数,为内存地址,len为数据长度,ret为返回值。

    BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);

    BN_bin2bn() converts the positive integer in big-endian form of length len at s into a BIGNUM and places it in ret. If ret is NULL, a new BIGNUM is created.

    FROM : OpenSSL Manuel

  • 将大数放回内存中

    int BN_bn2bin(const BIGNUM *a, unsigned char *to);

    BN_bn2bin() converts the absolute value of a into big-endian form and stores it at to. to must point to BN_num_bytes(a) bytes of memory.

    FROM : OpenSSL Manuel

书写自己的大数包装函数

测试是否支持:2^65536-1

由于网上的Manuel没有找到对应的条目,理论上内存够大应该能实现。下面实际测试能否支持这么大的数。

2655361=(28)8192

书写测试代码:

#include <openssl/bn.h>
#include <stdio.h>
#include <string.h>

int main(){
    int ret;
    int i;
    BIGNUM *a;
    BIGNUM *b;
    unsigned char num[8192];
    num[0] = 0x1;
    num[8190] = 0x01;
    a = BN_bin2bn(num,8192,NULL);
    b = BN_bin2bn(num,8192,NULL);
    BN_add(b,a,b);
    printf("%d\n",a->dmax);
    num[0] = 0x0;
    num[8190] = 0x00;
    ret = BN_bn2bin(b,num);
    printf("0x%x 0x%x 0x%x\n",num[0],num[8190],num[8191]);
    printf("%d\n",ret);
    return 0;
}

测试输出

$ ./test
1024
0x3 0x2 0x0

正常存储,所以就限定我的库最大支持的长度为8192char类型数据。

书写直接从ascii转成大数的函数

在了解了BN的存储定义,这里很容就可以写出直接赋值的函数。

注意,这里str_bn16进制的数字

char ascii2hex(char ascii){
    if(ascii >= '0' && ascii <= '9')
        return ascii - '0';
    else if(ascii >= 'a' && ascii <= 'f')
        return ascii - 'a' + 10;
    else
        return NOT_HEX;
}

/* BN_str2bn
 *
 */
BIGNUM *BN_str2bn(char *str_bn){
    BIGNUM* result = BN_new();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值