diff --git a/hack.h b/hack.h new file mode 100644 index 0000000..e139db5 --- /dev/null +++ b/hack.h @@ -0,0 +1,290 @@ +#ifndef DES6_HACK_H +#define DES6_HACK_H +#include +#include +#include "const.h" +#include "did_table.h" +#include +#include +#include +#include + +using namespace std; + +independent_bits_engine random_engine; + +static DidTable did; + +class DesHackHelper { +private: + ull l_match; + ull r_match; + size_t avail_index_num; + int avail_index[8]; + +public: + DesHackHelper(int mode) { + if (mode == 1) { + l_match = 0x40080000; + r_match = 0x04000000; + avail_index_num = 5; + avail_index[0] = 2; + avail_index[1] = 5; + avail_index[2] = 6; + avail_index[3] = 7; + avail_index[4] = 8; + } + else { + l_match = 0x00200008; + r_match = 0x00000400; + avail_index_num = 2; + avail_index[0] = 1; + avail_index[1] = 4; + } + } + + bool inputCheck(const ull& inA, const ull& inB) { + ull inD = calcIp(inA) ^ calcIp(inB); + ull l = left32(inD); + ull r = right32(inD); + return (l == l_match && r == r_match); + } + + bool availCheck(const ull& inA, const ull& inB, const ull& outA, const ull& outB) { + return hack(inA, inB, outA, outB, nullptr); + } + + bool hack(const ull& inA, + const ull& inB, + const ull& outA, + const ull& outB, + vector >* ret_key = nullptr) { + if (!inputCheck(inA, inB)) return false; + ull outD = calcInvPi(outA ^ outB); + ull r6D = right32(outD); + ull c = calcInvPerm(r6D ^ r_match); + + ull eA = calcExt(left32(calcInvPi(outA))); + ull eB = calcExt(left32(calcInvPi(outB))); + ull eD = eA ^ eB; + + for (unsigned int i = 0; i < avail_index_num; i++) { // each sbox available + int index = avail_index[i] - 1; + + int shift_e = (7 - index) * 6; + int sub_eD = (int)((eD & (63ULL << shift_e)) >> shift_e); + int sub_eA = (int)((eA & (63ULL << shift_e)) >> shift_e); + + int shift_c = (7 - index) * 4; + int sub_c = (int)((c & (15ULL << shift_c)) >> shift_c); + + vector cdt; // candidate + did.get(index, sub_eD, sub_c, cdt); + if (cdt.empty()) { + return false; + } + if (ret_key != nullptr) { + set t; + t.clear(); + for (unsigned int j = 0; j < cdt.size(); j++) { + int key_maybe = cdt[j] ^ sub_eA; + if ((*ret_key)[index].count(key_maybe)) { + t.insert(key_maybe); + } + } + (*ret_key)[index].clear(); + for (int j : t) { + (*ret_key)[index].insert(j); + } + } + } + return true; + } + + void constructCipherPlaintexts(const ull& key, ull& inA, ull& inB, ull& outA, ull& outB, ull in = 0) {// 给定key构造一组明密文对 + while (true) { + if (in == 0) + inA = random_engine(); + else { + inA = in; // 使用给定的明文 + } + ull diff = (l_match << 32) | r_match; + inB = calcInvIp(calcIp(inA) ^ diff); + + pre_l3 = 0; + outA = desEncrypt(inA, key); + outB = desEncrypt(inB, key); + + if (pre_l3 == ((r_match << 32) | l_match)) { + if (availCheck(inA, inB, outA, outB)) { + //找到了合适的明密文对 + printf("--- new cp ---\n"); + print_long_hex(inA); + print_long_hex(inB); + print_long_hex(outA); + print_long_hex(outB); + return; + } + } + } + } +}; + + +class DesHacker { +private: + struct PairCp { // a pair of cipher and plaintext 一组明文和密文 + ull inA, inB, outA, outB; + PairCp(const ull& inA, const ull& inB, const ull& outA, const ull& outB) : + inA(inA), inB(inB), outA(outA), outB(outB) {} + }; + vector cp_m1; // 满足第一种差分特征的明密文对 + vector cp_m2; // 满足第二种差分特征的明密文对 + DesHackHelper hackerA; + DesHackHelper hackerB; + vector > ret_sub_key; // 输入到每个S盒可能的子密钥。一共有64中可能性 + vector enum_binary_position; // 需要枚举的14个二进制位的位置 + bool found_key; // 是否找到密钥 + ull ret_key; // 存放找到的密钥 + + ull invPc(ull pc2_out) { + ull pc2_in = calcInvPc2(pc2_out); + ull l = left28(pc2_in); + ull r = right28(pc2_in); + for (int j = 0; j < 10; j++) { + l = (0x0fffffff & (l >> 1)) | ((0x00000001 & l) << 27); // right shift + r = (0x0fffffff & (r >> 1)) | ((0x00000001 & r) << 27); + } + ull pc1_out = (l << 28) | r; + ull pc1_in = calcInvPc1(pc1_out); + return pc1_in; + } + + int cur_process = 0; // 当前进度 + int max_process = 0; + + void binaryEnum(ull num) { // 对其他二进制位进行枚举 + cur_process++; + if (cur_process % 100 == 0) + printf("process: %d/%d\n", cur_process, max_process); + if (cur_process > max_process) { + cur_process = max_process; + } + int enum_max = (1 << enum_binary_position.size()) - 1; + // if ((target_key & invPc(0xfff03fffffff)) == num) + for (int i = 0; i < enum_max; i++) { + int bin = i; //枚举的14位二进制数 + ull key = num; + for (int j : enum_binary_position) { + if (bin & 1) { + key |= (1ULL << j); + } + bin >>= 1; + } + if (desEncrypt(cp_m1[0].inA, key) == cp_m1[0].outA) { + ret_key = key; + found_key = true; + break; + } + } + } + + void combine(int deep, ull num) { //对每个S盒可能的子密钥进行组合,使用DFS + if (deep >= 8) { + ull out = invPc(num); + binaryEnum(out); + return; + } + if (deep == 2) { + combine(deep + 1, num); + return; + } + for (int i : ret_sub_key[deep]) { + int shift = (7 - deep) * 6; + ull cur = num | (((ull)i) << shift); + combine(deep + 1, cur); + if (found_key) return; + } + } + +public: + // ull target_key; + DesHacker() :hackerA(1), hackerB(2), found_key(false), ret_key(0) { + random_engine.seed((ull)time(nullptr)); + ret_sub_key.resize(8); + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 64; j++) { + ret_sub_key[i].insert(j); // 一开始存放所有可能的情况,随着分析过程逐步筛减。 + } + } + cp_m1.clear(); + cp_m2.clear(); + enum_binary_position.clear(); + ull enum_mask = calcInvPc1((1ULL << 56) - 1); + ull pc_mask = invPc(0xfff03fffffff) ^ (~enum_mask); // 其中等于0的二进制位是需要最后时枚举的,一共14位 + ull t = pc_mask; + for (int i = 0; i < 64; i++) { + if (!(t & 1)) + enum_binary_position.push_back(i); + t >>= 1; + } + } + + bool addCipherPlaintexts(ull in1, ull in2, ull out1, ull out2) { + if (hackerA.inputCheck(in1, in2)) { + cp_m1.push_back(PairCp(in1, in2, out1, out2)); + return true; + } + else if (hackerB.inputCheck(in1, in2)) { + cp_m2.push_back(PairCp(in1, in2, out1, out2)); + return true; + } + else + return false; + } + + bool hack() { + found_key = false; + if (cp_m1.empty() || cp_m2.empty()) { + printf("At least one pair of cipher and plaintexts for each mode...\n"); + return false; + } + + for (unsigned int i = 0; i < cp_m1.size(); i++) { + if (!hackerA.hack(cp_m1[i].inA, cp_m1[i].inB, cp_m1[i].outA, cp_m1[i].outB, &ret_sub_key)) + return false; + } + for (unsigned int i = 0; i < cp_m2.size(); i++) { + if (!hackerB.hack(cp_m2[i].inA, cp_m2[i].inB, cp_m2[i].outA, cp_m2[i].outB, &ret_sub_key)) + return false; + } + + max_process = 1; // 用于展示计算进度 + for (int i = 0; i < 8; i++) { + if (i == 2) continue; + max_process *= ret_sub_key[i].size(); + } + + combine(0, 0ULL); // 对每个可能的密钥进行枚举 + return found_key; + } + + ull getKey() { + if (found_key) + return ret_key; + else { + printf("Key not found...\n"); + return 0; + } + } +}; + +void constructCipherPlaintexts(const ull& key, int mode, + ull& inA, ull& inB, ull& outA, ull& outB, + const ull& given_inA = 0) { + DesHackHelper hacker(mode); + hacker.constructCipherPlaintexts(key, inA, inB, outA, outB, given_inA); +} + +#endif //DES6_HACK_H +#pragma once