Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1683293
  • 博文数量: 584
  • 博客积分: 13857
  • 博客等级: 上将
  • 技术积分: 11883
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-16 09:34

分类: LINUX

2010-09-03 09:59:57

主要介绍了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;

 

.初始化函数

rsa * rsa_new(void);初始化一个rsa结构

 

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

 

rsa私 钥产生函数

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

 

.判断位数函 数

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

 

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

 

rsarsa_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);

 

.加解密函数

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.....都不为空的话,他会调用中国剩余定理来进行加密。

 

.签名函数

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)

 

.写入文件函 数

 int rsa_print(bio *bp, rsa *x, int offset);

 

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

 

.其他

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研究和实现比较有价值
 

.初始化函数

 

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,要不就释放空间。

 

.上下文情景函数,存储计算中的中间过程

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;

 

.复制以及交换函数

  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

 

.取位函数

 

. 产生素数函数

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表示错误

 

.位数函数

 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

 

.与字符串 的转换函数

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);

 

.其他函数

下面函数可以进行更有效率的模乘和模除,假如在重复在同一模下重复进行模乘和模除计算,计算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,

 



阅读(1844) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~