网上瞎逛总能碰到点有趣的事情,看到一个名叫谢益辉的博主的自我简介,其中有一段是这样的:

我很少用 QQ,因为即时聊天会打乱时间的完整性,我希望能有整块的时间集中做事情,而不是盯着几个聊天窗口打着零碎的句子。我的 QQ 号的 MD5 码是 ff8fb48d51329ad82a306fa309b97e3a(将 QQ 号写入文件、不带换行符的文件的 MD5 码)。我的主要联系方式是电子邮件。

哈希码的反推只能是硬碰,暴力破拆,好在我们知道QQ号都是数字组成,范围小了很多。我也好奇解出这个号要花多长时间,正好用Rust练习一下。程序非常简单,但里面有几个坑需要提一下。

首先使用的库是md-5,而不是md5,不清楚2个库是怎么回事。

[dependencies]
md-5 = "0.10.6"

程序非常简单,因为不知道计算量多大,我一开始查找范围很小,7位数字,后来范围慢慢扩大。另外,debug运行模式和release模式的效率也是天差地别,需要以release编译和运行:

$ cargo build --release 

测试发现7位数字可以在1.2秒左右找完,这个效果比较惊人。那8位大约12秒,9位120秒,10位1200秒(20分钟)。于是我就先找9位数,想如果再找不到,就要用多线程了。好在这个QQ号码只有9位:

peter@~/workspace/md5force $ ./target/release/md5force 
Found it: 250145077
Time: 29.146758416s

代码还是比较简单的:

use md5::{Digest, Md5};
use std::time::Instant;

fn find_num_md5(target_hash: &str) -> u64 { 
    let mut found_number = 0; 
    let startnum: u64 = 1000;
    let endnum: u64 = 999999999;

    
    for num in startnum..=endnum {
        let numstr = num.to_string();
        
        let mut hasher = Md5::new();
        hasher.update(numstr);
        let result = hasher.finalize();
        
        let hash_str = format!("{:x}", result);
        
        if hash_str == target_hash { 
            found_number = num;
            break; 
        }
    }
 
    found_number 
}

fn main() {
    let start_time = Instant::now();
    let target_hash = "ff8fb48d51329ad82a306fa309b97e3a"; 
    let num = find_num_md5(target_hash); 
    
    println!("Found it: {num}"); 
    let duration = start_time.elapsed();    
    println!("Time: {:?}", duration);
}


#[cfg(test)]
mod tests {
    use md5::{Digest, Md5};

    use crate::find_num_md5;
    #[test]
    fn test_verify_1() {
        let num1 = b"5068775";
        let num1_hash = "ee5ccbb2e45d7f5f6af991cb93de6274"; 

        let mut hasher = Md5::new();
        hasher.update(num1);
        let result = hasher.finalize();
        let result_hex = format!("{:x}", result);

        assert_eq!(num1_hash, result_hex);
    }

    #[test]
    fn test_find_num_md5() {
        let target_hash = "ee5ccbb2e45d7f5f6af991cb93de6274"; 
        let num = find_num_md5(target_hash); 

        assert_eq!(num, 5068775);
    }

    #[test]
    fn test_find_num_md5_not_found() {
        let target_hash = "ee5ccbb2e45d7f5f6af991cb93de6270"; 
        let num = find_num_md5(target_hash); 

        assert_eq!(num, 0);
    }
}