Skip to content

Instantly share code, notes, and snippets.

@yohanes
Created April 15, 2014 03:24
Show Gist options
  • Save yohanes/10699541 to your computer and use it in GitHub Desktop.
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.
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