You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

291 lines
9.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#ifndef DES6_HACK_H
#define DES6_HACK_H
#include <iostream>
#include <random>
#include "const.h"
#include "did_table.h"
#include <ctime>
#include <cassert>
#include <set>
#include <algorithm>
using namespace std;
independent_bits_engine<default_random_engine, 64, ull> 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<set<int> >* 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<int> cdt; // candidate
did.get(index, sub_eD, sub_c, cdt);
if (cdt.empty()) {
return false;
}
if (ret_key != nullptr) {
set<int> 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) {// <20><><EFBFBD><EFBFBD>key<65><79><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD>
while (true) {
if (in == 0)
inA = random_engine();
else {
inA = in; // ʹ<>ø<EFBFBD><C3B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
}
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)) {
//<2F>ҵ<EFBFBD><D2B5>˺<EFBFBD><CBBA>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD>
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 һ<><D2BB><EFBFBD><EFBFBD><EFBFBD>ĺ<EFBFBD><C4BA><EFBFBD><EFBFBD><EFBFBD>
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<PairCp> cp_m1; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>ֲ<EFBFBD><D6B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD>
vector<PairCp> cp_m2; // <20><><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD><DAB6>ֲ<EFBFBD><D6B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD>
DesHackHelper hackerA;
DesHackHelper hackerB;
vector<set<int> > ret_sub_key; // <20><><EFBFBD>뵽ÿ<EBB5BD><C3BF>S<EFBFBD>п<EFBFBD><D0BF>ܵ<EFBFBD><DCB5><EFBFBD><EFBFBD><EFBFBD>Կ<EFBFBD><D4BF>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>64<36>п<EFBFBD><D0BF><EFBFBD><EFBFBD><EFBFBD>
vector<int> enum_binary_position; // <20><>Ҫö<D2AA>ٵ<EFBFBD>14<31><34><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>λ<EFBFBD><CEBB>
bool found_key; // <20>Ƿ<EFBFBD><C7B7>ҵ<EFBFBD><D2B5><EFBFBD>Կ
ull ret_key; // <20><><EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD><EFBFBD>Կ
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; // <20><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>
int max_process = 0;
void binaryEnum(ull num) { // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD>ö<EFBFBD><C3B6>
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; //ö<>ٵ<EFBFBD>14λ<34><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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) { //<2F><>ÿ<EFBFBD><C3BF>S<EFBFBD>п<EFBFBD><D0BF>ܵ<EFBFBD><DCB5><EFBFBD><EFBFBD><EFBFBD>Կ<EFBFBD><D4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϣ<EFBFBD>ʹ<EFBFBD><CAB9>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); // һ<><D2BB>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>п<EFBFBD><D0BF>ܵ<EFBFBD><DCB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ŷ<EFBFBD><C5B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɸ<EFBFBD><C9B8><EFBFBD><EFBFBD>
}
}
cp_m1.clear();
cp_m2.clear();
enum_binary_position.clear();
ull enum_mask = calcInvPc1((1ULL << 56) - 1);
ull pc_mask = invPc(0xfff03fffffff) ^ (~enum_mask); // <20><><EFBFBD>е<EFBFBD><D0B5><EFBFBD>0<EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>ʱö<CAB1>ٵģ<D9B5>һ<EFBFBD><D2BB>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; // <20><><EFBFBD><EFBFBD>չʾ<D5B9><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
for (int i = 0; i < 8; i++) {
if (i == 2) continue;
max_process *= ret_sub_key[i].size();
}
combine(0, 0ULL); // <20><>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD>ܵ<EFBFBD><DCB5><EFBFBD>Կ<EFBFBD><D4BF><EFBFBD><EFBFBD>ö<EFBFBD><C3B6>
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