经典加密算法的实现与破解&大素数生成算法

0x00 信息系统安全实验报告

实验(一):经典加密算法的实现与破解

1、 实现凯撒加密、暴力破解凯撒加密
2、 选取k值,编译凯撒加密算法
3、 编写算法尝试暴力破解凯撒加密

实验(二):大素数生成算法,不同素数生成算法优劣

1、 使用费马小定理素数判定法生成大素数
2、 使用米勒拉宾素数判定算法生成大素数
3、 总结出两种算法特点

0x01 经典加密算法的实现与破解

一、实现凯撒加密

在密码学中,恺撒密码(英语:Caesar cipher),或称恺撒加密、恺撒变换、变换加密,是一种最简单且最广为人知的加密技术。它是一种替换加密的技术,明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。例如,当偏移量是3的时候,所有的字母A将被替换成D,B变成E,以此类推。这个加密方法是以罗马共和时期恺撒的名字命名的,当年恺撒曾用此方法与其将军们进行联系。

Encrypt:

def encrypt():
    global result
    for word in message:
        if word in dic:
            num = dic.find(word)
            offset = (num + key) % 26
            word = dic[offset]
        result = result + word

Decrypt:

def decrypt():
    global result
    for word in message:
        if word in dic:
            num = dic.find(word)
            offset = num - key
            if offset < 0:
                offset = offset + 26
            word = dic[offset]
        result = result + word

The_fu11_scr1pt:

dic = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
result = ''

message = input('Please input the message:')
mode = input('Please input the mode:')
key = input('Please input the key:')
key = int(key)

def encrypt():
    global result
    for word in message:
        if word in dic:
            num = dic.find(word)
            offset = (num + key) % 26
            word = dic[offset]
        result = result + word

def decrypt():
    global result
    for word in message:
        if word in dic:
            num = dic.find(word)
            offset = num - key
            if offset < 0:
                offset = offset + 26
            word = dic[offset]
        result = result + word
            
def main():
    if mode == 'encrypt':
        encrypt()
    if mode == 'decrypt':
        decrypt()
    print(result)

if __name__ == '__main__':
    main()

运行结果如下:
在这里插入图片描述

笔者这里写的较为简单,仅考虑了大写字母,如过想要涵盖小写字母甚至特殊字符的话,可以使用python自带的string模块,或者根据ascii进行编写。

print [chr(i) for i in range(65,91)]    #所有大写字母
print [chr(i) for i in range(97,123)]   #所有小写字母
print [chr(i) for i in range(48,58)]    #所有数字

在这里插入图片描述

import string                #导入string这个模块
print string.digits          #输出包含数字0~9的字符串
print string.letters         #包含所有字母(大写或小写)的字符串
print string.lowercase       #包含所有小写字母的字符串
print string.uppercase       #包含所有大写字母的字符串
print string.punctuation     #包含所有标点的字符串
print string.ascii_letters   #与string.letters一样

二、暴力破解凯撒加密

dic = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

message = input('Please input the message:')

def decrypt(key):
    global result
    result = ''
    for word in message:
        if word in dic:
            num = dic.find(word)
            offset = num - key
            if offset < 0:
                offset = offset + 26
            word = dic[offset]
        result = result + word

def main():
	for key in range(1,27):
	    decrypt(key)
	    print('key:' + str(key) + '\t result:' + result)

if __name__ == '__main__':
	main()

运行结果如下:
在这里插入图片描述

0x02 大素数生成算法

一、使用费马小定理素数判定法生成大素数

费马小定理(Fermat’s little theorem)是数论中的一个重要定理,在1636年提出。如果p是一个质数,而整数a不是p的倍数,则有 a^(p-1) ≡ 1 (mod p)。

由上述公式得,p = a^(p-1) * p + 1。我们令 a = p-1 以取得较大的p值,算法实现如下:

# include<iostream>
# include<math.h>
using namespace std;

int main()
{
	long long a,t,p;
	cout<<"Please enter an integer:";
	cin>>p;
	a = p-1;
	t = pow(a,a);
	p = t*p + 1;
	//cout<<"p = "<<p<<endl;
	cout<<"The large prime number is:"<<p<<endl;
}

运行结果如下:
在这里插入图片描述
但当结果过于大以至于超出了long long的范围时,我们就必须要采用其他方法来实现运算了。比如用数组或字符串来表示数值,然后再构造函数从而实现大数的运算。
在这里插入图片描述
在这里插入图片描述
C++大整数运算的实现可以参考以下文章:

https://www.cnblogs.com/yilis/p/10680176.html
https://blog.csdn.net/Ring_k/article/details/80615561
https://www.cnblogs.com/youngforever/articles/3262043.html

二、使用米勒-拉宾素数判定法生成大素数

p是质数一定满足费马小定理,但满足费马小定理的数并一定是质数。有些数虽然满足费马小定理但并不是质数,他们叫做伪质数(Carmichael),伪质数的个数是无穷的。所以说如果我们用费马小定理来生成大素数,是会一定几率出错的。那么这个出错的概率是多大呢?在一定范围内又有多少个数是伪素数呢?这个和 a 的取值有关。当 a = 2 时,前十亿个正整数中能满足费马小定理且不是素数的数有5597个,也就是说出错的概率是0.011%。虽然它的错误率不高,但是无法否认的是,仍存在一定数量的伪素数是费马小定理无法检测出来的。因此我们需要一个方法来尽可能的筛查出这些伪素数,这也就是米勒拉宾算法的核心部分二次探测。

在这里插入图片描述
因此,如果我们要判断 p 是否为素数,可以根据二次探测定理遍历 x 的值(0<x<p),计算 x^2 ≡ 1 (mod p) 的解是否为 x = 1 和 x = p-1(平凡平方根),即当且仅当 x = 1 或 x = p-1 时,x^2 ≡ 1 (mod p) 成立。但是当 p 的值过于大时,遍历 x 就显得不切实际,米勒拉宾算法就此提供了一个快速且相对准确的方法。

虽然我们遍历 x 让它 mod p 的结果有很多种,但我们需要的仅是那些能使 x^2 ≡ 1 (mod p) 成立的 x。那我们反过来,把所有能使 x^2 ≡ 1 (mod p) 成立的 x 取出来,看他们是否等于 p - 1 或 1 即可。不过如何不经过计算快速找出这些能使等式成立的 x 呢?我们再看下刚才的费马素性检测。

所有的质数都是奇数,任何一个偶数都可以写成 2^s * t 的形式 ,比如 6 = 2^1 * 3

a^(p-1) ≡ 1 (mod p) => a^(2^s * t) ≡ 1 (mod p) => (a^t)^(2^s) ≡ 1 (mod p),令 a^t = k

(a^t)^(2^s) ≡ 1 (mod p) => k^(2^s) ≡ 1 (mod p) => (k * k * …… * k)^2 ≡ 1 (mod p) => x^2 ≡ 1 (mod p)

综上,遍历 x 就相当于遍历 k,遍历 k 就相当于遍历 a( t 为可计算的常数,计算方法见下文)。米勒拉宾算法其实就是随机取一定数量的不同的 a,从而得到不同的 k ,再对 k 不断地平方进行二次探测(进行 s 次),判断是否等于 1 或 p-1。多尝试几个 k 即多尝试几个a,这个算法的错误概率就可以降低到忽略不计。

t 的计算方法:

以 72 为例,72 = 1001000 = 8 * 9 = 2^3 * 9,1001000 中最低位起不间断得 0 的个数为3,故 t = 3。

又如 28 = 11100 = 4 * 7 = 2^2 * 7,t = 2。

快速积:

3 * 7 => 3 * (111) => 3 * (2^0 + 2^1 +2^2) => 3 * (1 + 2 + 4)

令 res=3,res = res + res = 3 * 2 = 6 => res = res + res = 3 * 4 = 12……

long long Quick_Multiply(int a,int b,int c) 
{
    long long ans=0,res=a;
    while(b)
    {
        if(b&1) //低位是否为1
        	ans=(ans+res)%c;
        res=(res+res)%c;
        b>>=1; //左移一位,即去除最低位
    }
    return ans;
}

快速幂:

3^5 => 3^(101) => 3^(2^0 + 2^2) => 3^(1 + 4) => 3^1 * 3^4

令 res = 3,res = res * res = 9 (第二位为0,故9不参与运算)=> res = res * res = 81 = 3^4……

long long Quick_Power(int a,int b,int c)
{
    int 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;
}

米勒-拉宾素性检验:

bool Miller_Rabin(long long x)
{
    long long i,j,k;
    long long s=0,t=x-1;
    //cout<<t<<endl;
    if(x==2)  return true;
    if(x<2||!(x&1))  return false; //与操作,判断 x 二进制最低位是否为 1,即 x 是否为奇数
    while(!(t&1)) 
    {
        s++;
        t>>=1; //移位操作,删除 n 二进制的最低位
    }
    for(i=0;i<10&&prime[i]<x;++i)
    {
        long long a=prime[i];
        long long b=Quick_Power(a,t,x);
        for(j=1;j<=s;++j)
        {
            k=Quick_Multiply(b,b,x);
            if(k==1&&b!=1&&b!=x-1)
            	return false;
            b=k;
        }
        if(b!=1)  return false;
    }
    return true; 
}

结合费马小定理与米勒-拉宾素性检验,构造大素数生成代码:

#include<iostream>
#include<math.h>
using namespace std;
typedef long long ll;
 
int prime[10]={2,3,5,7,11,13,17,19,23,29};
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;
}
bool Miller_Rabin(ll x)
{
    ll i,j,k;
    ll s=0,t=x-1;
    //cout<<t<<endl;
    if(x==2)  return true;
    if(x<2||!(x&1))  return false;
    while(!(t&1)) 
    {
        s++;
        t>>=1;
    }
    for(i=0;i<10&&prime[i]<x;++i)
    {
        ll a=prime[i];
        ll b=Quick_Power(a,t,x);
        for(j=1;j<=s;++j)
        {
            k=Quick_Multiply(b,b,x);
            if(k==1&&b!=1&&b!=x-1)
              return false;
            b=k;
        }
        if(b!=1)  return false;
    }
    return true; 
}
int main()
{
    ll x,y,z,flag;
    cout<<"Please enter an integer:";
    cin>>flag;
    while(true)
    {
    	x=flag;
		y=x-1;
    	z=pow(y,y);
    	x=x*z+1;
    	cout<<"x = "<<x<<endl; //查看是否越界 
    	if(Miller_Rabin(x))
		{
			cout<<"The large prime number is:"<<x<<endl;
			break;
		}
    	else
		{
			cout<<x<<" is not a prime number,it will add the integer you enter to 1 and try again"<<endl;
			flag++;
		}	
	}
	return 0;
}

运行结果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看出当输入的整数为 11 时,程序运行至 x 越界也没能生成素数。大质数可在此查找:大质数表

0x03 Summary

费马素数判定与米勒-拉宾素数判定均属于随机性测试。这类测试方法一般比较快,但无法完全证明一个数是否为素数。在米勒-拉宾算法中,随着测试成功次数的增加,合数的概率会呈指数式下滑,素数的可信度越来越大(但不完全可信)。一旦测试失败,则表明该数为一定为合数。
在这里插入图片描述

0x04 Reference

https://blog.csdn.net/qq_42146775/article/details/102562329
https://blog.csdn.net/forever_dreams/article/details/82314237
https://blog.csdn.net/holly_Z_P_F/article/details/85197424

  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值