浅析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) |