Created
April 15, 2014 03:24
-
-
Save yohanes/10699541 to your computer and use it in GitHub Desktop.
diff against http://cseweb.ucsd.edu/~hovav/papers/hs09.html for recreating private key from corrupted file. note you must fix the modulus from public key (openssl pkey -pubin -in public.pub -text -noout). See http://rentjong-team.blogspot.com/ for more info.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -ruN rsabits-orig/rsa.C rsabits/rsa.C | |
--- rsabits-orig/rsa.C 2014-04-15 10:09:53.406244277 +0700 | |
+++ rsabits/rsa.C 2014-04-15 10:15:55.666047590 +0700 | |
@@ -40,6 +40,8 @@ | |
// C: | |
#include <sys/types.h> | |
+#include <stdio.h> | |
+#include <string.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <fcntl.h> | |
@@ -47,9 +49,12 @@ | |
#include <sys/time.h> | |
// *shudder* STL: | |
#include <iostream> | |
+#include <sstream> | |
#include <fstream> | |
#include <iomanip> | |
#include <queue> | |
+#include <vector> | |
+#include <string> | |
// NTL: | |
#include <NTL/ZZ.h> | |
#include <NTL/LLL.h> | |
@@ -148,6 +153,150 @@ | |
file >> priv.dq1; | |
} | |
+std::string hextab = "0123456789abcdef"; | |
+ | |
+int hexval(char c) | |
+{ | |
+ return hextab.find(c); | |
+} | |
+ | |
+//we need strip 0 in case it is corrupted | |
+void read_corrupted_value(vector<string> &lines, unsigned int &start, ZZ &val, ZZ &mask, bool stripzero) | |
+{ | |
+ std::string hex; | |
+ | |
+ while (start < lines.size()) { | |
+ if (lines[start][0]!=' ') { | |
+ break; | |
+ } | |
+ std::string line = lines[start].substr(4); | |
+ //-1: ignore last ':' | |
+ for (unsigned int i = 0; i < line.size()-1; i+=3) { | |
+ std::string part = line.substr(i, 2); | |
+ hex = part + hex; | |
+ } | |
+ start++; | |
+ } | |
+ | |
+ if (stripzero) { | |
+ hex = hex.substr(0, hex.size()-2); | |
+ } else { | |
+ //if it ends with 00 | |
+ if (hex[hex.size()-1]=='0' && hex[hex.size()-2]=='0') { | |
+ hex = hex.substr(0, hex.size()-2); | |
+ } | |
+ } | |
+ | |
+ vector<unsigned char> bytes; | |
+ | |
+ printf("hex = %s\n", hex.c_str()); | |
+ int current_bit = 0; | |
+ | |
+ clear(mask); | |
+ | |
+ for (unsigned int i =0; i < hex.size(); i+=2) { | |
+ char c1 = hex[i]; | |
+ char c2 = hex[i+1]; | |
+ if (c1!=' ' && c2!=' ') { | |
+ unsigned char v = hexval(c1) << 4 | hexval(c2); | |
+ bytes.push_back(v); | |
+ for (int j = 0; j < 8; j++) { | |
+ SetBit(mask, current_bit + j); | |
+ } | |
+ } else if (c1==' ' && c2==' ') { | |
+ bytes.push_back(0); | |
+ } else if (c1==' ') { //eg: ' f' | |
+ bytes.push_back(hexval(c2)); | |
+ //only first 4 bits known | |
+ for (int j = 0; j < 4; j++) { | |
+ SetBit(mask, current_bit + j); | |
+ } | |
+ } else { //c2 ==' ', eg: 'f ' | |
+ bytes.push_back(hexval(c1)<<4); | |
+ //only last 4 bits known | |
+ for (int j = 4; j < 8; j++) { | |
+ SetBit(mask, current_bit + j); | |
+ } | |
+ | |
+ } | |
+ current_bit += 8; | |
+ } | |
+ | |
+ ZZFromBytes(val, &bytes[0], bytes.size()); | |
+ | |
+// cout << val; | |
+// printf("\n"); | |
+// cout << mask; | |
+// printf("\n"); | |
+ | |
+} | |
+ | |
+void | |
+read_corrupted_file(char *filename, | |
+ rsa_pub &pub, | |
+ rsa_priv &priv, | |
+ int &bits, | |
+ rsa_mask &mask) | |
+{ | |
+ ifstream file(filename); | |
+ if (!file) | |
+ { | |
+ cerr << "Error: can't open input file " << filename << endl; | |
+ exit(1); | |
+ } | |
+ vector<string> lines; | |
+ ZZ dummymask; | |
+ | |
+ while(!file.eof()) { | |
+ std::string tmp; | |
+ getline(file, tmp); | |
+ lines.push_back(tmp); | |
+ } | |
+ | |
+ unsigned int start = 0; | |
+ //too lazy to parse | |
+ //Private-Key: (N bit) | |
+ if (lines[start].find("1024")!=string::npos) { | |
+ bits = 1024; | |
+ cout << "1024 BITS\n"; | |
+ } else if (lines[start].find("2048")!=string::npos) { | |
+ bits = 2048; | |
+ cout << "2048 BITS\n"; | |
+ } else { | |
+ cout << "UNKNOWN NUMBER OF BITS\n"; | |
+ exit(0); | |
+ } | |
+ | |
+ start += 2;//start from line 2, read modulus (modulus is NOT corrupted, if it is corrupted, please copy from public key) | |
+ | |
+ cout << "Modulus \n"; | |
+ read_corrupted_value(lines, start, pub.N, dummymask, true); | |
+ //todo: should parse this: | |
+ pub.e = 65537; | |
+ start++; | |
+ cout << "Private exponent \n"; | |
+ start++; | |
+ read_corrupted_value(lines, start, priv.d, mask.d, true); | |
+ start++; | |
+ cout << "p\n"; | |
+ | |
+ read_corrupted_value(lines, start, priv.p, mask.p, true); | |
+ start++; | |
+ cout << "q\n"; | |
+ | |
+ read_corrupted_value(lines, start, priv.q, mask.q, true); | |
+ start++; | |
+ cout << " dp1\n"; | |
+ read_corrupted_value(lines, start, priv.dp1, mask.dp1, false); | |
+ start++; | |
+ cout << " dq1\n"; | |
+ read_corrupted_value(lines, start, priv.dq1, mask.dq1, false); | |
+ | |
+ //exit(0); | |
+} | |
+ | |
+ | |
+ | |
void | |
make_rsa_key(rsa_pub &pub, rsa_priv &priv, long bits, ZZ& e) | |
{ | |
@@ -544,6 +693,7 @@ | |
"\t-t\tgives timing information\n" | |
"\t-w W\tsets panic width to W (default is -1, meaning no limit)\n" | |
"\t-i FILE\treads RSA key from FILE\n" | |
+ "\t-x FILE\tfix RSA key from FILE\n" | |
"\t-h\tprint this message\n"); | |
} | |
@@ -573,6 +723,49 @@ | |
SetSeed(ZZFromBytes(randbuf, RANDBYTES)); | |
} | |
+ | |
+int write_solution(rsa_priv &priv, rsa_pub &pub) | |
+{ | |
+ static int ctr = 0; | |
+ stringstream ss; | |
+ ss << "solution" << ctr << ".asn"; | |
+ | |
+ | |
+ ZZ coeff; | |
+ | |
+ if (InvModStatus(coeff, priv.q, priv.p)!=0) { | |
+ cout << " not a solution \n"; | |
+ return 0; | |
+ } | |
+ | |
+ priv.d = InvMod(pub.e, (priv.p-1)*(priv.q-1)); | |
+ | |
+ ofstream output(ss.str().c_str()); | |
+ if (output.is_open()) { | |
+ output << "asn1=SEQUENCE:rsa_key\n\n"; | |
+ output << "[rsa_key]\nversion=INTEGER:0\n"; | |
+ output << "modulus=INTEGER:" << pub.N << "\n"; | |
+ output << "pubExp=INTEGER:" << pub.e << "\n"; | |
+ output << "privExp=INTEGER:" << priv.d << "\n"; | |
+ output << "p=INTEGER:" << priv.p << "\n"; | |
+ output << "q=INTEGER:" << priv.q << "\n"; | |
+ ZZ e1; | |
+ ZZ e2; | |
+ | |
+ rem(e1, priv.d, priv.p-1); | |
+ rem(e2, priv.d, priv.q-1); | |
+ output << "e1=INTEGER:" << e1 << "\n"; | |
+ output << "e2=INTEGER:" << e2 << "\n"; | |
+ ZZ coeff = InvMod(priv.q, priv.p); | |
+ output << "coeff=INTEGER:" << coeff << "\n"; | |
+ | |
+ output.close(); | |
+ } | |
+ ctr++; | |
+ return 1; | |
+} | |
+ | |
+ | |
int | |
main(int argc, char *argv[]) | |
{ | |
@@ -586,9 +779,11 @@ | |
E = 65537; | |
char *filename = NULL; | |
+ bool fix_file = false; | |
int c; | |
- while((c = getopt(argc, argv, "e:n:f:svtw:i:h")) != EOF) | |
+ | |
+ while((c = getopt(argc, argv, "e:n:f:svtw:i:x:h")) != EOF) | |
switch (c) | |
{ | |
case 'e': | |
@@ -615,6 +810,10 @@ | |
case 'i': | |
filename = optarg; | |
break; | |
+ case 'x': | |
+ fix_file = true; | |
+ filename = optarg; | |
+ break; | |
case 'h': | |
usage(); | |
exit(0); | |
@@ -623,11 +822,16 @@ | |
if (do_seed) | |
seed(); | |
- if (filename) | |
- read_rsa_key(filename, pub, key, MODULUS_BITS); | |
- else | |
- make_rsa_key(pub, key, MODULUS_BITS, E); | |
- degrade_rsa_key(mask, key, delta); | |
+ if (!fix_file) { | |
+ if (filename) | |
+ read_rsa_key(filename, pub, key, MODULUS_BITS); | |
+ else | |
+ make_rsa_key(pub, key, MODULUS_BITS, E); | |
+ degrade_rsa_key(mask, key, delta); | |
+ } else { | |
+ read_corrupted_file(filename, pub, key, MODULUS_BITS, mask); | |
+ } | |
+ | |
double start_time = 0.0, mid_time = 0.0, stop_time = 0.0; | |
@@ -828,6 +1032,10 @@ | |
while (!Q_gh.empty()) | |
{ | |
item &soln = Q_gh.front(); | |
+ if (write_solution(soln.key, pub)) { | |
+ found = 1; | |
+ } | |
+ | |
if (soln.key.p == key.p) | |
{ | |
found = 1; | |
@@ -839,6 +1047,11 @@ | |
while (!Q_hg.empty()) | |
{ | |
item &soln = Q_hg.front(); | |
+ | |
+ if (write_solution(soln.key, pub)) { | |
+ found = 1; | |
+ } | |
+ | |
if (soln.key.p == key.p) | |
{ | |
found = 1; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment