仿射密码(原理+代码)

仿射密码

目录

1、原理:

2、流程图

3、编程实现

4、总结


1、原理:

        仿射密码是一种单表代换的对称密码。明文中所有字母对应成数值,经过加密函数加密成新的数值,再对应到相应的字母,组成密文, 密文和明文一样经过解密函数恢复成明文。


        加密函数:E(x)=(ax+b)\mod m


        解密函数:D(x)=a^{-1}(x-b)\mod m


        其中,a与m互质,a^{-1}是a在Z_{m}群中的乘法逆元

2、流程图

3、编程实现

        需要解决的难点:如何编程实现求 乘法逆元 视频介绍的非常清楚。

        方法一:简单凑数

int cnt = 26, a = 0, ainv = 0;
cin >> a;
int i = 1;
while (1) {
    int temp = a * i;
    if (temp % cnt == 1) {
        ainv = i;
        break;
    }
    i++;
}

        方法二:费马小定理

                当m为质数时有:a^{m-1}\equiv 1\mod m   ,即有 a*a^{m-2}\equiv 1\mod m

                所以求a的乘法逆元就是求a的m-2次方,可以通过快速幂得到,当然这种方法只能在m为质数的时候使用。

typedef long long ll;
ll fastPow(ll a, ll p, ll m) {
    ll ans = 1;
    a %= m;
    while (p) {
        if (p & 1)ans = (ans * a) % m;
        a = (a * a) % m;
        p >>= 1;
    }
    return ans;
}
ll getInv(ll a, ll m) {
    return fastPow(a, m - 2, m);
}   

        方法三:扩展欧几里得算法

int x, y;
int gcd(int a, int b,int &x,int &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    int g = gcd(b, a % b, x, y);
    int temp = x;
    x = y;
    y = temp - (a / b) * y;
    return g;
}
int getInv(int a, int m) {
    gcd(a, m, x, y);
    return (x % m + m) % m;
}

        方法四:线性求逆元

                这种方法同样只适用于当m为质数的情况,但是可以快速地求出从1到n(n<m)模m的乘法逆元

int inv[MAXN];
int getInv(int a, int m) {
    inv[1] = 1;
    for (int i = 2; i <= a; i++) {
        inv[i] = -(m / i) * inv[m % i];
        inv[i] = (inv[i] % m + m) % m;
    }
    return inv[a];
}

        难点完美解决了,接下来开始写代码。

        具体代码如下:

        输入的明文默认小写英文字母,密文默认大写英文字母

        主函数:

#include"affine.h"

int main() {
	while (1) {
		show();		//菜单界面
		keyDown();	//按键处理
		system("pause");
		system("cls");		
	}
}

        头文件affine.h

#pragma once
#include<cstdio>
#include<iostream>
#include<cstring>
#include<Windows.h>
using namespace std;
void init();
void show();
void keyDown();
void readFile();
void saveFile();
void encrypt();
void decrypt();
int gcd(int a, int b,int &x,int &y);
int getInv(int a, int m);

        affine.h 的具体实现 affine.cpp

#include "affine.h"
string fileStr="";
string finalStr = "";
int a, b;
int x, y;
int itable[26] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25 };
char Ctable[26] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N' ,'O','P','Q','R','S','T' ,'U','V','W','X','Y','Z' };
char ctable[26] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n' ,'o','p','q','r','s','t' ,'u','v','w','x','y','z' };
void init()//初始化
{
	a = 0;
	b = 0;
	fileStr = "";
	finalStr = "";
	x = 0;
	y = 0;
}
void show()
{
	cout << "*****************仿射密码*****************" << endl;
	cout << "\t\t1.加密文件" << endl;
	cout << "\t\t2.解密文件" << endl;
	cout << "\t\t3.退出" << endl;
	cout << "******************************************" << endl;

}

void keyDown()//按键处理
{
	int userkey = 0;
	cin >> userkey;
	switch (userkey) {
	case 1:
		cout << "-----------------加密文件-----------------" << endl;
		readFile();
		encrypt();
		saveFile();
		init();
		break;
	case 2:
		cout << "-----------------解密文件-----------------" << endl;
		readFile();
		decrypt();
		saveFile();
		init();
		break;
	case 3:
		exit(0);
		break;
	}
}

void readFile()//读取文件
{
	cout << "请输入文件名:" << endl;
	string fileName ;
	cin >> fileName;
	FILE* fp = fopen(fileName.c_str(), "r+");
	if (fp == nullptr) {
		cout << "未找到相关文件" << endl;
		return;
	}
	else {
		cout << "成功打开文件" << endl;
	}
	char ch;
	int pos = 0;
	while ((ch = fgetc(fp)) != EOF) {
		fileStr+=ch;
	}
	cout << endl << "待处理的文件为:" << endl;
	cout << fileStr << endl;
	fclose(fp);
}



void saveFile()//保存文件
{
	string fileName;
	cout << endl << "请输入要保存信息的文件名:" << endl;
	cin >> fileName;
	FILE* fp = fopen(fileName.c_str(), "w+");
	if (fp == nullptr) {
		cout << endl << "保存文件失败" << endl;
		return;
	}
	else {
		cout << endl << "保存成功" << endl;
	}
	fprintf(fp, "%s", finalStr.c_str());
	fclose(fp);
	
}

void encrypt()//加密文件
{
	cout << endl << "请输入密钥(a,b):" << endl;
	cin >> a >> b;
	cout << endl << "按下任意键进行加密" << endl;
	char ch = getchar(); ch = getchar();
	for (char ch : fileStr) {
		if (ch == ' ') {
			finalStr += ' ';
		}
		else {
			int temp = (a * itable[ch - 'a'] + b) % 26;
			finalStr += Ctable[temp];
		}
	}
	cout << endl << "得到的密文为:" << endl;
	cout << finalStr << endl;
}

void decrypt()//解密文件
{
	cout << endl << "请输入密钥(a,b):" << endl;
	cin >> a >> b;
	int ainv = getInv(a, 26);
	cout << endl << a << "的乘法逆元为:" << ainv << endl;
	cout << endl << "按下任意键进行解密" << endl;
	char ch = getchar(); ch = getchar();
	for (char ch : fileStr) {	
		if (ch == ' ') {
			finalStr += ' ';
			continue;
		}
		else {
			int temp = ainv * (itable[ch - 'A'] - b) % 26;
			temp = (temp % 26 + 26) % 26;
			finalStr += ctable[temp];
		}
	}

	cout << endl << "得到的明文为:" << endl;
	cout << finalStr << endl;
}

int gcd(int a, int b, int& x, int& y)//求最大公约数
{
	if (b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	int g = gcd(b, a % b, x, y);
	int temp = x;
	x = y;
	y = temp - (a / b) * y;
	return g;
}

int getInv(int a, int m)//求乘法逆元
{
	gcd(a, m, x, y);
	return (x % m + m) % m;
}

4、总结

        仿射密码是一种比较简单的密码,明文空间一般为26个英文字母,任意两个不同的字母加密或解密后对应不用的字母,相同的字母加密或解密后对应相同的字母,所有仿射密码可以使用频率分析法破解。

        当密钥a=1时,即为凯撒密码。对于26个英文字母来说,由于要满足a与m互质,而由于\varphi (26)=12,所以对于仿射密码来说,密钥空间大小只有12*26=312,应该是比较小的。以上就是个人对仿射密码的理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值