Openssl中大数以及RSA相关函数介绍 [转]

主要介绍了openssl之rsa相关函数,这个对学习和实现rsa算法比较有帮助。

rsa基 本结构
struct

 {


  int pad;


  long version;


  const rsa_method *meth;


  engine *engine;


  bignum *n;         n=p*q


  bignum *e;         公开的加密指数,经常为65537(ox10001)


  bignum *d;         私钥


  bignum *p;         大素数p


  bignum *q;         大素数q


  bignum *dmp1;      d mod (p-1)


  bignum *dmq1;      d mod (q-1)


  bignum *iqmp;      (inverse of q) mod p


  int references;


  int flags;


    // ...


  }rsa;

2.初始化函数
rsa * rsa_new(void);初始化一个rsa结构

void rsa_free(rsa *rsa);释放一个rsa结构

3.rsa私 钥产生函数
rsa *rsa_generate_key(int num, unsigned long e,void (*callback)(int,int,void *), void *cb_arg);产生一个模为num位的密钥对,e为公开的加密指数,一般为65537(ox10001),假如后两个参数不为null,将有些调用。在产生密钥对之前,一般需要指定随机数种子

4.判断位数函 数
int rsa_size(const rsa *rsa);返回rsa模的位数,他用来判断需要给加密值分配空间的大小

int rsa_check_key(rsa rsa);他测试p,q是否为素数,n=pq,de = 1 mod (p-1q-1), dmp1, dmq1, iqmp是否均设置正确了。

5.rsa的rsa_method函 数
了解rsa的运算那就必须了解rsa_method,下面我们先看看rsa_method结构

typedef struct rsa_meth_st

    {


    const char *name;


    int (*rsa_pub_enc)(int flen,const unsigned char *from,


        unsigned char *to,rsa *rsa,int padding);


    int (*rsa_pub_dec)(int flen,const unsigned char *from,


         unsigned char *to,rsa *rsa,int padding);


    int (*rsa_priv_enc)(int flen,const unsigned char *from,


            unsigned char *to, rsa *rsa,int padding);


    int (*rsa_priv_dec)(int flen,const unsigned char *from,


            unsigned char *to,rsa *rsa,int padding);


    int (*rsa_mod_exp)(bignum *r0,const bignum *i,rsa *rsa);        int (*bn_mod_exp)(bignum *r, const bignum *a, const bignum *p,


            const bignum *m, bn_ctx *ctx,bn_mont_ctx *m_ctx);


    int (*init)(rsa *rsa);          /* called at new */


    int (*finish)(rsa *rsa);        /* called at free */


    int flags;              /* rsa_method_flag_* things */


    char *app_data;                  /* may be needed! */


    int (*rsa_sign)(int type,const unsigned char *m, unsigned int m_length,unsigned char *sigret, unsigned int *siglen, const rsa *rsa);


    int (*rsa_verify)(int dtype,const unsigned char *m, unsigned int m_length,unsigned char *sigbuf, unsigned int siglen, const rsa *rsa);


    } rsa_method;

const rsa_method *rsa_pkcs1_ssleay(void);

const rsa_method *rsa_null_method(void);

主要有上面两个函数。第二个函数是定义了rsa_null才会调用,其实要调用这个函数以后几乎什么都不能干,只是输出错误信息。第一个是常用的method,下面我们看看它的定义

const rsa_method *rsa_pkcs1_ssleay(void)

    {


    return(&rsa_pkcs1_eay_meth);


    }

static rsa_method rsa_pkcs1_eay_meth={

    "eric young's pkcs#1 rsa",


    rsa_eay_public_encrypt,


    rsa_eay_public_decrypt, /* signature verification */


    rsa_eay_private_encrypt, /* signing */


    rsa_eay_private_decrypt,


    rsa_eay_mod_exp,


    bn_mod_exp_mont,


    rsa_eay_init,


    rsa_eay_finish,


    0, /* flags */


    null,


    0, /* rsa_sign */


    0  /* rsa_verify */


    };

由此可以看出,一般rsa->meth-> rsa_pub_enc对应于rsa_eay_public_encrypt,刚开始看openssl的时候最难得就是这个指向函数的指针,根本不知道rsa->meth-> rsa_pub_enc对应于哪里。在openssl里面这种指针很多,到以后也能够看到。下面是设置meth的一些函数应该都很容易理解

void rsa_set_default_method(const rsa_method *meth);

const rsa_method *rsa_get_default_method(void);

int rsa_set_method(rsa *rsa, const rsa_method *meth);

const rsa_method *rsa_get_method(const rsa *rsa);

int rsa_flags(const rsa *rsa);

rsa *rsa_new_method(engine *engine);

6.加解密函数
int rsa_public_encrypt(int flen, unsigned char *from, unsigned char *to, rsa *rsa, int padding);

int rsa_private_decrypt(int flen, unsigned char *from,unsigned char *to, rsa *rsa, int padding);

int rsa_private_encrypt(int flen, unsigned char *from, unsigned char *to, rsa *rsa,int padding);

int rsa_public_decrypt(int flen, unsigned char *from,

unsigned char *to, rsa *rsa,int padding);

有了第4节的基础,那理解这些加解密函数就容易了,假如

rsa_set_method(rsa, rsa_pkcs1_ssleay())的话,那rsa_public_encrypt对应于rsa_eay_public_encrypt,这样我们就可以调试公钥加密的过程了。flen为要加密信息的长度,from为需要加密的信息,to为加密后的信息,一般to至少要申请bn_num_bytes(rsa->n)大的空间。padding是采取的加解密方案。pkcs#1中主要提供了两种加密方案,rsaex-oaep和psaes-pkcs1-v1_5(反正就是两种加密过程了,有点复杂,它主要是先对先对需要加密的数据进行了编码,比如rsaes-oaep采用eme-oaep编码,再进行加密或解密)。openssl中已经编好了编码的函数:

case rsa_pkcs1_padding:

i=rsa_padding_add_pkcs1_type_2(buf,num,from,flen);

#ifndef openssl_no_sha

case rsa_pkcs1_oaep_padding: i=rsa_padding_add_pkcs1_oaep(buf,num,from,flen,null,0);

#endif

case rsa_sslv23_padding:

i=rsa_padding_add_sslv23(buf,num,from,flen);

case rsa_no_padding:

i=rsa_padding_add_none(buf,num,from,flen);

等上面编好码后,就调用bn_mod_exp_mont来进行模幂了。最后得出值,这也就是具体的加密和解密过程。在这里还可以发现,加密时输入的rsa有两种方式,一是p,q,…为null,只有rsa->d,和rsa->n不为空,这样就直接用rsa->d和rsa->n进行模幂计算,假如p,q…都不为空的话,他会调用中国剩余定理来进行加密。

7.签名函数
int rsa_sign(int type, unsigned char *m, unsigned int m_len, unsigned char *sigret, unsigned int *siglen, rsa *rsa);

int rsa_verify(int type, unsigned char *m, unsigned int m_len, unsigned char *sigbuf, unsigned int siglen, rsa *rsa);

其实签名其实和用私钥加密差不多是一回事,所以签名函数最终调用的就是私钥加密的函数,在openssl中这个签名函数很少单独拿出来用的,都是为了给evp_signfinal来调用的。所以假如是利用rsa进行签名的话,rsa_private_encrypt,bn_mod_exp_mont是最基本的,所有的都需要调用他,区别无非就在于在需要签名的信息上做了一下处理(一般将需要签名的信息求取摘要值得到m)

8.写入文件函 数
int rsa_print(bio *bp, rsa *x, int offset);

int rsa_print_fp(file *fp, rsa *x, int offset);offset是为了调整输出格式的,随意一个数都可以(例如2,12,16。。)

9.其他
int rsa_blinding_on(rsa *rsa, bn_ctx *ctx);

void rsa_blinding_off(rsa *rsa);

为了防止时间攻击,openssl还在签名的时候产生一个随机因子,附加在私钥上。

int rsa_sign_asn1_octet_string(int dummy, unsigned char *m,unsigned int m_len, unsigned char *sigret, unsigned int *siglen,rsa *rsa);

int rsa_verify_asn1_octet_string(int dummy, unsigned char *m,unsigned int m_len, unsigned char *sigbuf, unsigned int siglen,rsa *rsa);

用私钥对八元组串进行签名,原理同rsa_sign
openssl有关大数运算函数介绍- -

主要介绍openssl中的有关大数运算函数,这个对于以后的rsa研究和实现比较有价值

1.初始化函数

bignum *bn_new(void); 新生成一个bignum结构

void bn_free(bignum *a); 释放一个bignum结构,释放完后a=null;

void bn_init(bignum *); 初始化所有项均为0,一般为bn_ init(&c)

void bn_clear(bignum *a); 将a中所有项均赋值为0,但是内存并没有释放

void bn_clear_free(bignum *a); 相当与将bn_free和bn_clear综合,要不就赋值0,要不就释放空间。

2.上下文情景函数,存储计算中的中间过程
bn_ctx *bn_ctx_new(void);申请一个新的上下文结构

void bn_ctx_init(bn_ctx *c);将所有的项赋值为0,一般bn_ctx_init(&c)

void bn_ctx_free(bn_ctx *c);释放上下文结构,释放完后c=null;

3.复制以及交换函数
bignum *bn_copy(bignum *a, const bignum *b);将b复制给a,正确返回a,错误返回null

bignum *bn_dup(const bignum *a);新建一个bignum结构,将a复制给新建结构返回,错误返回null

bignum *bn_swap(bignum *a, bignum *b);交换a,b

4.取位函数

9. 产生素数函数
bignum *bn_generate_prime(bignum *ret, int bits,int safe, bignum *add, bignum *rem, void (*callback)(int, int, void *), void *cb_arg);产生一个bits位的素数,后面几个参数都可以为null

int bn_is_prime(const bignum *p, int nchecks, void (*callback)(int, int, void *), bn_ctx *ctx, void *cb_arg);

判断是否为素数,返回0表示成功,1表示错误概率小于0。25,-1表示错误

10.位数函数
int bn_set_bit(bignum *a, int n);将a中的第n位设置为1,假如a小于n位将扩展

int bn_clear_bit(bignum *a, int n);将a中的第n为设置为0,假如a小于n位将出错

int bn_is_bit_set(const bignum *a, int n);测试是否已经设置,1表示已设置

int bn_mask_bits(bignum *a, int n);将a截断至n位,假如a小于n位将出错

int bn_lshift(bignum *r, const bignum *a, int n);a左移n位,结果存于r

int bn_lshift1(bignum *r, bignum *a); a左移1位,结果存于r

int bn_rshift(bignum *r, bignum *a, int n); a右移n位,结果存于r

int bn_rshift1(bignum *r, bignum *a); a左移1位,结果存于r

11.与字符串 的转换函数
int bn_bn2bin(const bignum *a, unsigned char *to);将abs(a)转化为字符串存入to,to的空间必须大于bn_num_bytes(a)

bignum *bn_bin2bn(const unsigned char *s, int len, bignum *ret);将s中的len位的正整数转化为大数

char *bn_bn2hex(const bignum *a);转化为16进制字符串

char *bn_bn2dec(const bignum *a);转化为10进制字符串

int bn_hex2bn(bignum **a, const char *str);同上理

int bn_dec2bn(bignum **a, const char *str);同上理

int bn_print(bio *fp, const bignum *a);将大数16进制形式写入内存中

int bn_print_fp(file *fp, const bignum *a); 将大数16进制形式写入文件

int bn_bn2mpi(const bignum *a, unsigned char *to);

bignum *bn_mpi2bn(unsigned char *s, int len, bignum *ret);

12.其他函数
下面函数可以进行更有效率的模乘和模除,假如在重复在同一模下重复进行模乘和模除计算,计算r=(a*b)%m 利用了recp=1/m

bn_recp_ctx *bn_recp_ctx_new(void);

void bn_recp_ctx_init(bn_recp_ctx *recp);

void bn_recp_ctx_free(bn_recp_ctx *recp);

int bn_recp_ctx_set(bn_recp_ctx *recp, const bignum *m, bn_ctx *ctx);

int bn_mod_mul_reciprocal(bignum *r, bignum *a, bignum *b,

bn_recp_ctx *recp, bn_ctx *ctx);

下面函数采用蒙哥马利算法进行模幂计算,可以提高效率,他也主要应用于在同一模下进行多次幂运算

bn_mont_ctx *bn_mont_ctx_new(void);

void bn_mont_ctx_init(bn_mont_ctx *ctx);

void bn_mont_ctx_free(bn_mont_ctx *mont);

int bn_mont_ctx_set(bn_mont_ctx *mont, const bignum *m, bn_ctx *ctx);

bn_mont_ctx *bn_mont_ctx_copy(bn_mont_ctx *to, bn_mont_ctx *from);

int bn_mod_mul_montgomery(bignum *r, bignum *a, bignum *b, bn_mont_ctx *mont, bn_ctx *ctx);

int bn_from_montgomery(bignum *r, bignum *a, bn_mont_ctx *mont, bn_ctx *ctx);

int bn_to_montgomery(bignum *r, bignum *a, bn_mont_ctx *mont,

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值