2021SC@SDUSC 大数运算

2021SC@SDUSC

11 大数
11.1 介绍

大数一般指的是位数很多的数。 计算机表示的数的大小是有限的,精度也是有限的,它不能支持大数运算。 密码学中采用了很多大数计算,为了让计算机实现大数运算,用户需要定义自己的大数表示方式并及实现各种大数运算。 Openssl为我们提供了这些功能,主要用于非对称算法。

11.2 openssl大数表示

    crypto/bn.h中定义了大数的表示方式,如下:

    struct bignum_st
    {
   
           BN_ULONG *d;
           int top;
           int dmax;
           int neg;
           int flags;
    };

    /*
    各项意义如下:
      d   :BN_ULONG(应系统而异,win32下为4个字节)数组指针首地址,
            大数就存放在这里面,不过是倒放的。
            比如,用户要存放的大数为 12345678000(通过BN_bin2bn放入),
            则 d 的内容如下:
                 0x30 0x30 0x30 0x38 0x37 0x36 0x35 0x34 0x33 0x32 0x31 ;

      top :用来指明大数占多少个BN_ULONG空间,上例中top为3。
      dmax:d数组的大小。
      neg :是否为负数, 如果 为1,则是负数,为0,则为正数。
      flags:用于存放一些标记,
             比如flags
               含有 BN_FLG_STATIC_DATA 时, d 的内存是静态分配的;
               含有 BN_FLG_MALLOCED    时,d 的内存是动态分配的。
    */

11.3 大数函数

大数函数一般都能根据函数名字知道其实现的功能。下面简单介绍了几个函数。

1)

    int BN_rand(BIGNUM *rnd, int bits, int top, int bottom);
    int BN_priv_rand(BIGNUM *rnd, int bits, int top, int bottom);
    int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom);
生成一个随机的大数。

2)

    int BN_rand_range(BIGNUM *rnd, BIGNUM *range);
    int BN_priv_rand_range(BIGNUM *rnd, BIGNUM *range);
    int BN_pseudo_rand_range(BIGNUM *rnd, BIGNUM *range);
生成随机数,但是给出了随机数的范围。

3)

    BIGNUM *BN_copy(BIGNUM *to, const BIGNUM *from);
    BIGNUM *BN_dup(const BIGNUM *from);
    void BN_with_flags(BIGNUM *dest, const BIGNUM *b, int flags);
大数复制。
    int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe, const BIGNUM *add,
                           const BIGNUM *rem, BN_GENCB *cb);

    #if OPENSSL_API_COMPAT < 0x00908000L
    BIGNUM *BN_generate_prime(BIGNUM *ret, int num, int safe, BIGNUM *add,
                              BIGNUM *rem, void (*callback)(int, int, void *),
                              void *cb_arg);
生成素数。

5)

int BN_add_word(BIGNUM *a, BN_ULONG w)

    给大数a加上w,

        BN_add_word() adds w to a ("a+=w").
        BN_sub_word() subtracts w from a ("a-=w").
        BN_mul_word() multiplies a and w ("a*=w").
        BN_div_word() divides a by w ("a/=w") and returns the remainder.
        BN_mod_word() returns the remainder of a divided by w ("a%w").

        For BN_div_word() and BN_mod_word(), w must not be 0.

    return 1 for success, 0 on error
  1. 转换

6.1

     BIGNUM * BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret)
   将 s 中的换为大数,

   入参
       s  : 为内存地址,
       len : 为数据长度,
   出参:
       ret : 为返回值。

6.2

       int BN_bn2bin(const BIGNUM *a, unsigned char *to)
   将大数转换为内存形式。

   入参:
           a  : 大数,
           to : 为输出缓冲区地址,缓冲区需要预先分配,可以为NULL,

   return : 返回冲区的长度。

   BN_bn2bin() returns the length of the big-endian number placed at to.
   BN_bin2bn() returns the BIGNUM, NULL on error

6.3

       char *BN_bn2dec(const BIGNUM *a)
   将大数转换成整数字符串。

   return : 返回值中存放 整数字符串,它由内部分配空间,
            用户必须在外部用OPENSSL_free函数释放该空间。
       int BN_dec2bn(BIGNUM **a, const char *str);  //将整数字符串转换成大数。

6.4

       char *BN_bn2hex(const BIGNUM *a)
   将大数转换为十六进制字符串。

   return: 返回值为生成的十六进制字符串,
           外部需要用OPENSSL_free函数释放
       int BN_hex2bn(BIGNUM **a, const char *str); // 将十六进制字符串转换为大数
   BN_bn2hex() and BN_bn2dec() return a null-terminated string, or NULL on error.
   BN_hex2bn() and BN_dec2bn() return the number of characters used in parsing,
   or 0 on error, in which case no new BIGNUM will be created.
  1. 比较
    int BN_cmp(BIGNUM *a, BIGNUM *b);  比较两个大数。
    int BN_ucmp(BIGNUM *a, BIGNUM *b); 比较两个大数绝对值。

    int BN_is_zero(BIGNUM *a);
    int BN_is_one(BIGNUM *a);
    int BN_is_word(BIGNUM *a, BN_ULONG w);
    int BN_is_odd(BIGNUM *a);

11)

BIGNUM *BN_mod_inverse( BIGNUM *in,
                            const BIGNUM *a,
                            const BIGNUM *n,
                            BN_CTX *ctx)
计算ax=1(mod n)。

用户使用openssl函数编程时, 一般用不着进行大数运算。
BN_bin2bn、BN_hex2bn、BN_dec2bn、BN_bin2bn、BN_bn2bin、BN_bn2hex和BN_bn2dec比较常用。
比如给定RSA密钥的内存形式,用户可以调用BN_bin2bn来构造RSA密钥的大数元素来进行RSA运算,
或者已经生成了RSA密钥,用户调用BN_bn2bin将RSA各个元素导出到内存中再写入密钥文件。

#include <openssl/bio.h>
#include <openssl/bn.h>

int main() 
{
   
	int ret; 
	BIGNUM *a;
	BN_ULONG w;

	a=BN_new(); 
	//BN_zero(a); 
	//BN_one(a); 
	//BN_set_word(a,16);
	//BN_set_word(a,256);
	w=2685550010; 
	//w=0x2685550010; 
	ret=BN_add_word(a,w); 
	if(ret!=1) {
   
		printf("a+=w err!\n"); 
		BN_free(a);
		return -1;
	} 
	
	BIO *bio_out;
	bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);

		
	//int BN_print(BIO *fp, const BIGNUM *a);
	BIO_printf(bio_out, "-------------------\n");
	BN_print(bio_out, a);
	BIO_printf(bio_out, "\n-------------------\n");

        int bits = BN_num_bits(a);
	BIO_printf(bio_out, "bits = %d \n" ,bits);

        bits = BN_num_bytes(a);
	BIO_printf(bio_out, "bytes = %d \n" ,bits);
	
	BN_free(a); 
	return 0;
}
#include <openssl/bio.h>
#include <openssl/bn.h>

int main()
{
   
    BIGNUM *ret1,*ret2;
 
    ret1=BN_new();
    ret1=BN_bin2bn("242424ab",8, ret1);
    ret2=BN_bin2bn("242424ab",8, NULL);
	
    // printf
    BIO *bio_out;
    bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);

    BN_print(bio_out, ret1); // 16进制打印
    BIO_printf(bio_out, "\n");
    BN_print(bio_out, ret2);
    BIO_printf(bio_out, "\n");
    BIO_free(bio_out);

    // free
    BN_free(ret1);
    BN_free(ret2);
    return 0;
}
#include <openssl/bio.h>
#include <openssl/bn.h>

int main()
{
   
	BIGNUM *ret = NULL;
	char bin[50]={
   's'}, *buf = 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值