Z26上的仿射密码体制

本文介绍了一种基于Z26的仿射密码体制,详细阐述了加密和解密过程。加密公式为y=k1x+k2(mod26),解密公式为x=_k1(y-k2)(mod26),其中_k1是k1的乘法逆元。通过实例,实现了读取文本文件‘in.txt’进行加密,并将结果保存到‘encode.txt’,同时进行解密,结果保存到‘decode.txt’。

加密过程
y=k1x+k2(mod26)

解密过程

x=_k1(y-k2)(mod26)

_k1为k1的乘法逆元,因为有26这个范围,而且逆元唯一,所以可直接脑残试出_k1的值

 

具体实现:

读文本文件"in.txt"进行加密,结果放到"encode.txt"中,同时进行解密,结果放在"decode.txt"中

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <fstream>
#include <math.h>
#include <time.h>
using namespace std;

int k1[12]={1,3,5,7,9,11,15,17,19,21,23,25},k2, _k1;
int index;
char temp;
char ans;

int gcd(int a,int b)
{
    int temp;
    if(a<b)
    {
        temp=a;
        a=b;
        b=temp;
    }

    int r=1;
    while(r)
    {
        r=a%b;
        a=b;
        b=r;
    }
    return a;
}

void chengfaniyuan()
{
    int i;
    for(i=1; i<26; i++)
    {
        if((k1[index]*i)%26==1)
        {
            _k1=i;
            return;
        }
    }
}

void encode()
{
    temp=temp-97;
    temp=(k1[index]*temp+k2)%26+97;
}

void decode()
{
    int sum=temp-97-k2;
    while(sum<0)
    {
        sum+=26;
    }
    ans=(_k1*(sum))%26+97;
}

int main()
{
    srand(time(NULL));

    index=rand()%12;
    k2=rand()%26;

    //cout<<k1[index]<<" "<<k2<<endl;
    chengfaniyuan();
    //cout<<_k1<<endl;

//因为仿射密码是流密码,所以对每个字符进行处理
    ifstream in("in.txt");
    ofstream out1("encode.txt");
    ofstream out2("decode.txt");

    while(in.get(temp))
    {
        if(!(temp>='a'&&temp<='z'))
        {
            out1<<temp;
            out2<<temp;
            continue;
        }
        
        encode();
        out1<<temp;
        decode();
        out2<<ans;
    }
    in.close();
    out1.close();
    out2.close();
    return 0;
}
实验2.3 代换密码-仿射密码的实现 所谓代换(Substitution),就是将明文中的一个字母由其它字母、数字或符号替代的一种方法。按照一个明文字母是否总是被一个固定的字符代换进行划分:单表(码)代换密码,指的是对明文消息中出现的同一个字母,在加密时都使用同一固定的字母来代换,不管它出现在什么地方。例如移位、仿射、字母表置换密码;多表(码)代换密码,是指明文消息中出现的同一个字母,在加密时不是完全被同一固定的字母代换,而是根据其出现的位置次序,用不同的字母代换,例如维吉利亚密码、HILL密码、轮转密码机。本章实验要实现移位密码,仿射密码和维吉尼亚密码。 仿射密码的算法说明如下:明密文是26个英文字母,密钥空间K={ (a,b) : a,b∈Z26, 且gcd(a, 26)=1},在实际进行加解密运算时,先把26个英文字母依次与0,1,2,…,25对应。加密算法为Ek(m)= am+b =c (mod 26),解密算法为 Dk(c)= a-1(c-b) =m (mod 26)。 要求:编程实现上述算法,明文为hot,密钥k=(7,3),求输出密文。要能够实现解密算法,在输入密文和求得解密密钥后得到正确的明文。注意输入输出都要是英文字符的形式。输入输出不区分大小写。程序中应当有判断密钥第一位是否与26互素以及在互素的前提下求得逆元的子程序。用c语言生成
最新发布
03-14
<think>好的,我现在需要解决用户的问题,帮助实现仿射密码的加密和解密程序,用C语言编写。用户给定了明文“hot”和密钥k=(7,3),需要输出密文,并且程序要能够解密,同时要检查密钥的有效性以及计算逆元。 首先,我需要理解仿射密码的工作原理。加密公式是E(m) = (a*m + b) mod 26,解密是D(c) = a⁻¹*(c - b) mod 26。这里的关键点在于a必须与26互质,否则无法找到逆元a⁻¹,导致解密失败。所以程序中必须检查gcd(a,26)是否为1。 接下来,我需要考虑如何将字符转换为数字。英文字母不区分大小写,所以需要统一处理,比如将所有输入转为大写或小写。例如,'h'对应的数字是7(因为h是第8个字母,从0开始计数),'o'是14,'t'是19。 然后,加密过程:对于每个字符,计算(a * m + b) mod 26。例如,h对应的7,加密后是(7*7 +3)=52 mod26=0,即字符'A'或'a'。同样处理o和t,得到密文。 解密时,需要计算a的逆元。这里a=7,逆元是满足7*x ≡1 mod26的数。通过扩展欧几里得算法,可以找到x=15,因为7*15=105,105 mod26=1。所以解密时使用15作为a的逆元。 接下来,程序的结构。需要实现以下功能: 1. 检查a是否与26互质,即gcd(a,26)=1。 2. 计算a的逆元。 3. 加密函数,输入明文和密钥,输出密文。 4. 解密函数,输入密文和密钥,输出明文。 对于输入处理,需要考虑将字符转换为小写或大写,减去'a'或'A'的ASCII值得到0-25的数字。加密后的结果再转换回字符。 可能的错误点:忘记处理大小写,逆元计算错误,或者没有正确实现模运算(特别是负数的情况,例如解密时c-b可能为负数,需要调整为正数再取模)。 测试用例:明文hot,密钥(7,3),加密后应为axq。例如,h→7→7*7+3=52→0→a,o→14→7*14+3=101→101 mod26=23→x,t→19→7*19+3=136→136 mod26=4→e?等等,可能哪里算错了?或者可能我计算的时候出错了,需要再仔细核对。 等一下,计算h的例子:7*7=49+3=52,52 mod26=0,对应a。正确。o:7*14=98+3=101,101除以26是3*26=78,余23,对应x。t:7*19=133+3=136,136-5*26=136-130=6,所以对应g?或者我哪里算错了? 哦,这里可能出错了。让我再算一遍:7*19=133,133+3=136。136除以26是多少?26*5=130,136-130=6,所以余6,对应g?那密文应该是axg?但用户给出的例子可能结果不同,或者我哪里算错了? 或者可能用户给的示例中正确密文是什么?可能需要重新计算。根据用户的问题,可能需要正确计算。 可能我之前的思考中t的计算有误,需要再检查一次。 所以,用户的问题中,密钥k=(7,3),明文是hot,加密后的密文应该是什么? h: h是第7个字母(从0开始),7*7 +3 =52 →52 mod26=0 →a。 o: o是14,7*14=98+3=101 →101 mod2626*3=78,101-78=23 →x。 t是19,7*19=133 +3=136 →136 mod2626*5=130,136-130=6 →对应g。所以密文应为axg?但可能用户期望的是另一个结果?或者我的计算有误? 这个时候可能需要再仔细检查。或者可能用户的问题中的示例有误?或者我的计算哪里出错了? 或者,可能模26时,余数的范围是0到25,所以136除以26等于5*26=130,余6,所以正确是g。那密文是axg? 或者,可能我哪里弄错了字母顺序?例如,0是a,1是b,...,6是g。所以是的。所以密文应为axg。 但根据常见的仿射密码示例,例如,当a=7,b=3时,加密后的结果可能不同。或者可能我哪里弄错了? 或者,可能用户的问题中的正确密文是什么?可能需要用户自己运行程序后得到结果。但程序需要正确实现计算。 接下来,我需要确保程序中正确执行这些计算。例如,在加密函数中,将每个字符转换为数字,应用公式,再转换回来。 对于解密函数,需要计算a的逆元。当a=7时,逆元是15。所以解密时,计算15*(c -3) mod26。例如,假设密文字符是a(0),则15*(0-3)= -45 mod26。因为-45 + 26*2=7,所以7对应h,正确。 同样,如果密文是x(23),则15*(23-3)=15*20=300 →300 mod2626*11=286,300-286=14→o,正确。对于g(6),15*(6-3)=45 mod26=45-26=19→t,正确。所以密文axg解密回hot。这说明程序是正确的。 现在,编写C语言程序的结构: 首先,检查a是否与26互质。gcd函数可以用欧几里得算法实现。如果gcd(a,26)!=1,则密钥无效。 计算逆元:使用扩展欧几里得算法来找x,使得a*x ≡1 mod26。或者,可以用穷举法,因为26比较小,试从1到25,寻找x满足(a*x)%26 ==1。 程序中,需要实现这两个函数:检查互质,以及求逆元。 加密函数:遍历明文的每个字符,转为小写,转换为数字,应用公式,转换回字符。 解密函数类似,但使用逆元和公式。 输入输出要求不区分大小写,所以可以将所有输入转为小写或大写处理。 需要注意,输入可能包含非字母字符?但题目中说明明密文是26个英文字母,所以可能不需要处理其他字符,或者可以忽略? 根据题目描述,输入输出都是英文字符,所以假设输入是字母,程序可以忽略非字母字符,或者报错。但题目可能要求只处理字母,其他字符保留原样?但用户问题中的明文是hot,所以可能只需处理字母,其他字符可能不处理。但根据题目要求,输入输出都是英文字符,所以可能假设输入是纯字母。 综上,程序的大致步骤: 1. 检查a是否有效(与26互质),无效则提示错误。 2. 计算a的逆元。 3. 加密:对每个字符,转换为数字,加密,转换回字符。 4. 解密:对每个字符,转换,应用解密公式,转回字符。 现在,编写代码的大纲: - 函数gcd计算最大公约数。 - 函数modInverse计算逆元。 - 加密函数affine_encrypt。 - 解密函数affine_decrypt。 - main函数处理输入,测试用例。 例如,用户需要输入明文和密钥,或者直接测试给出的例子。根据题目要求,可能需要将明文hot加密,所以main函数中可以硬编码测试案例。 但是,题目要求程序能够实现加密和解密,所以可能需要用户输入选择加密或解密,并输入相应的密钥和文本。但用户的问题可能需要一个程序,当给定明文和密钥时,输出密文,并能够解密。所以可能需要将密钥作为参数,或者从输入读取。 根据用户的要求,程序应当有判断密钥是否有效,以及在互素时求逆元的子程序。所以需要包含这些检查。 现在,可能的代码结构: #include <stdio.h> #include <string.h> #include <ctype.h> // 计算最大公约数 int gcd(int a, int b) { if (b == 0) return a; else return gcd(b, a % b); } // 计算a的模26逆元,如果存在的话 int modInverse(int a) { a = a % 26; for (int x=1; x<26; x++) { if ((a*x) %26 ==1) return x; } return -1; // 不存在逆元 } // 加密函数 void affine_encrypt(char *plaintext, int a, int b) { for (int i=0; plaintext[i]!='\0'; i++) { if (isalpha(plaintext[i])) { char c = tolower(plaintext[i]); int m = c - 'a'; int encrypted = (a * m + b) %26; if (encrypted <0) encrypted +=26; // 处理负数 plaintext[i] = encrypted + 'a'; } } } // 解密函数 void affine_decrypt(char *ciphertext, int a, int b) { int a_inv = modInverse(a); if (a_inv == -1) { printf("Invalid key, cannot decrypt.\n"); return; } for (int i=0; ciphertext[i]!='\0'; i++) { if (isalpha(ciphertext[i])) { char c = tolower(ciphertext[i]); int m = c - 'a'; int decrypted = (a_inv * (m - b)) %26; if (decrypted <0) decrypted +=26; // 处理负数 ciphertext[i] = decrypted + 'a'; } } } int main() { int a =7, b=3; char plaintext[] = "hot"; char ciphertext[strlen(plaintext)+1]; strcpy(ciphertext, plaintext); // 检查a是否有效 if (gcd(a,26)!=1) { printf("密钥a无效,必须与26互质。\n"); return 1; } // 加密 affine_encrypt(ciphertext, a, b); printf("加密后的密文:%s\n", ciphertext); // 解密测试 char decrypted[strlen(ciphertext)+1]; strcpy(decrypted, ciphertext); affine_decrypt(decrypted, a, b); printf("解密后的明文:%s\n", decrypted); return 0; } 但这里的加密函数是直接修改原字符串,所以需要复制明文到密文字符串。或者,可以创建一个新的字符串来存储结果。 另外,测试时,加密后的结果应该打印出来。根据之前的计算,加密后的结果应为"axg"。但是根据代码运行结果,是否正确? 例如,h的加密: m=7,加密为7*7+3=52 mod26=0 →a。 o是14:7*14=98+3=101 →101 mod26=101-3*26=101-78=23 →x. t是19:7*19=133+3=136 →136-5*26=136-130=6 →g. 所以密文是axg。 但用户是否预期这个结果?或者可能我哪里弄错了? 根据仿射密码的正确性,这应该是正确的。所以当输入hot时,密文是axg。但可能用户预期不同的结果?例如,如果计算错误,比如模运算时错误。 但根据代码中的处理,是正确的。例如,在加密函数中,计算encrypted时,用%26,并且处理了负数的情况(虽然在这里不需要,因为a和m都是正数,b也是正数,所以结果不会为负数)。 那么,程序运行后,加密结果是axg,解密后恢复为hot。这应该正确。 现在,检查可能的错误: 在解密函数中,是否计算正确?比如,密文字符是a(0): a_inv=15,解密是15*(0-3)= -45 →-45 mod26。计算方式:-45 + 26*2 =7 →7 →h。 是的,正确。 同理,x是23:15*(23-3)=15*20=300 →300 mod26=300-11*26=300-286=14 →o。 t对应的密文字符是g(6):15*(6-3)=45 →45 mod26=45-26=19 →t。 所以解密正确。 因此,程序是正确的。 现在,用户问题中的示例中可能期望不同的结果?或者可能我的计算哪里出错了? 或者,可能用户的问题中的示例中,密钥是(7,3)时正确的密文确实是axg? 是的。因此,程序应该正确生成该结果。 综上,这个程序应该满足用户的要求,并且通过测试。</think>以下是仿射密码的C语言实现及详细解析: ```c #include <stdio.h> #include <string.h> #include <ctype.h> // 计算最大公约数 int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } // 计算模26逆元 int modInverse(int a) { a = a % 26; for (int x = 1; x < 26; x++) if ((a * x) % 26 == 1) return x; return -1; // 逆元不存在 } // 加密函数 void affine_encrypt(char *text, int a, int b) { for (int i = 0; text[i]; i++) { if (isalpha(text[i])) { int m = tolower(text[i]) - 'a'; int c = (a * m + b) % 26; text[i] = c < 0 ? c + 26 + 'a' : c + 'a'; } } } // 解密函数 void affine_decrypt(char *text, int a, int b) { int a_inv = modInverse(a); if (a_inv == -1) return; for (int i = 0; text[i]; i++) { if (isalpha(text[i])) { int c = tolower(text[i]) - 'a'; int m = (a_inv * (c - b)) % 26; text[i] = m < 0 ? m + 26 + 'a' : m + 'a'; } } } int main() { char plain[] = "hot"; int a = 7, b = 3; // 验证密钥有效性 if (gcd(a, 26) != 1) { printf("错误:a必须与26互质\n"); return 1; } // 加密演示 char cipher[10]; strcpy(cipher, plain); affine_encrypt(cipher, a, b); printf("加密结果:%s\n", cipher); // 输出:axg // 解密演示 char decrypted[10]; strcpy(decrypted, cipher); affine_decrypt(decrypted, a, b); printf("解密结果:%s\n", decrypted); // 输出:hot return 0; } ``` ### 关键算法说明 1. **加密公式** $$E_k(m) = (a \cdot m + b) \mod 26$$ 其中`m`为明文字母对应数字(a=0, b=1,...z=25) 2. **解密公式** $$D_k(c) = a^{-1} \cdot (c - b) \mod 26$$ 其中$a^{-1}$是$a$在模26下的乘法逆元 3. **密钥有效性验证** - 通过`gcd(a, 26) == 1`验证互质性 - 逆元通过穷举法查找满足$(a \cdot x) \% 26 = 1$的`x` ### 代码执行流程 1. **输入处理**:统一转为小写字母处理 2. **加密过程**:将每个字母转换为数字后代入公式计算 3. **解密过程**:先计算逆元,再代入解密公式 4. **异常处理**:检测无效密钥并提前终止 ### 示例验证 - 明文:`hot`(对应数字7,14,19) - 加密计算: - $h \rightarrow (7*7+3)\%26 = 0 \rightarrow a$ - $o \rightarrow (7*14+3)\%26 = 23 \rightarrow x$ - $t \rightarrow (7*19+3)\%26 = 6 \rightarrow g$ - 密文输出:`axg`
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值