【密码学】RSA
下一个问题是容易想到的,“这能用普通的加密技术来做吗?我们能产生一个安全的加密信息,该信息不需要预先交换密钥就能被授权的接收方解读吗?”
0x00 RSA 介绍
在此可以看到,非对称加密是通过两个密钥对(公钥-私钥)来实现对数据的加密和解密的。公钥用于加密,私钥用于解密。对于非对称的加密和解密为什么可以使用不同的密钥来进行,这些都是数学上的问题了。不同的非对称加密算法也会应用到不同的数学知识。上面也对RSA中使用的数学问题做了一个小小的介绍。现在就来看看RSA算法是怎么来对数据进行加密的吧,如下是一幅RSA加密算法流程及加密过程图。
RSA算法基于的原理,基本上来说,加密和解密数据围绕着模幂运算
0x01 产生随机素数
1.1 随机数生成
rand( ) 函数用于生成一个 0~32767 (即一个15bit数);
srand( ) 函数用于为rand( ) 函数指定种子( 若未指定则默认为srand(1) );
通常使用时间作为随机数种子,但由于本程序执行时间过快(在1秒内),导致时间种子不变,使得产生的随机数相等,故为其乘上随机数rand() ;
// 4~8bit
ll randtonum8()
{
srand((unsigned)time(NULL)*rand());
ll randnum=(rand()&0xF)+1;
randnum <<= 4;
return randnum+(rand()&0xF);
}
1.2 素数检验(Miller-Rabin概率检测法)
ll Quick_Multiply(ll a,ll b,ll c) //快速积
{
ll ans=0,res=a;
while(b){
if(b&1)
ans=(ans+res)%c;
res=(res+res)%c;
b>>=1;
}
return ans;
}
int maxhight(ll val) // 求最高位数
{
int i=0;
while(val){
i++;
val = val>>1;
}
return i;
}
// 对上文伪代码的翻译
bool Miller_Rabin(ll n) //判断素数
{
int prime[10]={2,3,5,7,11,13,17,19,23,29}; // 选10个不同的a,概率至少为1-2^(-10)
if(!(n&1)) return false; //如果x是偶数或者是0,1,那它不是素数
int maxh=maxhight(n-1);
ll tmp=0x01;
tmp<<=(maxh-1); // b的最高位
for(int i=0;i<10;i++){
ll d=1;
ll x;
ll b=n-1;
while(tmp){
x=d;
d=Quick_Multiply(d,d,n);
if(d==1 && x!=1 && x!=n-1) return false;
if(b&tmp) d=Quick_Multiply(d,prime[i],n);
tmp>>=1; // 从高位到低位取出b的每一位
}
if(d!=1) return false;
}
return true;
}
0x02 快速幂
// 没什么好说的
ll Quick_Power(ll a,ll b,ll c) //快速幂
{
ll ans=1,res=a;
while(b)
{
if(b&1)
ans=Quick_Multiply(ans,res,c);
res=Quick_Multiply(res,res,c);
b>>=1;
}
return ans;
}
0x03 求最大公因数
// 辗转相除法
ll gcd(ll a,ll b)
{
ll mod=a%b;
while(mod){
a=b;
b=mod;
mod=a%b;
}
return b;
}
附代码
/*
_/_/_/ _/_/_/ _/_/
_/ _/ _/ _/ _/
_/_/_/ _/_/ _/_/_/_/
_/ _/ _/ _/ _/
_/ _/ _/_/_/ _/ _/
*/
#include <iostream>
#include <string>
#include <cstdlib>
#include <stdio.h>
#include <time.h>
#define ll unsigned long long int
using namespace std;
ll Quick_Multiply(ll a,ll b,ll c) //快速积
{
ll ans=0,res=a;
while(b)
{
if(b&1)
ans=(ans+res)%c;
res=(res+res)%c;
b>>=1;
}
return ans;
}
ll Quick_Power(ll a,ll b,ll c) //快速幂
{
ll ans=1,res=a;
while(b)
{
if(b&1)
ans=Quick_Multiply(ans,res,c);
res=Quick_Multiply(res,res,c);
b>>=1;
}
return ans;
}
int maxhight(ll val) // 求最高位数
{
int i=0;
while(val)
{
i++;
val = val>>1;
}
return i;
}
bool Miller_Rabin(ll n) //判断素数
{
int prime[10]={2,3,5,7,11,13,17,19,23,29};
if(!(n&1)) return false; //如果x是偶数或者是0,1,那它不是素数
int maxh=maxhight(n-1);
ll tmp=0x01;
tmp<<=(maxh-1);
for(int i=0;i<10;i++){
ll d=1;
ll x;
ll b=n-1;
while(tmp){
x=d;
d=Quick_Multiply(d,d,n);
if(d==1 && x!=1 && x!=n-1) return false;
if(b&tmp) d=Quick_Multiply(d,prime[i],n);
tmp>>=1;
}
if(d!=1) return false;
}
return true;
}
ll randtonum8()
{
srand((unsigned)time(NULL)*rand());
ll randnum=(rand()&0xF)+1;
randnum <<= 4;
return randnum+(rand()&0xF);
}
ll toprime()
{
while(1){
ll randnum=randtonum8();
if( Miller_Rabin(randnum) ) return randnum;
}
}
ll gcd(ll a,ll b)
{
ll mod=a%b;
while(mod){
a=b;
b=mod;
mod=a%b;
}
return b;
}
void rsa2key(ll key[3])
{
ll p,q,E,D,N,L;
while(1){
p=toprime();
q=toprime();
printf("p: %d, q: %d\n",p,q);
N=p*q;
L=(p-1)*(q-1);
while(1){
E=rand()%L;
if(gcd(L,E)==1) break;
}
while(1){
D=rand()%L;
if(E*D%L==1) break;
}
if(E!=1 && D!=1) break;
}
key[0]=E;
key[1]=N;
key[2]=D;
}
int main()
{
ll key[3];
rsa2key(key);
printf("密钥:0x%X 0x%X 0x%X\n",key[0],key[1],key[2]);
ll plain=randtonum8();
printf("明文: 0x%X\n",plain);
ll encrypt=Quick_Power(plain,key[0],key[1]);
printf("密文: 0x%X\n",encrypt);
ll decrypt=Quick_Power(encrypt,key[2],key[1]);
printf("解密文: 0x%X\n",decrypt);
return 0;
}
参考文章: