维吉尼亚密码破解

首先使用Friedman确定关键词长度

//s为密文,len为密文长度
int friedman(string s,int len)
{
    int keyLength = 2;  //猜测秘钥长度
    double avgIc;  //平均重合指数

    while(true)
    {
        vector<string> cipherGroup;  //密文分组
        avgIc = 0;
        double Ic[keyLength]; //重合指数
        //根据秘钥长度分组
        for(int i=0; i<keyLength; ++i)
        {
            string temp = "";
            for(int j=0; i+j*keyLength<len; ++j)
            {
                temp += s[i+j*keyLength];
            }
            cipherGroup.push_back(temp);
        }

        //计算每一组的重合指数
        for(int i=0; i<keyLength; ++i)
        {
            string subCipher = cipherGroup[i];
            int occurrentNumber[26]= {0}; //记录每个字母出现的次数
            for(int j=0; j<subCipher.length(); j++)
            {
                occurrentNumber[subCipher[j]-'a']++;
            }
            //计算重合指数
            double denominator = subCipher.length()/1.0*subCipher.length();
            for(int k=0; k<26; k++)
            {
                double o = occurrentNumber[k]/1.0;
                Ic[i] += o*(o-1);
            }
            Ic[i] /= denominator;
        }

        //判断退出条件,重合指数的平均值是否大于0.065
        for(int i=0; i<keyLength; ++i)
        {
            avgIc += Ic[i];
        }
        avgIc /= (keyLength/1.0);
        if(avgIc>=0.065)
        {
            break;
        }
        else
        {
            keyLength++;
        }
        cipherGroup.clear();
    }

    cout<<"密钥长度为:"<<keyLength<<endl;
    return keyLength;
}

 再利用重合指数法确定关键词,解出明文

//keyLength为关键词长度,ciphertext为密文
void decryptCipher(int keyLength,string ciphertext)
{
    int key[keyLength];
    vector<string> cipherGroup;
    double probability[] = {0.082,0.015,0.028,0.043,0.127,0.022,0.02,0.061,0.07,0.002,0.008,
                            0.04,0.024,0.067,0.075,0.019,0.001,0.06,0.063,0.091,0.028,0.01,0.023,0.001,0.02,0.001
                           };

    //根据密钥长度分组
    for(int i=0; i<keyLength; ++i)
    {
        string temp = "";
        for(int j=0; i+j*keyLength<ciphertext.length(); ++j)
        {
            temp += ciphertext[i+j*keyLength];
        }
        cipherGroup.push_back(temp);
    }

    //确定密钥
    for(int i=0; i<keyLength; ++i)
    {
        double MG;  //重合指数
        int flag;  //移动位置
        int g = 0;  //密文移动g个位置
        string subCipher="";  //子串

        while(true)
        {
            int occurenceNumber[26]= {0}; //字母出现次数
            MG = 0;
            flag = g;
            subCipher = cipherGroup[i];

            //统计字母出现的次数
            for(int h=0; h<subCipher.length(); ++h)
            {
                occurenceNumber[subCipher[h]-'a']++;
            }

            //计算重合指数
            for(int k=0; k<26; ++k,++flag)
            {
                double p = probability[k];
                flag = (flag == 26)? 0:flag;
                double f = occurenceNumber[flag]/1.0/subCipher.length();
                MG += p*f;
            }

            //判断退出条件
            if(MG >= 0.055)
            {
                key[i] = g;
                break;
            }
            else
            {
                g++;
            }
        }
    }

    //打印密钥
    string keyString  = "";
    for(int i=0; i<keyLength; ++i)
    {
        keyString += (char)(key[i]+'a');
    }

    cout<<"密钥为:"<<keyString<<endl;

    //解密
    string plainBuffer = "";
    cout<<ciphertext<<endl;
    for(int i=0; i<ciphertext.length(); i++)
    {
        int j = i % keyLength;
        int k = keyString[j]-'a';
        plainBuffer += (ciphertext[i]-'a'+26-k)%26+'a';
    }

    cout<<"破解后明文为:"<<plainBuffer<<endl;
}

经过测试,关键词长度可准确求出,关键词会有误差。

    原文作者:维吉尼亚加密问题
    原文地址: https://blog.csdn.net/qq_37523868/article/details/82499793
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞