Inti dari solusinya adalah berdasarkan paper: "Reconstructing RSA Private Keys from Random Key Bits"
http://cseweb.ucsd.edu/~hovav/papers/hs09.html
Ada source code yang bisa didownload di situ, tapi sourcenya perlu dimodifikasi. Berikut ini adalah modifikasi yang saya lakukan:
This file contains hidden or 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; |
Saya menambahkan opsi -x <corrupted_file>. File input harus diperbaiki dulu supaya nilai modulus benar. Ini bisa didapatkan dari public key:
openssl pkey -pubin -in public.pub -text -noout
Contoh file input berdasarkan soal:
This file contains hidden or 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
Private-Key: (1024 bit) | |
modulus : | |
00:db:fa:bd:b1:49:5d:32:76:e7:62:6b:84:79:6e: | |
9f:c2:0f:a1:3c:17:44:f1:0c:8c:3f:3e:3c:2c:60: | |
40:c2:e7:f3:13:df:a3:d1:fe:10:d1:ae:57:7c:fe: | |
ab:74:52:aa:53:10:2e:ef:7b:e0:09:9c:02:25:60: | |
e5:7a:5c:30:d5:09:40:64:2d:1b:09:7d:d2:10:9a: | |
e0:2f:2d:cf:f8:19:8c:d5:a3:95:fc:ac:42:66:10: | |
78:48:b9:dd:63:c3:87:d2:53:8e:50:41:53:43:04: | |
20:33:ea:09:c0:84:15:5e:65:2b:0f:06:23:40:d5: | |
d4:71:7a:40:2a:9d:80:6a:6b | |
publicExponent : 65537 (0x10001) | |
privateExponent : | |
f: : : a: a:9 :e : : 1: 2: : :e : :1 : | |
3 : 1: : : : a: :2 : : : : : : : : | |
9 : a: : : : : : 5:c1: 0:b : 3: 2:0 :b0: | |
:c : f: :f : :d2: : : d: :1 : :3 : : | |
: : :0 : 3: : : 5:c : :3 :6 : :a4: : | |
4 : : :8f: : : : : a: : c:5f: 7: 6: : | |
1: : b: : 5: :84:0 :b : f: 3: : : 4: 6: | |
: : 5:1 : :d : : f: : c: : : 5: : : | |
:e :f4:b :4 :8e: : | |
prime1 : | |
00: :6 : 1:1 : :b :0 : 2:c : b:2 : : a:1 : | |
c : : 0: :28:0 : :cd: : 8: : :20: c: : | |
: 5: :9 : c:3 : : : a:b :c :3 : : : : | |
f: : : f: 1: 1:b : : c:f : a: :a : : : | |
a:38: :6 : | |
prime2 : | |
:e : :d :2 :6 : 7: :33: :46: : 4: : : | |
:5 : : 4:6 : : 6: : e:d : : : 9: e:1 : | |
: : : : :0 : : : :c : 5: : :a :0 : | |
6 : : :8 :e9:f : f:7 :5 : e:1 : : : 1:9 : | |
4:d :e9: 6: | |
exponent1: | |
9:d : 5: :c :67: : 9: : : : d: : : 3: | |
f:6 : 0:c : :6 :ad: :2 :d :d : : :0 :7 : | |
:5 : 6: : 5:1 :f : d: : 2: : : 2: 3: : | |
9 : : : : :67: 3: :4 : 7:c0: 4:b :c :f : | |
:3 :b : 1 | |
exponent2 : | |
1 : 9:47:8 : : : : 3: : : :6 : : :0 : | |
e :e :8 : : : : : 1:c :74: : :d : 9:3 : | |
5 : e: : 2: :7 : 2:c : : : : :5 : : 8: | |
: :c : : 1: :a : : 9: 5: : 3: : e:c : | |
: : 6: | |
coefficient: | |
:a :d :84:f : : c:43: : : : 6: : : : | |
: b: :c :9 : : : : : : 4:23:8b: :6 : | |
2 : 2: : : 7:5b: : : :7 : : : : : : | |
f1:7 :1 : :f : a: : 5: : : : 5: : c: 1: | |
:48: b: 6: |
Jalankan program:
./rsa -x corrupted.pem
Hasilnya: solution0.asn
Ubah ke format der:
openssl asn1parse -genconf solution0.asn -out newkey.der
Check bahwa keynya benar, dan tuliskan ke PEM:
openssl rsa -in newkey.der -inform der -text -check > key.pem
Decrypt pesan:
openssl rsautl -decrypt -in encrypted -out plaintext.txt -inkey key.pem
Hasilnya adalah:
crypt0>>>f0rensics3~
please send me rsa.c source code that you modified. hw10d234@gmail.com. thanks.
ReplyDeleteAs find a way to|you probably can} see we now have chosen three different ways of calculating ABV but the number that we give the highest worth in our star rankings is ABV100. 온라인 카지노 We do that because of|as a result of} we believe that a $100 casino welcome bonus is what’s related to most players. Some individuals just wish to play at no cost, some wants to play huge, but most of us wants to put some cash on the table but not too much quantity of}. Then a $100 casino bonus is an even and good number that works for most of us.
ReplyDelete