ntlm_hash/
lib.rs

1//! This crate inplements the ntlm hash in pure rust.
2//!
3//! # Usage :
4//! 
5//! ```rust
6//!use ntlm_hash::*
7//!println!("{}", ntlm_hash("some_string"))
8//! ```
9//! # Limitation :
10//! 	This crate hashes only strings of maximum 31 characters long.
11
12// this implementation is just a translated version of the one available here : https://openwall.info/wiki/john/NTLM
13
14// a comment that I left out from the original c inplementation :
15/* 
16Written by Alain Espinosa <alainesp@gmail.com> in 2008
17and placed in the public domain.
18 
19Notes:
20- the mayor length of the key its 27 character. This is a restriction of this
21implementation and its very simple to bypass.
22*/
23 
24
25
26//Init values
27const INIT_A: u32 = 0x67452301;
28const INIT_B: u32 = 0xefcdab89;
29const INIT_C: u32 = 0x98badcfe;
30const INIT_D: u32 = 0x10325476;
31 
32const SQRT_2: u32 = 0x5a827999;
33const SQRT_3: u32 = 0x6ed9eba1;
34 
35const ITOA16: [char; 16] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
36
37/// The main function of this crate : the raw hash function
38pub fn ntlm_crypt(nt_buffer: [u32; 16]) -> [u32; 4]
39{
40	let mut a = INIT_A;
41	let mut b = INIT_B;
42	let mut c = INIT_C;
43	let mut d = INIT_D;
44 
45	/* Round 1 */
46	a = a.wrapping_add(d ^ (b & (c ^ d))).wrapping_add(nt_buffer[0]);a = (a << 3 ) | (a >> 29);
47	d = d.wrapping_add(c ^ (a & (b ^ c))).wrapping_add(nt_buffer[1]);d = (d << 7 ) | (d >> 25);
48	c = c.wrapping_add(b ^ (d & (a ^ b))).wrapping_add(nt_buffer[2]);c = (c << 11) | (c >> 21);
49	b = b.wrapping_add(a ^ (c & (d ^ a))).wrapping_add(nt_buffer[3]);b = (b << 19) | (b >> 13);
50 
51	a = a.wrapping_add(d ^ (b & (c ^ d))).wrapping_add(nt_buffer[4]);a = (a << 3 ) | (a >> 29);
52	d = d.wrapping_add(c ^ (a & (b ^ c))).wrapping_add(nt_buffer[5]);d = (d << 7 ) | (d >> 25);
53	c = c.wrapping_add(b ^ (d & (a ^ b))).wrapping_add(nt_buffer[6]);c = (c << 11) | (c >> 21);
54	b = b.wrapping_add(a ^ (c & (d ^ a))).wrapping_add(nt_buffer[7]);b = (b << 19) | (b >> 13);
55
56	a = a.wrapping_add(d ^ (b & (c ^ d))).wrapping_add(nt_buffer[8]);a = (a << 3 ) | (a >> 29);
57	d = d.wrapping_add(c ^ (a & (b ^ c))).wrapping_add(nt_buffer[9]);d = (d << 7 ) | (d >> 25);
58	c = c.wrapping_add(b ^ (d & (a ^ b))).wrapping_add(nt_buffer[10]);c = (c << 11) | (c >> 21);
59	b = b.wrapping_add(a ^ (c & (d ^ a))).wrapping_add(nt_buffer[11]);b = (b << 19) | (b >> 13);
60 
61	a = a.wrapping_add(d ^ (b & (c ^ d))).wrapping_add(nt_buffer[12]);a = (a << 3 ) | (a >> 29);
62	d = d.wrapping_add(c ^ (a & (b ^ c))).wrapping_add(nt_buffer[13]);d = (d << 7 ) | (d >> 25);
63	c = c.wrapping_add(b ^ (d & (a ^ b))).wrapping_add(nt_buffer[14]);c = (c << 11) | (c >> 21);
64	b = b.wrapping_add(a ^ (c & (d ^ a))).wrapping_add(nt_buffer[15]);b = (b << 19) | (b >> 13);
65 
66
67	/* Round 2 */
68	a = a.wrapping_add((b & (c | d)) | (c & d)).wrapping_add(nt_buffer[0]).wrapping_add(SQRT_2); a = (a<<3 ) | (a>>29);
69	d = d.wrapping_add((a & (b | c)) | (b & c)).wrapping_add(nt_buffer[4]).wrapping_add(SQRT_2); d = (d<<5 ) | (d>>27);
70	c = c.wrapping_add((d & (a | b)) | (a & b)).wrapping_add(nt_buffer[8]).wrapping_add(SQRT_2); c = (c<<9 ) | (c>>23);
71	b = b.wrapping_add((c & (d | a)) | (d & a)).wrapping_add(nt_buffer[12]).wrapping_add(SQRT_2); b = (b<<13) | (b>>19);
72 
73	a = a.wrapping_add((b & (c | d)) | (c & d)).wrapping_add(nt_buffer[1]).wrapping_add(SQRT_2); a = (a<<3 ) | (a>>29);
74	d = d.wrapping_add((a & (b | c)) | (b & c)).wrapping_add(nt_buffer[5]).wrapping_add(SQRT_2); d = (d<<5 ) | (d>>27);
75	c = c.wrapping_add((d & (a | b)) | (a & b)).wrapping_add(nt_buffer[9]).wrapping_add(SQRT_2); c = (c<<9 ) | (c>>23);
76	b = b.wrapping_add((c & (d | a)) | (d & a)).wrapping_add(nt_buffer[13]).wrapping_add(SQRT_2); b = (b<<13) | (b>>19);
77    
78	a = a.wrapping_add((b & (c | d)) | (c & d)).wrapping_add(nt_buffer[2]).wrapping_add(SQRT_2); a = (a<<3 ) | (a>>29);
79	d = d.wrapping_add((a & (b | c)) | (b & c)).wrapping_add(nt_buffer[6]).wrapping_add(SQRT_2); d = (d<<5 ) | (d>>27);
80	c = c.wrapping_add((d & (a | b)) | (a & b)).wrapping_add(nt_buffer[10]).wrapping_add(SQRT_2); c = (c<<9 ) | (c>>23);
81	b = b.wrapping_add((c & (d | a)) | (d & a)).wrapping_add(nt_buffer[14]).wrapping_add(SQRT_2); b = (b<<13) | (b>>19);
82 
83	a = a.wrapping_add((b & (c | d)) | (c & d)).wrapping_add(nt_buffer[3]).wrapping_add(SQRT_2); a = (a<<3 ) | (a>>29);
84	d = d.wrapping_add((a & (b | c)) | (b & c)).wrapping_add(nt_buffer[7]).wrapping_add(SQRT_2); d = (d<<5 ) | (d>>27);
85	c = c.wrapping_add((d & (a | b)) | (a & b)).wrapping_add(nt_buffer[11]).wrapping_add(SQRT_2); c = (c<<9 ) | (c>>23);
86	b = b.wrapping_add((c & (d | a)) | (d & a)).wrapping_add(nt_buffer[15]).wrapping_add(SQRT_2); b = (b<<13) | (b>>19);
87 
88
89	/* Round 3 */
90	a = a.wrapping_add(d ^ c ^ b).wrapping_add(nt_buffer[0]).wrapping_add(SQRT_3); a = (a << 3 ) | (a >> 29);
91	d = d.wrapping_add(c ^ b ^ a).wrapping_add(nt_buffer[8]).wrapping_add(SQRT_3); d = (d << 9 ) | (d >> 23);
92	c = c.wrapping_add(b ^ a ^ d).wrapping_add(nt_buffer[4]).wrapping_add(SQRT_3); c = (c << 11) | (c >> 21);
93	b = b.wrapping_add(a ^ d ^ c).wrapping_add(nt_buffer[12]).wrapping_add(SQRT_3); b = (b << 15) | (b >> 17);
94 
95	a = a.wrapping_add(d ^ c ^ b).wrapping_add(nt_buffer[2]).wrapping_add(SQRT_3); a = (a << 3 ) | (a >> 29);
96	d = d.wrapping_add(c ^ b ^ a).wrapping_add(nt_buffer[10]).wrapping_add(SQRT_3); d = (d << 9 ) | (d >> 23);
97	c = c.wrapping_add(b ^ a ^ d).wrapping_add(nt_buffer[6]).wrapping_add(SQRT_3); c = (c << 11) | (c >> 21);
98	b = b.wrapping_add(a ^ d ^ c).wrapping_add(nt_buffer[14]).wrapping_add(SQRT_3); b = (b << 15) | (b >> 17);
99 
100	a = a.wrapping_add(d ^ c ^ b).wrapping_add(nt_buffer[1]).wrapping_add(SQRT_3); a = (a << 3 ) | (a >> 29);
101	d = d.wrapping_add(c ^ b ^ a).wrapping_add(nt_buffer[9]).wrapping_add(SQRT_3); d = (d << 9 ) | (d >> 23);
102	c = c.wrapping_add(b ^ a ^ d).wrapping_add(nt_buffer[5]).wrapping_add(SQRT_3); c = (c << 11) | (c >> 21);
103	b = b.wrapping_add(a ^ d ^ c).wrapping_add(nt_buffer[13]).wrapping_add(SQRT_3); b = (b << 15) | (b >> 17);
104 
105	a = a.wrapping_add(d ^ c ^ b).wrapping_add(nt_buffer[3]).wrapping_add(SQRT_3); a = (a << 3 ) | (a >> 29);
106	d = d.wrapping_add(c ^ b ^ a).wrapping_add(nt_buffer[11]).wrapping_add(SQRT_3); d = (d << 9 ) | (d >> 23);
107	c = c.wrapping_add(b ^ a ^ d).wrapping_add(nt_buffer[7]).wrapping_add(SQRT_3); c = (c << 11) | (c >> 21);
108	b = b.wrapping_add(a ^ d ^ c).wrapping_add(nt_buffer[15]).wrapping_add(SQRT_3); b = (b << 15) | (b >> 17);
109    
110    [a.wrapping_add(INIT_A), b.wrapping_add(INIT_B), c.wrapping_add(INIT_C), d.wrapping_add(INIT_D)]
111}	
112 
113/// This function takes care of the Unicode conversion and the padding
114/// it takes an array of bytes as input so do `str.as_bytes()` to use the function on a &str
115pub fn prepare_key(key: &[u8]) -> [u32; 16]
116{
117    let mut nt_buffer = [0u32; 16];
118	let length = key.len() as u32;
119	for i in 0..16 {
120        nt_buffer[i] = 0;
121    }
122	//The length of key need to be <= 27
123	for i in 0usize..(length/2) as usize {
124	    nt_buffer[i] = key[2*i] as u32 | ((key[2*i+1] as u32) << 16);
125    }
126	
127	let i = (length/2) as usize;
128	//padding
129	if length % 2 == 1 {
130		nt_buffer[i] = key[(length-1) as usize] as u32 | 0x800000;
131    }
132	else {
133		nt_buffer[i]=0x80;
134    }
135	//put the length
136	nt_buffer[14] = length << 4;
137    nt_buffer
138}
139 
140/// This function converts the output of `ntlm_crypt` to hexadecimal form
141pub fn convert_hex(output: &mut [u32; 4]) -> String
142{
143    let mut hex_format: [char; 32] = [' '; 32];
144	//Iterate the integer
145	for i in 0..4
146	{
147		let mut n: u32 = output[i];
148		//iterate the bytes of the integer		
149		for j in 0..4
150		{
151			let mut convert = n % 256;
152			hex_format[i*8+j*2+1] = ITOA16[(convert%16) as usize];
153			convert = convert/16;
154			hex_format[i*8+j*2+0] = ITOA16[(convert%16) as usize];
155			n /= 256;
156		}	
157	}
158	let mut out = String::new();
159	hex_format.iter().for_each(|&c| out.push(c));
160	out
161}
162
163/// This function takes a string and output a hex of the ntlm hash
164pub fn ntlm_hash(s: &str) -> String {
165	convert_hex(&mut ntlm_crypt(prepare_key(s.as_bytes())))
166}
167
168#[test]
169fn limit() {
170	println!("{}", ntlm_hash("0123456789012345678901234567890"));
171}