仿射密码解密,输出大小写不同

Posted

技术标签:

【中文标题】仿射密码解密,输出大小写不同【英文标题】:Affine cipher decryption, output differs for upper case and lower case 【发布时间】:2020-02-03 12:44:00 【问题描述】:

我在使用仿射密码解密明文时遇到问题。 加密工作正常,但对小写/大写字符的解密应用相同的逻辑会返回不同的输出。

这是输出:

加密消息是:ulctkbsjarizqhypgxofwnevmd ULCTKBSJARIZQHYPGXOFWNEVMD 解密消息为:opqrstuvwxyzabcdefghijklmn ABCDEFGHIJKLMNOPQRSTUVWXYZ

我怀疑这与检索 ASCII 值有关,有人可以纠正我吗?

这是我的代码:

#include<bits/stdc++.h> 
using namespace std; 

//Key values of a and b 
const int a = 17; 
const int b = 20; 

string encryptMessage(string plainText) 
 
    string cipher = ""; 

    for (int i = 0; i < plainText.length(); i++) 
     
        if(plainText[i]!=' ') 
        
            if ((plainText[i] >= 'a' && plainText[i] <= 'z') || (plainText[i] >= 'A' && plainText[i] <= 'Z'))
            
                if (plainText[i] >= 'a' && plainText[i] <= 'z')
                
                    cipher = cipher + (char) ((((a * (plainText[i]-'a') ) + b) % 26) + 'a'); 
                

                else if (plainText[i] >= 'A' && plainText[i] <= 'Z')
                
                    cipher = cipher + (char) ((((a * (plainText[i]-'A') ) + b) % 26) + 'A');
                

            
            else
            
                cipher += plainText[i]; 
            

        
        else
        
            cipher += plainText[i]; 
        

     
    return cipher; 
 

string decryptCipher(string cipher) 
 
    string plainText = ""; 
    int aInverse = 0; 
    int flag = 0; 

    for (int i = 0; i < 26; i++) 
     
        flag = (a * i) % 26; 

        if (flag == 1) 
         
            aInverse = i; 
         
     

    for (int i = 0; i < cipher.length(); i++) 
     
        if(cipher[i] != ' ') 
        
            if ((cipher[i] >= 'a' && cipher[i] <= 'z') || (cipher[i] >= 'A' && cipher[i] <= 'Z'))
            
                if (cipher[i] >= 'a' && cipher[i] <= 'z')
                
                    plainText = plainText + (char) ((((aInverse * (cipher[i]+ 'a') ) - b) % 26) + 'a'); 

                

                else if (cipher[i] >= 'A' && cipher[i] <= 'Z')
                
                    plainText = plainText + (char) (((aInverse * ((cipher[i]+'A' - b)) % 26)) + 'A'); 

                

            
            else
            
                plainText += cipher[i]; 
                       
        
        else

            plainText += cipher[i]; 
     

    return plainText; 

 

//Driver Program 
int main(void) 
 
    string msg = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 

    //Calling encryption function 
    string cipherText = encryptMessage(msg); 
    cout << "Encrypted Message is : " << cipherText<<endl; 

    //Calling Decryption function 
    cout << "Decrypted Message is: " << decryptCipher(cipherText); 

    return 0; 
 


【问题讨论】:

((((a * (plainText[i]-'a') ) + b) % 26) + 'a')更改为(((((a * (plainText[i]-'a') ) + b) % 26) + 'a') % 26) 每次出现ab 变量都是编译器错误。你的意思是'a''b' ... 例如,在这一行中:cipher = cipher + (char) ((((a * (plainText[i]-'A') ) + b) % 26) + 'A'); 您使用 ab - 但这些声明和/或定义在哪里? @AdrianMole a 和 b 是仿射密码的密钥。以下公式 E ( x ) = ( a x + b ) mod m 和 D ( x ) = a^-1 ( x - b ) mod m 然后在您发布的代码中包含这些定义! (我试图编译您的代码以查看问题出在哪里,但由于错误而无法编译 - 这就是为什么我们要求一个最小的 reproducible 示例!!) 【参考方案1】:

我一直在考虑这个问题,虽然我无法提供完整的解释,但我有一些可能有用的“观察”,以及一个“作弊”解决方法.

首先,尽管您说您使用“相同的逻辑来解密小写/大写”,每个解密块中的代码的字符对齐表明这是' t 相当是的:

plainText = plainText + (char) ((((aInverse * (cipher[i]+ 'a') ) - b) % 26) + 'a'); // Lower case
plainText = plainText + (char) (((aInverse * ((cipher[i]+'A' - b)) % 26)) + 'A');   // Upper case

因此,将小写代码“修复”为完全类似于大写的(工作)代码(并删除多余的括号)给出:

if (cipher[i] >= 'a' && cipher[i] <= 'z')

    plainText = plainText + (char)( ( (aInverse * (cipher[i] + 'a' - b) ) % 26 ) + 'a' );

else if (cipher[i] >= 'A' && cipher[i] <= 'Z')

    plainText = plainText + (char)( ( (aInverse * (cipher[i] + 'A' - b) ) % 26 ) + 'A' );

但是,这实际上并不能解决问题(它只是稍微改变了它),因为输出如下:

Encrypted Message is : ulctkbsjarizqhypgxofwnevmd ULCTKBSJARIZQHYPGXOFWNEVMD
Decrypted Message is : qrstuvwxyzabcdefghijklmnop ABCDEFGHIJKLMNOPQRSTUVWXYZ

这里的问题是小写值都被值16“旋转”了——这看起来很接近a的值。另外请注意,虽然a 用于加密公式,但它在您的解密中使用。

因此,我想出了以下解决方法,假设(由于尚未推断出的原因)在解码大写值时,这个 16 在 ASCII 值的位表示中以某种方式丢失:

if ((cipher[i] >= 'a' && cipher[i] <= 'z') || (cipher[i] >= 'A' && cipher[i] <= 'Z'))

    int offset = ((cipher[i] - 'A') / 26) ? a - 1 : 0;
    if (cipher[i] >= 'a' && cipher[i] <= 'z') 
        plainText = plainText + (char)( ( (aInverse * (cipher[i] + 'a' - b) - offset ) % 26 ) + 'a' );
    
    else if (cipher[i] >= 'A' && cipher[i] <= 'Z') 
        plainText = plainText + (char)( ( (aInverse * (cipher[i] + 'A' - b) - offset ) % 26 ) + 'A' );
    

请注意,您的代码可以使用标准库提供的函数进一步简化/澄清,并删除一些“冗余”检查:

for (int i = 0; i < cipher.length(); i++) 
    if (isalpha(cipher[i])) 
        int offset = islower(cipher[i]) ? a - 1 : 0;
        int letter = islower(cipher[i]) ? 'a' : 'A';
        plainText = plainText + (char)(((aInverse * (cipher[i] + letter - b) - offset) % 26) + letter);
    
    else 
        plainText += cipher[i];
    

【讨论】:

以上是关于仿射密码解密,输出大小写不同的主要内容,如果未能解决你的问题,请参考以下文章

如何在 JAVA 中编写仿射密码解密的逻辑?

简单的加密与解密的实现---仿射密码

Python-移位密码仿射变换解密

简单的加密与解密的实现---仿射密码(c++使用string)

大小写字符串加解密,基本密码c++

字符串加密