基于流加密(stream cipher)下如何依靠多段密文获取特定密文的明文(c++实现)

问题:已知十段密文,以及一段待解出的特定密文,如何获取特定密文的明文?

已知:所有的密文都是使用同样的key,使用stream cipher(流加密),只是简单使用原文和key异或得到密文,而且key是随机的,长于所有的原文

解决方法:主要思想在于利用空格(space),因为空格与任意大小写字母异或都能够得到大小写相反的同样字母,比如space与a异或可以得到A,可参考如下的ASCII表:
这里写图片描述

1、首先找出待解密文的空格
利用十段密文分别与待解密文异或,如果异或的结果同一位置都是字母,而且密文内容不一样,那么可以暂且判定当前位置的待解密文的原文是空格,因为密文异或的结果和明文异或的结果是相同的,那么既然不同的明文和同一个明文异或结果都是字母,那就可以暂且判断这个明文是空格,如下证明了为何明文异或结果与密文异或结果相同:
这里写图片描述

2、再获取待解密文中的字母
利用总的十一段密文相互异或,使用1中的方法找出十段密文中某个位置上的空格,那么就可以使用该位置待解密文与具有空格的密文异或的结果再与空格异或即可获得待解密文的原文。理由在于我们知道明文之间的异或结果与密文的异或结果相同,已知一个明文是空格,则只需要在等式两边分别再异或一个空格,则可以消除明文这一边的空格剩下待解明文,如下图所示(假设我们利用1的方法找到P2是space,则可以得出下例)
这里写图片描述

3、最后再重新对待解密文中在1中暂认为是空格的地方重判断
也就是再利用2中的方法即可。因为比如说我们使用ASCII码的237位与191位异或,也会得到字母,所以有可能当前target其实并不是空格,因此我们还需要再反过来判断一次。

代码如下所示:

c1.txt(总共十段密文)
315c4eeaa8b5f8aaf9174145bf43e1784b8fa00dc71d885a804e5ee9fa40b16349c146fb778cdf2d3aff021dfff5b403b510d0d0455468aeb98622b137dae857553ccd8883a7bc37520e06e515d22c954eba5025b8cc57ee59418ce7dc6bc41556bdb36bbca3e8774301fbcaa3b83b220809560987815f65286764703de0f3d524400a19b159610b11ef3e
234c02ecbbfbafa3ed18510abd11fa724fcda2018a1a8342cf064bbde548b12b07df44ba7191d9606ef4081ffde5ad46a5069d9f7f543bedb9c861bf29c7e205132eda9382b0bc2c5c4b45f919cf3a9f1cb74151f6d551f4480c82b2cb24cc5b028aa76eb7b4ab24171ab3cdadb8356f
32510ba9a7b2bba9b8005d43a304b5714cc0bb0c8a34884dd91304b8ad40b62b07df44ba6e9d8a2368e51d04e0e7b207b70b9b8261112bacb6c866a232dfe257527dc29398f5f3251a0d47e503c66e935de81230b59b7afb5f41afa8d661cb
32510ba9aab2a8a4fd06414fb517b5605cc0aa0dc91a8908c2064ba8ad5ea06a029056f47a8ad3306ef5021eafe1ac01a81197847a5c68a1b78769a37bc8f4575432c198ccb4ef63590256e305cd3a9544ee4160ead45aef520489e7da7d835402bca670bda8eb775200b8dabbba246b130f040d8ec6447e2c767f3d30ed81ea2e4c1404e1315a1010e7229be6636aaa
3f561ba9adb4b6ebec54424ba317b564418fac0dd35f8c08d31a1fe9e24fe56808c213f17c81d9607cee021dafe1e001b21ade877a5e68bea88d61b93ac5ee0d562e8e9582f5ef375f0a4ae20ed86e935de81230b59b73fb4302cd95d770c65b40aaa065f2a5e33a5a0bb5dcaba43722130f042f8ec85b7c2070
32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd2061bbde24eb76a19d84aba34d8de287be84d07e7e9a30ee714979c7e1123a8bd9822a33ecaf512472e8e8f8db3f9635c1949e640c621854eba0d79eccf52ff111284b4cc61d11902aebc66f2b2e436434eacc0aba938220b084800c2ca4e693522643573b2c4ce35050b0cf774201f0fe52ac9f26d71b6cf61a711cc229f77ace7aa88a2f19983122b11be87a59c355d25f8e4
32510bfbacfbb9befd54415da243e1695ecabd58c519cd4bd90f1fa6ea5ba47b01c909ba7696cf606ef40c04afe1ac0aa8148dd066592ded9f8774b529c7ea125d298e8883f5e9305f4b44f915cb2bd05af51373fd9b4af511039fa2d96f83414aaaf261bda2e97b170fb5cce2a53e675c154c0d9681596934777e2275b381ce2e40582afe67650b13e72287ff2270abcf73bb028932836fbdecfecee0a3b894473c1bbeb6b4913a536ce4f9b13f1efff71ea313c8661dd9a4ce
315c4eeaa8b5f8bffd11155ea506b56041c6a00c8a08854dd21a4bbde54ce56801d943ba708b8a3574f40c00fff9e00fa1439fd0654327a3bfc860b92f89ee04132ecb9298f5fd2d5e4b45e40ecc3b9d59e9417df7c95bba410e9aa2ca24c5474da2f276baa3ac325918b2daada43d6712150441c2e04f6565517f317da9d3
271946f9bbb2aeadec111841a81abc300ecaa01bd8069d5cc91005e9fe4aad6e04d513e96d99de2569bc5e50eeeca709b50a8a987f4264edb6896fb537d0a716132ddc938fb0f836480e06ed0fcd6e9759f40462f9cf57f4564186a2c1778f1543efa270bda5e933421cbe88a4a52222190f471e9bd15f652b653b7071aec59a2705081ffe72651d08f822c9ed6d76e48b63ab15d0208573a7eef027
466d06ece998b7a2fb1d464fed2ced7641ddaa3cc31c9941cf110abbf409ed39598005b3399ccfafb61d0315fca0a314be138a9f32503bedac8067f03adbf3575c3b8edc9ba7f537530541ab0f9f3cd04ff50d66f1d559ba520e89a2cb2a83


target.txt(待解密文)
275a1ae0a6b5f8bfe8115441ed0ffa654acabc58de178c46800804bbe95aeb


#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <set>
using namespace std; 
int temptemp[1000] = {0}; //暂存16进制转为10进制的数值 
int tar[1000] = {0};      //存储target的10进制数 
int cyp[20][1000] = {0};  //存储10个密文的10进制数 
int tar_xor_cyp[20][1000] = {0}; //存储target与10个密文异或的结果 
int tar_len = 0;          //存储target的长度 
int tar_blank[1000] = {0}; 
//转换进制 
void transform_16_to_10(string s){
    int len = s.length();
    memset(temptemp,0,sizeof(temptemp));
    for(int i = 0 ; i < len/2 ; i++){
        int temp = 0;
        int t = 0;
        if(s[2*i] >= 'a' && s[2*i] <= 'f'){
            t = s[2*i] - 'a' + 10;
        }else{
            t = s[2*i] - '0';
        }
        temp += t * 16;
        if(s[2*i +1] >= 'a' && s[2*i +1] <= 'f'){
            t = s[2*i +1] - 'a' + 10;
        }else{
            t = s[2*i +1] - '0';
        }
        temp += t;
        temptemp[i] = temp;
    }
}

//将target分别与10个密文异或 
void do_xor(){
    ofstream out("tar_xor_cyp.txt");
    for(int j = 0 ; j < 10 ; j++){
        for(int i = 0 ; i < tar_len ; i++){
            tar_xor_cyp[j][i] = tar[i] ^ cyp[j][i];
            //out << (char)tar_xor_cyp[j][i] << " ";
            out << tar_xor_cyp[j][i] << " ";
        }
        out <<endl;
    }
    out.close();
}

//判断是否是字母 
bool is_char(int t){
    if((t>= 65&&t<=90) || (t>=97 && t <= 122)){
        return true;
    }
    return false;
}

//获取target是否是空格 
void get_blank_num(){
    set<int> set0;
    for(int i = 0 ; i < tar_len ; i++){
        set0.clear();
        for(int j = 0 ; j < 10 ; j++){
            if(is_char(tar_xor_cyp[j][i])){
                set0.insert(cyp[j][i]);
            }
        }
        if(set0.size() >= 2){
            //cout << "blank_cyp:" << i << " " << tar[i] << " " << set0.size() << endl;
            tar_blank[i] = 1;
        } 
    }
}


//计算第i个cyp的第j位是不是空格 
bool com_blank_of_cyp(int i, int j){  //第i个cyp第j位 
    set<int> set0;
    set0.clear();
    int xor_temp;
    xor_temp = tar[j] ^ cyp[i][j];
    if(is_char(xor_temp)){
        set0.insert(tar[j]);
    }
    for(int k = 0 ; k < 10 ; k++){
        if(k==i){
            continue;
        }else{
            xor_temp = cyp[i][j] ^ cyp[k][j];
            if(is_char(xor_temp)){
                set0.insert(cyp[k][j]);
            }   
        }
    }
    if(set0.size() >= 2 ){
        return true;
    }else{
        //cout << "dont know j:" << j <<endl;
        return false;
    }
}


//获取第i位字符 
void get_str_tar(){
    for(int i = 0 ; i < tar_len; i++){
        if(tar_blank[i] == 0){
            for(int j = 0 ; j < 10 ; j++){
                if(com_blank_of_cyp(j,i)){ //计算第i个cyp的第j位是不是空格
                    //cout << "get_str_tar:" << i <<endl;
                    //cout <<"cyp[i][j]:" << cyp[i][j] <<endl;
                    int mn = cyp[j][i] ^ tar[i];
                    //cout << "mn:" << mn <<endl;
                    if(is_char(mn)){
                        if(mn>= 65 && mn<=90){
                            tar[i] = mn + 32;
                            //cout << "tar[i]:" <<i << " "<< tar[i] <<endl; 
                        }else{
                            tar[i] = mn - 32;
                        }
                    }
                    //tar[i] = cyp[j][i] ^ tar[i] ^ 32;
                    break;
                }
            }
        }
        //对之前判定为空格的部分重新判断 
        else{
            for(int j = 0 ; j < 10 ; j++){
                if(com_blank_of_cyp(j,i)){
                    //cout << "get_str_tar:" << i <<endl;
                    int mn = cyp[j][i] ^ tar[i];
                    //cout << "mn:" << mn <<" " << cyp[j][i] <<" " << tar[i] <<" "<<endl;
                    if(is_char(mn)){
                        tar_blank[i] = 0;
                        if(mn>= 65 && mn<=90){
                            tar[i] = mn + 32;
                            //cout << "tar[i]:" <<i << " "<< tar[i] <<endl; 
                        }else{
                            tar[i] = mn - 32;
                        }
                        break;
                    }
                    //tar[i] = cyp[j][i] ^ tar[i] ^ 32;
                }
            }
        }
    }   
}

//输出原文 
void get_plantext(){
    ofstream out("plaintext.txt");
    for(int i = 0 ; i < tar_len; i++){
        if(tar_blank[i] == 1){
            out << " ";
            cout << " ";
        }else{
            out << (char)tar[i];
            cout << (char)tar[i];
        }
    }
    out.close();
}


int main(){
    ifstream in("target.txt");
    ofstream out("look.txt");
    string str;
    if(in){
        while(getline(in,str)){
            tar_len = str.length() / 2;
            //cout << "tar_len:" << tar_len << endl;
            transform_16_to_10(str);
            for(int i = 0 ; i < str.length()/2 ; i++){
                //获取target的16进制数值 
                tar[i] = temptemp[i];
                out << temptemp[i] << " ";
            }
            out <<endl;
        }
    }
    //cout << "target down" <<endl;
    in.close();

    //string str;
    ifstream in1("c1.txt");
    if(in1){
        int time = 0;
        while(getline(in1,str)){
            transform_16_to_10(str);
            for(int i = 0 ; i < str.length()/2 ; i++){
                //获取十段密文的16进制数值 
                cyp[time][i] = temptemp[i];
                out << temptemp[i] << " ";
            }
            out <<endl;
            time++;
        }
    }

    for(int i = 0 ; i < 10; i++){
        for(int j = 0 ; j < tar_len; j++){
            out << cyp[i][j] <<" ";
        }
        out <<endl;
    }

    in1.close();
    //cout << "cyp down" <<endl;
    out.close();

    do_xor();       //将target与十段密文异或 

    get_blank_num();//获取target中空格的位置 

    get_str_tar();  //获取target中的字母 

    get_plantext(); //输出原文 

    return 0;
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值