Requirements
请用 Crypto++实现一个程序,寻找 SHA-1 的 “近似碰撞”。也就是说,要找到两个输入a 和 b,满足 a≠b,但是 SHA1(a)和 SHA1(b)有尽可能多的对应比特相同。请说明你找到的 SHA1(a)和 SHA1(b)有多少个比特相同。请提交找到的 a 和 b 的值,以及它们的 Hash 值。
Compilation Options
g++ SHA1.cpp -o SHA1 -lcryptopp
Description
According to birthday attack, I calculate that the probability of no less than 113 bits’ partial collision with 10,000,000 attempts is 60.88% and 31.57% for 114 bits. With the help of Mathematica, I get the exact probability. Here is the source code:
In[1]:= p = N[Sum[Binomial[160, i]/(2^160), {i, 113, 160}]]
Out[1]= 9.38456*10^-8
In[2]:= N[1 - (1 - p)^10000000]
Out[2]= 0.608768
In[3]:= p = N[Sum[Binomial[160, i]/(2^160), {i, 114, 160}]]
Out[3]= 3.79404*10^-8
In[4]:= N[1 - (1 - p)^10000000]
Out[4]= 0.315731
Source Code
#include <iostream>
#include <string.h>
#include <time.h>
#include <cryptopp/cryptlib.h>
#include <cryptopp/sha.h>
#include <cryptopp/hex.h>
using namespace std;
using namespace CryptoPP;
const int SIZE_CHAR = 32;
const int SIZE_SPACE = 10000000;
const int UP_BOUND = 113;
const char CCH[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
string gen_rand_str();
string calculate_hash(string);
string convert_hex_binary(string);
int main() {
srand((unsigned)time(NULL));
int no = SIZE_SPACE;
while (no--) {
string str1 = gen_rand_str();
string str2 = gen_rand_str();
string hash1 = calculate_hash(str1);
string hash2 = calculate_hash(str2);
string binary_str1 = convert_hex_binary(hash1);
string binary_str2 = convert_hex_binary(hash2);
int counter = 0;
for (int i = 0; i < 160; i++) {
if (binary_str1[i] == binary_str2[i]) counter++;
}
if (counter > UP_BOUND) {
cout << str1 << ": " << hash1 << endl;
cout << str2 << ": " << hash2 << endl;
cout << counter << endl;
}
}
return 0;
}
string gen_rand_str() {
char ch[SIZE_CHAR + 1] = {0};
for (int i = 0; i < SIZE_CHAR; ++i) {
int x = rand() / (RAND_MAX / (sizeof(CCH) - 1));
ch[i] = CCH[x];
}
return ch;
}
string calculate_hash(string str) {
int bs_size = SIZE_CHAR * sizeof(wchar_t);
byte* bytes_string = new byte[bs_size];
int n = 0; //real bytes count
for (int i = 0; i < SIZE_CHAR; i++) {
wchar_t wcharacter = str[i];
int high_byte = wcharacter & 0xFF00;
high_byte = high_byte >> 8;
int low_byte = wcharacter & 0xFF;
if (high_byte != 0) {
bytes_string[n++] = (byte)high_byte;
}
bytes_string[n++] = (byte)low_byte;
}
SHA1 sha1;
string hash;
StringSource ss(bytes_string, n, true, new HashFilter(sha1, new HexEncoder(new StringSink(hash))));
return hash;
}
string convert_hex_binary(string str) {
string binary_str;
for (int i = 0; i < str.size(); i++) {
if (str[i] == '0') {
binary_str += "0000";
}
else if (str[i] == '1') {
binary_str += "0001";
}
else if (str[i] == '2') {
binary_str += "0010";
}
else if (str[i] == '3') {
binary_str += "0011";
}
else if (str[i] == '4') {
binary_str += "0100";
}
else if (str[i] == '5') {
binary_str += "0101";
}
else if (str[i] == '6') {
binary_str += "0110";
}
else if (str[i] == '7') {
binary_str += "0111";
}
else if (str[i] == '8') {
binary_str += "1000";
}
else if (str[i] == '9') {
binary_str += "1001";
}
else if (str[i] == 'A') {
binary_str += "1010";
}
else if (str[i] == 'B') {
binary_str += "1011";
}
else if (str[i] == 'C') {
binary_str += "1100";
}
else if (str[i] == 'D') {
binary_str += "1101";
}
else if (str[i] == 'E') {
binary_str += "1110";
}
else if (str[i] == 'F') {
binary_str += "1111";
}
}
return binary_str;
}
Conclusion
I find a partial collision of 114 bits.
string 1
wjVaOoXXTn3BlSfmeHsjKlDIhkIV2mJe
hash1
38AB61B399F8FFB4AB159983C3FD757EED9B5CAD
string 2
7zjH48XHmH8J7xM15IZT0CJgInvjGryR
hash2
100A253FD8B06795A35DDDABE7F92466869A0E95