RSA为一个非对称加密算法,基本包含的数据类型为
struct rsa_st {
BIGNUM *n;
BIGNUM *e;
BIGNUM *d;
BIGNUM *p;
BIGNUM *q;
BIGNUM *dmp1;
BIGNUM *dmq1;
BIGNUM *iqmp;
};
typedef struct rsa_st RSA;
下面只对秘钥生成的过程以及各个数值之间的关系进行验证
当我们生成一个对应的RSA结构体时候,其中对应数值之间的关系为
一. 各个结构体元素之间的数学关系
1. p和q为两个不相等的随机生成的质数
2. n为p和q的乘积
3. 计算出来n的欧拉函数φ(n),这个φ(n)虽然没有在结构体里面体现出来但是其实是作为一个核心数据存在的。
4. 随机选择一个整数e,条件是1< e <φ(n),且e与φ(n)互质。
这个在openssl里面一般都使用给定的预定义宏
#define RSA_3 0x3L
#define RSA_F4 0x10001L
5. 计算e对于φ(n)的模反元素d
ed ≡ 1 (modφ(n))
e和d之间的乘积除以φ(n)余1
最终的公钥为n 和e; 私钥为n 和d。
二.使用上述结构加密的过程
1. 加密的过程
me ≡ c (mod n)
m必须是整数(字符串可以取ascii值或unicode值),且m必须小于n。
所谓"加密",就是算出下式的c:
me ≡ c (mod n)
2. 解密过程
cd ≡ m (mod n)
通过这个公式我们可以计算出来对应的m.这样就完成了对应的解密过程
三. 下面使用代码验证上述过程
1.初始化RSA
RSA* constructRSAHandler(int rsaBitLen, unsigned long e) {
RSA *handler;
int ret = 0;
BIGNUM *bNum = NULL;
int dumpIdx = 0;
bNum = BN_new();
ret = BN_set_word(bNum, e);
handler = RSA_new();
if (handler == NULL) {
printf("RSA_new return NULL\n");
return NULL;
}
ret = RSA_generate_key_ex(handler, rsaBitLen, bNum, NULL);
if (ret != 1) {
printf("Generate rsa keypair err\n");
return NULL;
}
RSA_print_fp(stdout, handler, 0);
return handler;
}
上述函数里面
(1)RSA_new 初始化一个RSA结构体。
(2)int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb);
rsa 参数为上面RSA_new的返回值
(3)bits参数上述原理介绍时候那个n的位数
e_value 为上述的e,一般会使用openssl为我们预定义的宏
#define RSA_3 0x3L
#define RSA_F4 0x10001L
(4)callback 回调函数由用户实现,用于干预密钥生成过程中的一些运算,可为空
对应dump出来数据为
modulus:
00:a7:74:95:79:29:13:26:0f:4a:ba:c4:b8:3f:7f:
b4:63:a0:23:6b:18:25:2d:bd:a0:a3:26:60:a8:4f:
65:f6:b6:76:e5:f4:f0:d7:61:69:f8:3d:07:29:77:
5f:95:4c:72:d5:be:f1:4a:3f:ad:e6:59:25:ab:8e:
c2:10:9e:4d:87:18:67:c2:89:c1:96:2d:62:f5:db:
eb:29:a6:0d:b6:80:16:8f:58:09:20:40:66:d2:ad:
07:e9:e6:7d:38:bb:5a:0d:4f:a6:91:84:bb:c4:0e:
14:96:f1:d7:83:62:61:98:b8:a7:f4:e5:c7:3f:bf:
01:c1:de:c9:fe:c3:d9:1d:47
publicExponent: 3 (0x3)
privateExponent:
6f:a3:0e:50:c6:0c:c4:0a:31:d1:d8:7a:d4:ff:cd:
97:c0:17:9c:ba:c3:73:d3:c0:6c:c4:40:70:34:ee:
a4:79:a4:99:4d:f5:e4:eb:9b:fa:d3:5a:1b:a4:ea:
63:88:4c:8e:7f:4b:86:d5:1e:99:90:c3:c7:b4:81:
60:69:89:03:a6:d0:e9:3b:23:c4:cd:13:54:1e:9c:
3c:e7:b1:c2:44:94:0e:22:0e:3a:6a:ef:01:7e:fe:
67:eb:b0:12:52:65:81:85:42:2e:c3:94:86:3f:be:
4d:e6:11:95:c8:f2:e6:1a:7f:74:bd:a6:12:3c:19:
67:a4:36:1e:cd:96:0e:eb
prime1:
00:d3:53:6e:55:9c:12:fd:d1:96:14:e6:11:67:ad:
e1:1d:35:1d:2f:79:0d:0f:fb:bc:26:9a:5d:55:48:
0e:cc:2b:e3:2a:20:1d:b6:85:d9:39:3a:7d:01:b6:
d1:4e:52:24:ab:77:1f:07:08:1e:a5:48:1d:e3:fb:
65:78:10:21:91
prime2:
00:ca:da:f6:5b:6f:db:fb:f4:61:99:1a:bc:e2:d5:
31:fc:03:5c:f5:7a:bb:90:04:94:47:ef:f0:af:ad:
0e:73:95:e7:dd:a3:2d:a8:d7:21:75:3c:a5:17:06:
51:66:a3:1a:e5:71:a6:c2:46:05:bf:93:88:84:7d:
6b:17:67:e5:57
exponent1:
00:8c:e2:49:8e:68:0c:a9:36:64:0d:ee:b6:45:1e:
96:13:78:be:1f:a6:08:b5:52:7d:6f:11:93:8e:30:
09:dd:72:97:71:6a:be:79:ae:90:d0:d1:a8:ab:cf:
36:34:36:c3:1c:fa:14:af:5a:bf:18:da:be:97:fc:
ee:50:0a:c1:0b
exponent2:
00:87:3c:a4:3c:f5:3d:52:a2:eb:bb:67:28:97:38:
cb:fd:57:93:4e:51:d2:60:03:0d:85:4a:a0:75:1e:
09:a2:63:ef:e9:17:73:c5:e4:c0:f8:d3:18:ba:04:
36:44:6c:bc:98:f6:6f:2c:2e:ae:7f:b7:b0:58:53:
9c:ba:45:43:8f
coefficient:
00:82:33:35:32:bd:90:f5:82:1a:35:51:35:ce:46:
da:5a:b5:a9:39:b3:6d:70:66:bd:03:8d:61:37:8e:
13:79:75:e2:93:47:ed:7f:9c:c0:8b:f0:a6:28:55:
ad:46:ec:ba:2b:6d:24:af:c1:22:ed:d4:59:9d:51:
62:f1:26:aa:98
2. p,q,n,e之间的关系
有了RSA结构体就可以验证上面1里面所属的p,q,n,e之间关系
2.1 n=p*q
BN_CTX *ctx = NULL;
BIGNUM *p = NULL, *q = NULL;
BIGNUM *mul = NULL;
int ret = -1;
BIO *out = NULL;
out = BIO_new(BIO_s_file());
ret=BIO_set_fp(out, stdout, BIO_NOCLOSE);
p = handler->p;
q = handler->q;
ctx = BN_CTX_new();
mul = BN_new();
ret = BN_mul(mul, p, q, ctx);
if(ret != 1) {
printf("BN_mul err.\n");
return;
}
BN_print(out, mul);
printf("dump n success\n");
关键函数就是两个大数p和q想乘的结果BN_mul(mul, p, q, ctx);
结果对应出来的dump为
A77495792913260F4ABAC4B83F7FB463A0236B18252DBDA0A32660A84F65F6B676E5F4F0D76169F83D0729775F954C72D5BEF14A3FADE65925AB8EC2109E4D871867C289C1962D62F5DBEB29A60DB680168F5809204066D2AD07E9E67D38BB5A0D4FA69184BBC40E1496F1D783626198B8A7F4E5C73FBF01C1DEC9FEC3D91D47
可以看出来跟第一步中dump出来所有rsa结构体里面的modulus相同。
2.2 ed ≡ 1 (modφ(n))
首先计算φ(n)的值时候可以由于p和q都为质数所以
φ(n) = (p-1)(q-1);
用一下代码段可以计算p-1以及q-1的值
strcpy(d, "1");
ret=BN_hex2bn(&b,d);
ret=BN_sub(psubone, p, b);
同样用BN_mul函数可以计算出来n的欧拉函数结果φ(n).
对应dump结果为
begin dump φ(n)
A77495792913260F4ABAC4B83F7FB463A0236B18252DBDA0A32660A84F65F6B676E5F4F0D76169F83D0729775F954C72D5BEF14A3FADE65925AB8EC2109E4D857A395DD8B5A7339CFE2DEA5B5B8AA366DE15331557A066823E7D9BE1881B7B984247E346255EC95F9D74D91A60AD6C5927BF2F1C791B5A261B76512E34611660
dump φ(n) over
2.3 ed ≡ 1 (modφ(n))
int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
BN_CTX *ctx)
这个函数计算的结果为 num/divisor, dv为相除的结果, num为num%divisor的值。
上面相关的结果都已经算出来这里直接用对应的大数相除函数可以验证对应的结果
e,d乘积除以φ(n)的结果为1.
Dump初上上述函数的num结果可以看到等式成立。
begin dump (e*d)modφ(n)
1
dump (e*d)modφ(n) over
四. 加密和解密使用的相关参数
根据上面解释,组成公钥的额有(n, e)即可,私钥使用(n,d)即可。
下面做以下测试生成RSA并调用对应的RSA_generate_key_ex函数来生成对应的n,e,d,p,q等数据,记为BaseRSA.
另外生成一个空的RSA,将BaseRSA的n和e赋值给这个空的RSA记为PublicPEMRSA.
在生成第二个空的RSA,将BaseRSA的n和d赋值给这个空的RSA记为PrivateKEYRSA.
使用PublicPEMRSA加密对应的数据,然后使用PrivateKEYRSA解密对应数据。
void rsaEncryptSeperate(RSA *BaseRSA) {
RSA* PublicPEMRSA= NULL;
RSA* PrivateKEYRSA= NULL;
int rsaLen = 0;
unsigned char *origData = NULL;
unsigned char encryptedBuffer[4096] = {0};
unsigned char decryptBuffer[4096] = {0};
int len = 0;
PublicPEMRSA= RSA_new();
if (PublicPEMRSA== NULL) {
printf("RSA_new return NULL\n");
goto err;
}
PrivateKEYRSA= RSA_new();
if (PrivateKEYRSA== NULL) {
printf("RSA_new return NULL\n");
goto err;
}
PublicPEMRSA->n = handler->n;
PublicPEMRSA->e = handler->e;
PrivateKEYRSA->n = handler->n;
PrivateKEYRSA->d = handler->d;
PrivateKEYRSA->e = handler->e;
rsaLen = RSA_size(BaseRSA);
printf("RSA_size -> %d\n", rsaLen);
constructOriData(origData, rsaLen);
len = RSA_public_encrypt(rsaLen, origData, encryptedBuffer, PublicPEMRSA, RSA_NO_PADDING);
if(len<=0) {
printf("RSA_private_encrypt err!\n");
goto err;
}
printf("after rsa encrypt len -> %d\n", len);
len = RSA_private_decrypt(rsaLen, encryptedBuffer, decryptBuffer, PrivateKEYRSA, RSA_NO_PADDING);
if(len <= 0) {
printf("RSA_public_decrypt err!\n");
goto err;
}
}
原理性描述参考
http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html