一:RSA 数学理论基础
1. 互质关系
如果两个正整数,除了1以外,没有其他公因子,我们就称这两个数是互质关系(coprime)。比如,15和32没有公因子,所以它们是互质关系。这说明,不是质数也可以构成互质关系。
2. 欧拉函数
请思考以下问题:
任意给定正整数n,请问在小于等于n的正整数之中,有多少个与n构成互质关系?(比如,在1到8之中,有多少个数与8构成互质关系?)
计算这个值的方法就叫做欧拉函数,以φ(n)表示。在1到8之中,与8形成互质关系的是1、3、5、7,所以 φ(n) = 4。
对于:
因为任意一个大于1的正整数n,都可以写成一系列质数的积。
上述公式其中p1,p2...pr 都是质数,k1,k2...kr表明是幂。
那么最终欧拉函数公式:
其中p1,p2....pr 是n的质数因子
3. 数论的欧拉定理
如果两个正整数a和n互质,则n的欧拉函数 φ(n) 可以让下面的等式成立:
也就是:
pow(a, φ(n) ) % n = 1
a的φ(n) 次幂 对 n 取余数是 恒等于 1
4. 模反元素
如果两个正整数a和n互质,那么一定可以找到整数b,使得 ab-1 被n整除,或者说ab被n除的余数是1。
这时,b就叫做a的"模反元素"。
注意
如果是要整篇文章描述的更清晰,这里应该这样描述比较好:
对于一个整数n(在RSA算法中是两个非常大质数的乘积), 它的φ(n)是N,如果一个正整数a(1 即: ab % N = 1
下面介绍的计算模反元素是对φ(n)计算而不是对n计算,切记!!!!
把上面的a理解成e(encrypt,加密),b理解成d(decrypt,解密), y是除法的结果
ed % n = 1
ed = yn + 1
这是一个二元一次方程
根据3和4 的公式 可以得知:
b的其中之一 就是:
a的 φ(n)-1 次方,即 b = pow(a, (φ(n)-1))
公钥与私钥
根据公式3:e 的 φ(n)次幂 对 n 取余 等于1,即 pow(e, φ(n)) % n = 1
根据公式4:ed 对 n 取余 等于1,即 ed % n = 1
公钥: n和e组成的字符串,e是跟φ(n)互质
私钥: n和d组成的字符串,d是模反元素
对于明文m,用公钥(n,e)加密 计算密文c
c = pow (m, e) % n
对于密文c,用私钥(n,d)解密 计算明文m
m = pow(c, d) % n
二:RSA 算法简单验证
1. 随机选择两个不相等的质数p和q。
例如选择了61和53。(实际应用中,这两个质数越大,就越难破解。)
int p = 61;
int q = 53;
2. 计算p和q的乘积得到n
int n = p * q;
3. 计算n的欧拉函数φ(n)
根据公式:
φ(n) = (p-1)(q-1)
// 数论中的欧拉函数证明过程非常复杂,其中之一的结论是:
// 对n求欧拉函数,n = p * q, 且p和q都是质数
- (int)Euler_functionWithN:(int)n p:(int)p q:(int)q {
return (p - 1) * (q - 1);
}
4. 随机选择一个整数e,条件是1< e < φ(n),且e与φ(n) 互质
- (int)calculate_random_valueWithEulerFunctionResult:(int)eulerFunctionResult {
NSMutableArray *ary = [NSMutableArray new];
BOOL find17 = NO;
// 加一个i < 100 控制一下列出所有的数据了
for (int i = 2; i < eulerFunctionResult && i < 100; i++) {
if (eulerFunctionResult % i != 0) {
[ary addObject:@(i)];
if (!find17 && i == 17) {
find17 = YES;
}
}
}
NSLog(@"find17:%@", find17 ? @"YES" : @"NO");
NSLog(@"ary:%@", [ary componentsJoinedByString:@","]);
return 17;
}
其中的输出结果:
find17:YES
ary:7,9,11,14,17,18,19,21,22,23,25,27,28,29,31,32,33,34,35,36,37,38,41,42,43,44,45,46,47,49,50,51,53,54,55,56,57,58,59,61,62,63,64,66,67,68,69,70,71,72,73,74,75,76,77,79,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99
17 只是众多结果之一
5. 计算e对于φ(n)的模反元素d
// 计算模反元素
- (int)calculate_Mofan_elementWith_eulerFunctionResult:(int)eulerFunctionResult andE:(int)e {
int x = 0; int y = 0;
// 模反元素计算公式: (e * x) + eulerFunctionResult * y = 1;
// 要保证x是正数,那么y就必须是负数,所以从y负一开始
NSMutableArray *ary = [NSMutableArray new];
int d = 0;
int yMax = -200;
for (y = -1; y > yMax; y--) {
int tmp = 1 - y * eulerFunctionResult;
if (tmp % e == 0) {
x = tmp / e;
[ary addObject:@(x)];
if (x == 2753) {
d = 2753;
}
}
}
NSLog(@"possibility mofan:%@", ary);
return d;
}
输出结果(y在-1之-200之间):
possibility mofan:(
2753,
5873,
8993,
12113,
15233,
18353,
21473,
24593,
27713,
30833,
33953
)
6. 对明文m使用公钥(n,e)加密得到密文c
// 计算加密
// c = pow(m, e) % n
// 参数: m: 明文,e:公钥的e,n:公钥的n
// 返回值 c: 密文
// 数据太大,pow(m, e)会溢出,所以采取如下的算法
- (int)calculate_encryptWithM:(int)m n:(int)n e:(int)e {
int c = m;
for (int i = 1; i < e; i ++) {
c = c * m;
if (c > n) {
c = c % n;
}
}
return c;
}
7. 对密码c使用私钥(n,d)得到明文m
// 计算解密
// decrypt = pow(c, d) % n
// 参数: c: 密文,e:私钥的d,n:私钥的n(跟公钥的n是一样的)
// 返回值 m: 明文
- (int)calculate_decryptWithC:(int)c n:(int)n d:(int)d {
int m = c;
for (int i = 1; i < d; i ++) {
m = m * c;
if (m > n) {
m = m % n;
}
}
return m;
}
8. 整个测试demo
- (void)test_encrypt_decrypt_exampleWithM:(int)m n:(int)n publicE:(int)e privateD:(int)d {
// 密文
int c = [self calculate_encryptWithM:m n:n e:e];
NSLog(@"m:%d, c:%d", m, c);
// 解密后的密文
int newM = [self calculate_decryptWithC:c n:n d:d];
NSLog(@"m:%d, newM:%d", m, newM);
}
- (void)test {
// 第一步,随机选择两个不相等的质数p和q
int p = 61;
int q = 53;
// 第二步,计算p和q的乘积得到n
int n = p * q;
// 第三步,计算n的欧拉函数得到eulerFunctionResult
int eulerFunctionResult = [self Euler_functionWithN:n p:p q:q];
// 第四步,随机选择一个整数e,1 < e < eulerFunctionResult, 且e与eulerFunctionResult互质
int e = [self calculate_random_valueWithEulerFunctionResult:eulerFunctionResult];
// 第五步,计算e与eulerFunctionResult的模反元素d
int d = [self calculate_Mofan_elementWith_eulerFunctionResult:eulerFunctionResult andE:e];
NSLog(@"p:%d, q:%d, n:%d, eulerFunctionResult:%d, e:%d, d:%d", p, q, n, eulerFunctionResult, e, d);
NSString *publicKey = [NSString stringWithFormat:@"%d-%d", n, e];
NSString *privateKey = [NSString stringWithFormat:@"%d-%d", n, d];
NSLog(@"publicKey:%@, privateKey:%@", publicKey, privateKey);
// 明文 m
int m = 65;
[self test_encrypt_decrypt_exampleWithM:m n:n publicE:e privateD:d];
}
以上就是RSA算法的总结。
本文参考:
RSA算法原理(一)
RSA算法原理(二)