Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15529339
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类:

2010-02-27 18:38:21

浅析openssl中RSA_padding_add_PKCS1_type_2和大数类型BIGNUM运算

apps/rsautl.c|289| rsa_outlen  = RSA_public_encrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad);
RSA_public_encrypt
==> rsa->meth->rsa_pub_enc(flen, from, to, rsa, padding)
==> rsa_pkcs1_eay_meth.RSA_eay_public_encrypt
==> RSA_eay_public_encrypt
// 一下一段来自openssl/doc/ssleay.txt|5407|
int RSA_public_encrypt(
int from_len;
unsigned char *from    
unsigned char *to    
RSA *rsa);
    This function implements RSA public encryption, the rsa variable
    should be a public key (but can be a private key).  'from_len'
    bytes taken from 'from' and encrypted and put into 'to'.  'to' needs
    to be at least RSA_size(rsa) bytes long.  The number of bytes
    written into 'to' is returned.  -1 is returned on an error.  The
    operation performed is
    to = from^rsa->e mod rsa->n. // 所以这里可以看出RSA_public_encrypt将只加密一组数据,改组数据

==> RSA_padding_add_PKCS1_type_2(buf,num,from,flen);
==> BN_bin2bn(buf,num,f);
// BN_bin2bn用来将char类型数据转换为BIGNUM大数类型数据,
// f大数类型就是以(m^e)%n实际RSA运算中最大输出数值n为最小存储单位的类似于数组的存储单元
// 其实这样f就可以存储0...(n-1)之间任何数了,也就是f中就可以存储(m^e)%n加密后的小于n的数据
// 也能存储(c^d)%n解密后的小于n的数据了[luther.gliethttp]
==> rsa->meth->bn_mod_exp(ret,f,rsa->e,rsa->n,ctx, // 实行RSA加密(m^e)%n
        rsa->_method_mod_n); // 其中f在BN_bin2bn(buf,num,f)调用后被填入char buf[]格式数据转换成BIGNUM格式的数据
==> 即: int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, // a为待加密数据块
            const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont)
==> 将包含加密后数据的大数类型变量ret转换为char类型数据
    /* put in leading 0 bytes if the number is less than the
     * length of the modulus */
    j=BN_num_bytes(ret); // 生成的加密数据长度
    i=BN_bn2bin(ret,&(to[num-j]));
    for (k=0; k<(num-i); k++) // 前面没有的添0,因为0^e和0^d计算结果都是0.
        to[k]=0;

其中
to   -- 加密数据待加密之前padding整理输出地址
from -- 待加密数据地址
tlen -- 等于BN_num_bytes(rsa->n);即p*q的乘机n所占用的字节总数,加密后的数据因为(m^e)%n,取余n,
        所以tlen是数据输出的最大长度.
flen -- 从from地址开始的待加密数据字节长度
int RSA_padding_add_PKCS1_type_2(unsigned char *to, int tlen,
         const unsigned char *from, int flen)
{
    int i,j;
    unsigned char *p;

    if (flen > (tlen-11)) // 看来被PKCS1_type_2加密的数据长度必须小于tlen [20100227]
        {
        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_2,RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
        return(0);
        }
    
    p=(unsigned char *)to;
// to[0] = 0;
// to[1] = 2; 标识加密数据的加密方式[luther.gliethttp]
    *(p++)=0;
    *(p++)=2; /* Public Key BT (Block Type) */
// to[2]...to[j]为填入的非0值随机数
    /* pad out with non-zero random data */
    j=tlen-3-flen;

    if (RAND_bytes(p,j) <= 0)
        return(0);
    for (i=0; i        { // 检查to[2]...to[j]之间的数据,如果数值为0,再次为该字节产生一个使用非0值随机数[luther.gliethttp]
        if (*p == '\0')
            do    {
                if (RAND_bytes(p,1) <= 0)
                    return(0);
                } while (*p == '\0');
        p++;
        }
// 向to[j+1]追加一个类似于字符串的结尾0值,这样取数据时,遇到0表示随机数填充结束,下一个字节开始为有效的加密数据[luther.gliethttp]
    *(p++)='\0';

    memcpy(p,from,(unsigned int)flen); // 向to[j+2]...to[tlen-1]拷贝真正的需要加密的有效数据[luther.gliethttp]
    return(1);
}

// 将len长度的char类型数据转换到BIGNUM大数类型变量ret中[luther.gliethttp]
BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret)
{
    unsigned int i,m;
    unsigned int n;
    BN_ULONG l;
    BIGNUM  *bn = NULL;

    if (ret == NULL)
        ret = bn = BN_new();
    if (ret == NULL) return(NULL);
    bn_check_top(ret);
    l=0;
    n=len;
    if (n == 0)
        {
        ret->top=0;
        return(ret);
        }
    i=((n-1)/BN_BYTES)+1; // BN_BYTES为一个大数类型占用的字节数目,len长度数据可以转换成i个BIGNUM大数数据
    m=((n-1)%(BN_BYTES));
    if (bn_wexpand(ret, (int)i) == NULL) // malloc空间
        {
        if (bn) BN_free(bn);
        return NULL;
        }
    ret->top=i;
    ret->neg=0;
    while (n--)
        { // 下面开始以BN_BYTES个字节为1组,合成BIGNUM大数,BIGNUM大数使用大端存储模式,高地址存储低位数据[luther.gliethttp]
        l=(l<<8L)| *(s++);
        if (m-- == 0)
            {
            ret->d[--i]=l; // --i表示从高地址到低地址依次存储BIGNUM大数[luther.gliethttp]
            l=0;
            m=BN_BYTES-1;
            }
        }
    /* need to call this due to clear byte at top if avoiding
     * having the top bit set (-ve number) */
    bn_correct_top(ret);
    return(ret);
}

int BN_bn2bin(const BIGNUM *a, unsigned char *to)
{
    int n,i;
    BN_ULONG l;

    bn_check_top(a);
    n=i=BN_num_bytes(a); // 大数包含的字节数
    while (i--)
        {
        l=a->d[i/BN_BYTES]; // 因为BIGNUM大数使用bigendian大端存储模式,
        // 所以BIGNUM大数的高地址存储的是低位数据,当前i字节对应的BIGNUM大数索引
        *(to++)=(unsigned char)(l>>(8*(i%BN_BYTES)))&0xff;
        // 取出当前BIGNUM大数中的第i%BN_BYTES个字节,存储到char类型buf中
        }
    return(n);
}
阅读(11720) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~