需要的前置知识: 欧拉函数,欧拉定理,费马小定理,同余式乘法性质,互质数判断
1977年,美国的罗纳德·李维斯特( R o n R i v e s t Ron\ Rivest Ron Rivest)、阿迪·萨莫尔( A d i S h a m i r Adi\ Shamir Adi Shamir)和伦纳德·阿德曼( L e o n a r d A d l e m a n Leonard\ Adleman Leonard Adleman)三人共同提出了著名的非对称加密算法 —— R S A RSA RSA,这是目前安全性最高的加密算法之一。
R S A RSA RSA 是一种建立在大数因子分解基础上的算法,算法明文以分组为单位进行加密,每个分组的二进制值均小于 n n n,即分组大小必须小于或等于 l o g 2 n log_2^n log2n 位。
设:明文 M M M,密文 C C C
加密: C = M e m o d n C = M^e\ mod\ n C=Me mod n
解密: M = C d m o d n M = C^d\ mod\ n M=Cd mod n
关于上述流程的几个关系的补充
若想证明 R S A RSA RSA 加密算法的正确性,只需证明解密得到的结果与明文相同
M = C d m o d n = ( M e m o d n ) d m o d n = M e d m o d n M = C^d\ mod\ n = (M^e\ mod\ n)^d\ mod\ n = M^{ed}\ mod\ n M=Cd mod n=(Me mod n)d mod n=Med mod n
也就是说只需要证明 M e d ≡ M ( m o d n ) M^{ed} \equiv M \ (mod\ n) Med≡M (mod n) 成立即可
e ∗ d m o d ϕ ( n ) = 1 \ \ \ \ \ e*d\ \ mod\ \ \phi(n) = 1 e∗d mod ϕ(n)=1
⇒ e ∗ d = k ∗ ϕ ( n ) + 1 \Rightarrow e*d\ = \ k * \phi(n) + 1 ⇒e∗d = k∗ϕ(n)+1
带入原式 M k ∗ ϕ ( n ) + 1 ≡ M ( m o d n ) \ \ M^{k * \phi(n) + 1} \equiv M \ (mod\ n) Mk∗ϕ(n)+1≡M (mod n)
分情况讨论
M , n M, n M,n 互质
根据欧拉定理有 M ϕ ( n ) ≡ 1 ( m o d n ) M^{\phi(n)} \equiv 1 \ (mod\ n) Mϕ(n)≡1 (mod n)
根据同余式乘法性质可得 M k ∗ ϕ ( n ) ≡ 1 ( m o d n ) M^{k * \phi(n)} \equiv 1 \ (mod\ n) Mk∗ϕ(n)≡1 (mod n)
又有 M ≡ M ( m o d n ) M \equiv M \ (mod\ n) M≡M (mod n)
⇒ M k ∗ ϕ ( n ) + 1 ≡ M ( m o d n ) \Rightarrow M^{k * \phi(n) + 1} \equiv M \ (mod\ n) ⇒Mk∗ϕ(n)+1≡M (mod n)
M , n M, n M,n 不互质
∵ M , n 不 互 质 \because M,n 不互质 ∵M,n不互质
且 n = p ∗ q \ \ 且\ n = p*q 且 n=p∗q
且 p , q 均 为 质 数 \ \ 且\ p,q均为质数 且 p,q均为质数
且 M < n \ \ 且\ M < n 且 M<n
∴ M = k ∗ p 或 者 M = k ∗ q \therefore M = k*p\ 或者\ M = k*q ∴M=k∗p 或者 M=k∗q (就是说 M M M 只能是 p p p 的倍数或者 q q q 的倍数, M M M 不能是 p ∗ q p*q p∗q 的倍数是因为 M < n M < n M<n)
令 M = k ∗ p ( 1 < k < q ) M = k*p\ (1 < k < q) M=k∗p (1<k<q)
∵ k < q , 且 q 是 质 数 \because k < q,且\ q\ 是质数 ∵k<q,且 q 是质数
∴ k , q 互 质 \therefore k, q\ 互质 ∴k,q 互质(互质数判断)
根据费马小定理: ( k ∗ p ) q − 1 ≡ 1 ( m o d q ) (k*p)^{q-1} \equiv 1\ (mod\ q) (k∗p)q−1≡1 (mod q) (费马小定理这个形式的条件是 k ∗ p k*p k∗p 不能整除 q q q,所以需要 k , q 互 质 k,q\ 互质 k,q 互质)
⇒ ( k ∗ p ) ( q − 1 ) ∗ ( p − 1 ) ∗ k ∗ ( k ∗ p ) ≡ ( k ∗ p ) ( m o d q ) \Rightarrow (k*p)^{(q-1)*(p-1)*k}*(k*p) \equiv (k*p)\ (mod\ q) ⇒(k∗p)(q−1)∗(p−1)∗k∗(k∗p)≡(k∗p) (mod q) (同余式乘法性质)
∵ ϕ ( n ) = ( p − 1 ) ∗ ( q − 1 ) , e ∗ d = k ∗ ϕ ( n ) + 1 \because \phi(n)\ = (p-1)*(q-1),\ e*d\ = \ k * \phi(n) + 1 ∵ϕ(n) =(p−1)∗(q−1), e∗d = k∗ϕ(n)+1
∴ ( k ∗ p ) e d ≡ ( k ∗ p ) ( m o d q ) \therefore (k*p)^{ed} \equiv (k*p)\ (mod\ q) ∴(k∗p)ed≡(k∗p) (mod q)
即 ⇒ ( k ∗ p ) e d = t ∗ q + k ∗ p \Rightarrow (k*p)^{ed} = t*q + k*p ⇒(k∗p)ed=t∗q+k∗p
将它的形式转换一下 ⇒ ( k ∗ p ) ∗ ( ( k ∗ p ) e d − 1 − 1 ) = t ∗ q \Rightarrow (k*p)*((k*p)^{ed-1}-1) = t*q ⇒(k∗p)∗((k∗p)ed−1−1)=t∗q
可见 t ∗ q t*q t∗q 能整除 k ∗ p k*p k∗p,又 q q q 是质数,所以 t t t 能整除 p p p
令 t = t ‘ ∗ p t = t^`*p t=t‘∗p
代回原式 ( k ∗ p ) e d = t ∗ q + k ∗ p (k*p)^{ed} = t*q + k*p (k∗p)ed=t∗q+k∗p 得: ⇒ ( k ∗ p ) e d = t ‘ ∗ p ∗ q + k ∗ p \Rightarrow(k*p)^{ed} = t^`*p*q + k*p ⇒(k∗p)ed=t‘∗p∗q+k∗p
∵ M = k ∗ p , n = p ∗ q \because M = k*p,n = p*q ∵M=k∗p,n=p∗q
∴ M e d = t ‘ ∗ n + M \therefore M^{ed} = t^`*n + M ∴Med=t‘∗n+M
即 ⇒ M e d ≡ M ( m o d n ) \Rightarrow M^{ed} \equiv M \ (mod\ n) ⇒Med≡M (mod n)
综上 ①,②,等式得证
#include
using namespace std;
// RSA算法所需参数
typedef struct RSA_PARAM_Tag {
unsigned __int64 p, q; // 两个素数,不参与加密解密运算
unsigned __int64 f; // f = (p-1)*(q-1),不参与加密解密运算
unsigned __int64 n, e; // 公匙PU,n = p*q,gcd(e,f) = 1
unsigned __int64 d; // 私匙PR,e*d = 1 (mod f),gcd(n,d) = 1
unsigned __int64 s; // 块长,满足^s<=n的最大的s,即log2(n)
} RSA_PARAM; // 小素数表
const static long g_PrimeTable[] = { 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 };
const static long g_PrimeCount = sizeof(g_PrimeTable) / sizeof(long);
const unsigned __int64 multiplier = 12747293821;
const unsigned __int64 adder = 1343545677842234541; // 随机数类
class RandNumber {
private:
unsigned __int64 randSeed;
public:
RandNumber(unsigned __int64 s=0);
unsigned __int64 Random(unsigned __int64 n);
};
RandNumber::RandNumber(unsigned __int64 s) {
if(!s) {
randSeed = (unsigned __int64)time(NULL);
}
else {
randSeed = s;
}
}
unsigned __int64 RandNumber::Random(unsigned __int64 n) {
randSeed = multiplier * randSeed + adder;
return randSeed % n;
}
static RandNumber g_Rnd; /* 模乘运算,返回值x=a*b mod n */
inline unsigned __int64 MulMod(unsigned __int64 a, unsigned __int64 b, unsigned __int64 n) {
return a * b % n;
}
/* 模幂运算,返回值 x = base^pow mod n */
unsigned __int64 PowMod(unsigned __int64 &base, unsigned __int64 &pow, unsigned __int64 &n) {
unsigned __int64 a = base, b = pow, c = 1;
while(b) {
while(!(b & 1)) {
b >>= 1; //a=a * a % n; //函数看起来可以处理位的整数,但由于这里a*a在a>=2^32时已经造成了溢出,因此实际处理范围没有位
a=MulMod(a, a, n);
}
b--; //c=a * c % n; //这里也会溢出,若把位整数拆为两个位整数不知是否可以解决这个问题。
c=MulMod(a, c, n);
}
return c;
}
/* Rabin-Miller素数测试,通过测试返回,否则返回。n是待测素数。注意:通过测试并不一定就是素数,非素数通过测试的概率是/4 */
long RabinMillerKnl(unsigned __int64 &n) {
unsigned __int64 b, m, j, v, i;
m = n-1;
j=0;
// 0、先计算出m、j,使得n-1=m*2^j,其中m是正奇数,j是非负整数
while(!(m & 1)) {
++j;
m>>=1;
}
// 1、随机取一个b,<=b
b = 2 + g_Rnd.Random(n - 3);
// 2、计算v=b^m mod n
v = PowMod(b, m, n);
// 3、如果v==1,通过测试
if(v == 1) {
return 1;
}
// 4、令i=1
i=1;
b=2;
// 5、如果v=n-1,通过测试
while(v != n - 1) {
// 6、如果i==l,非素数,结束
if(i == j) {
return 0;
}
// 7、v=v^2 mod n,i=i+1
v = PowMod(v, b, n);
++i;
// 8、循环到
}
return 1;
}
/* Rabin-Miller素数测试,循环调用核心loop次全部通过返回,否则返回 */
long RabinMiller(unsigned __int64 &n, long loop) {
//先用小素数筛选一次,提高效率
for(long i=0; i < g_PrimeCount; i++) {
if(n % g_PrimeTable[i] == 0) {
return 0;
}
}
//循环调用Rabin-Miller测试loop次,使得非素数通过测试的概率降为(1/4)^loop
for(long i=0; i < loop; i++) {
if(!RabinMillerKnl(n)) {
return 0;
}
}
return 1;
}
/* 随机生成一个bits位(二进制位)的素数,最多位*/
unsigned __int64 RandomPrime(char bits) {
unsigned __int64 base;
do {
base = (unsigned long)1 << (bits - 1); //保证最高位是
base += g_Rnd.Random(base); //再加上一个随机数
base |= 1; //保证最低位是,即保证是奇数
}
while(!RabinMiller(base, 30)); //进行拉宾-米勒测试次
return base; //全部通过认为是素数
}
/*欧几里得法求最大公约数*/
unsigned __int64 EuclidGcd(unsigned __int64 &p, unsigned __int64 &q) {
unsigned __int64 a = p > q ? p : q;
unsigned __int64 b = p < q ? p : q;
unsigned __int64 t;
if(p == q) {
return p; //两数相等,最大公约数就是本身
}
else {
//辗转相除法,gcd(a,b)=gcd(b,a-qb)
while(b) {
a = a % b;
t=a;
a=b;
b=t;
}
return a;
}
}
/* Stein法求最大公约数 */
unsigned __int64 SteinGcd(unsigned __int64 &p, unsigned __int64 &q) {
unsigned __int64 a = p > q ? p : q;
unsigned __int64 b = p < q ? p : q;
unsigned __int64 t, r=1;
if(p == q) {
return p; //两数相等,最大公约数就是本身
}
else {
while((!(a & 1)) && (!(b & 1))) {
r<<=1; //a、b均为偶数时,gcd(a,b)=2*gcd(a/2,b/2)
a>>=1;
b>>=1;
}
if(!(a & 1)){
t=a; //如果a为偶数,交换a,b
a=b;
b=t;
}
do {
while(!(b & 1)) {
b>>=1; //b为偶数,a为奇数时,gcd(b,a)=gcd(b/2,a)
}
if(b < a) {
t=a; //如果b小于a,交换a,b
a=b;
b=t;
}
b = (b - a) >> 1; //b、a都是奇数,gcd(b,a)=gcd((b-a)/2,a)
} while(b);
return r * a;
}
}
/* 已知a、b,求x,满足a*x =1 (mod b)相当于求解a*x-b*y=1的最小整数解 */
unsigned __int64 Euclid(unsigned __int64 &a, unsigned __int64 &b) {
unsigned __int64 m, e, i, j, x, y;
long xx, yy;
m = b;
e = a;
x = 0;
y = 1;
xx=1;
yy=1;
while(e) {
i=m / e;
j=m % e;
m=e;
e=j;
j=y;
y*=i;
if(xx == yy) {
if(x > y) {
y=x - y;
}
else {
y -= x;
yy = 0;
}
}
else {
y += x;
xx = 1 - xx;
yy = 1 - yy;
}
x = j;
}
if(xx == 0) {
x = b - x;
}
return x;
}
/* 随机产生一个RSA加密参数*/
RSA_PARAM RsaGetParam(void) {
RSA_PARAM Rsa={ 0 };
unsigned __int64 t;
Rsa.p=RandomPrime(16); //随机生成两个素数
Rsa.q=RandomPrime(16);
Rsa.n=Rsa.p * Rsa.q;
Rsa.f=(Rsa.p - 1) * (Rsa.q - 1);
do {
Rsa.e=g_Rnd.Random(65536); //小于^16,=2^16
Rsa.e|=1; //保证最低位是,即保证是奇数,因f一定是偶数,要互素,只能是奇数
} while(SteinGcd(Rsa.e, Rsa.f) != 1);
Rsa.d=Euclid(Rsa.e, Rsa.f);
Rsa.s=0; t=Rsa.n >> 1;
while(t) {
Rsa.s++; //s=log2(n)
t>>=1;
}
return Rsa;
}
/* 拉宾-米勒测试 */
void TestRM(void) {
unsigned long k=0;
cout << " - Rabin-Miller prime check.\n" << endl;
for(unsigned __int64 i = 4197900001ULL; i < 4198000000ULL; i+=2) {
if(RabinMiller(i, 30)) {
k++;
cout << i << endl;
}
}
cout << "Total: " << k << endl;
}
/* RSA加密解密 */
void TestRSA(void) {
RSA_PARAM r;
char pSrc[]="Hello RSA!";
const unsigned long n=sizeof(pSrc);
unsigned char *q, pDec[n];
unsigned __int64 pEnc[n];
r = RsaGetParam();
cout << "p=" << r.p << endl;
cout << "q=" << r.q << endl;
cout << "f=(p-1)*(q-1)=" << r.f << endl;
cout << "n=p*q=" << r.n << endl;
cout << "e=" << r.e << endl;
cout << "d=" << r.d << endl;
cout << "s=" << r.s << endl;
cout << "Source:" << pSrc << endl;
q= (unsigned char *)pSrc;
cout << "Encode:";
for(unsigned long i=0; i < n; i++) {
unsigned __int64 temp = (unsigned __int64)q[i];
pEnc[i]=PowMod(temp, r.e, r.n);
cout << hex << pEnc[i] << " ";
}
cout << endl;
cout << "Decode:";
for(unsigned long i=0; i < n; i++) {
pDec[i]=PowMod(pEnc[i], r.d, r.n);
cout << hex << (unsigned long)pDec[i] << " ";
}
cout << endl;
cout << (char *)pDec << endl;
}
int main(void) {
TestRSA();
return 0;
}
王晓峰老师《信息安全技术2018》
RSA算法证明-RSA算法证明参考资料
RSA算法原理-私钥解密的证明
RSA的证明
RSA加密算法中解密步骤的证明
RSA算法基础详解
合天网安实验室 RSA实验