makepad_http/
digest.rs

1// depfree sha1
2
3pub struct Sha1 {
4    state: [u32; STATE_LEN],
5    block: [u8; U8_BLOCK_LEN],
6    total: usize,
7    in_block: usize
8}
9
10impl Sha1 {
11    pub fn new() -> Sha1 {
12        Self {
13            state: SHA1_INIT_STATE,
14            block: [0u8; U8_BLOCK_LEN],
15            in_block: 0,
16            total: 0
17        }
18    }
19    
20    pub fn update(&mut self, bytes: &[u8]) {
21        // first write bytes into block,
22        for &byte in bytes {
23            self.block[self.in_block] = byte;
24            self.in_block += 1;
25            if self.in_block == U8_BLOCK_LEN {
26                sha1_digest_bytes(&mut self.state, &self.block);
27                self.block = [0u8; U8_BLOCK_LEN];
28                self.in_block = 0;
29                self.total += U8_BLOCK_LEN;
30            }
31        }
32    }
33    
34    pub fn finalise(mut self) -> [u8; U8_STATE_LEN] {
35        
36        let bits = (self.total as u64 + (self.in_block as u64)) * 8;
37        let extra = bits.to_be_bytes();
38        let mut last_one = [0u8; U8_BLOCK_LEN];
39        let mut last_two = [0u8; U8_BLOCK_LEN];
40        last_one[..self.in_block].clone_from_slice(&self.block[..self.in_block]);
41        last_one[self.in_block] = 0x80;
42        if self.in_block < 56 {
43            last_one[56..64].clone_from_slice(&extra);
44            sha1_digest_bytes(&mut self.state, &last_one);
45        } else {
46            last_two[56..64].clone_from_slice(&extra);
47            sha1_digest_bytes(&mut self.state, &last_one);
48            sha1_digest_bytes(&mut self.state, &last_two);
49        }
50        
51        sha1_state_to_bytes(&self.state)
52    }
53}
54
55impl Default for Sha1 {
56    fn default() -> Self {
57        Self::new()
58    }
59}
60
61const BASE64_TABLE: &[u8; 64] = &[65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47,];
62
63pub fn base64_encode(input: &[u8]) -> String {
64    let mut out = String::new();
65    let mut rem: usize = 0;
66    let mut step = 0;
67    for &inp in input {
68        let inp = inp as usize;
69        if step == 0 {
70            out.push(BASE64_TABLE[inp >> 2] as char);
71            rem = inp & 3;
72            step += 1;
73        }
74        else if step == 1 {
75            out.push(BASE64_TABLE[rem << 4 | inp >> 4] as char);
76            rem = inp & 0xf;
77            step += 1;
78        }
79        else if step == 2 {
80            out.push(BASE64_TABLE[rem << 2 | inp >> 6] as char);
81            out.push(BASE64_TABLE[inp & 0x3f] as char);
82            step = 0;
83        }
84    }
85    if step == 1 {
86        out.push(BASE64_TABLE[rem << 4] as char);
87        out.push('=');
88        out.push('=');
89    }
90    if step == 2 {
91        out.push(BASE64_TABLE[rem << 2] as char);
92        out.push('=');
93    }
94    out
95}
96
97
98// sha1 digest impl from Rust crypto minus all the crap.
99
100pub const STATE_LEN: usize = 5;
101pub const BLOCK_LEN: usize = 16;
102pub const U8_BLOCK_LEN: usize = BLOCK_LEN * 4;
103pub const U8_STATE_LEN: usize = STATE_LEN * 4;
104pub const K0: u32 = 0x5A827999u32;
105pub const K1: u32 = 0x6ED9EBA1u32;
106pub const K2: u32 = 0x8F1BBCDCu32;
107pub const K3: u32 = 0xCA62C1D6u32;
108pub const SHA1_INIT_STATE: [u32; STATE_LEN] = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];
109
110#[inline(always)]
111fn add(a: [u32; 4], b: [u32; 4]) -> [u32; 4] {
112    [
113        a[0].wrapping_add(b[0]),
114        a[1].wrapping_add(b[1]),
115        a[2].wrapping_add(b[2]),
116        a[3].wrapping_add(b[3]),
117    ]
118}
119
120#[inline(always)]
121fn xor(a: [u32; 4], b: [u32; 4]) -> [u32; 4] {
122    [a[0] ^ b[0], a[1] ^ b[1], a[2] ^ b[2], a[3] ^ b[3]]
123}
124
125#[inline]
126pub fn sha1_first_add(e: u32, w0: [u32; 4]) -> [u32; 4] {
127    let [a, b, c, d] = w0;
128    [e.wrapping_add(a), b, c, d]
129}
130
131fn sha1msg1(a: [u32; 4], b: [u32; 4]) -> [u32; 4] {
132    let [_, _, w2, w3] = a;
133    let [w4, w5, _, _] = b;
134    [a[0] ^ w2, a[1] ^ w3, a[2] ^ w4, a[3] ^ w5]
135}
136
137fn sha1msg2(a: [u32; 4], b: [u32; 4]) -> [u32; 4] {
138    let [x0, x1, x2, x3] = a;
139    let [_, w13, w14, w15] = b;
140    
141    let w16 = (x0 ^ w13).rotate_left(1);
142    let w17 = (x1 ^ w14).rotate_left(1);
143    let w18 = (x2 ^ w15).rotate_left(1);
144    let w19 = (x3 ^ w16).rotate_left(1);
145    
146    [w16, w17, w18, w19]
147}
148
149#[inline]
150fn sha1_first_half(abcd: [u32; 4], msg: [u32; 4]) -> [u32; 4] {
151    sha1_first_add(abcd[0].rotate_left(30), msg)
152}
153
154fn sha1_digest_round_x4(abcd: [u32; 4], work: [u32; 4], i: i8) -> [u32; 4] {
155    const K0V: [u32; 4] = [K0, K0, K0, K0];
156    const K1V: [u32; 4] = [K1, K1, K1, K1];
157    const K2V: [u32; 4] = [K2, K2, K2, K2];
158    const K3V: [u32; 4] = [K3, K3, K3, K3];
159    
160    match i {
161        0 => sha1rnds4c(abcd, add(work, K0V)),
162        1 => sha1rnds4p(abcd, add(work, K1V)),
163        2 => sha1rnds4m(abcd, add(work, K2V)),
164        3 => sha1rnds4p(abcd, add(work, K3V)),
165        _ => unreachable!("unknown icosaround index"),
166    }
167}
168
169fn sha1rnds4c(abcd: [u32; 4], msg: [u32; 4]) -> [u32; 4] {
170    let [mut a, mut b, mut c, mut d] = abcd;
171    let [t, u, v, w] = msg;
172    let mut e = 0u32;
173    
174    macro_rules!bool3ary_202 {
175        ( $ a: expr, $ b: expr, $ c: expr) => {
176            $ c ^ ( $ a & ( $ b ^ $ c))
177        };
178    } // Choose, MD5F, SHA1C
179    
180    e = e
181        .wrapping_add(a.rotate_left(5))
182        .wrapping_add(bool3ary_202!(b, c, d))
183        .wrapping_add(t);
184    b = b.rotate_left(30);
185    
186    d = d
187        .wrapping_add(e.rotate_left(5))
188        .wrapping_add(bool3ary_202!(a, b, c))
189        .wrapping_add(u);
190    a = a.rotate_left(30);
191    
192    c = c
193        .wrapping_add(d.rotate_left(5))
194        .wrapping_add(bool3ary_202!(e, a, b))
195        .wrapping_add(v);
196    e = e.rotate_left(30);
197    
198    b = b
199        .wrapping_add(c.rotate_left(5))
200        .wrapping_add(bool3ary_202!(d, e, a))
201        .wrapping_add(w);
202    d = d.rotate_left(30);
203    
204    [b, c, d, e]
205}
206
207fn sha1rnds4p(abcd: [u32; 4], msg: [u32; 4]) -> [u32; 4] {
208    let [mut a, mut b, mut c, mut d] = abcd;
209    let [t, u, v, w] = msg;
210    let mut e = 0u32;
211    
212    macro_rules!bool3ary_150 {
213        ( $ a: expr, $ b: expr, $ c: expr) => {
214            $ a ^ $ b ^ $ c
215        };
216    } // Parity, XOR, MD5H, SHA1P
217    
218    e = e
219        .wrapping_add(a.rotate_left(5))
220        .wrapping_add(bool3ary_150!(b, c, d))
221        .wrapping_add(t);
222    b = b.rotate_left(30);
223    
224    d = d
225        .wrapping_add(e.rotate_left(5))
226        .wrapping_add(bool3ary_150!(a, b, c))
227        .wrapping_add(u);
228    a = a.rotate_left(30);
229    
230    c = c
231        .wrapping_add(d.rotate_left(5))
232        .wrapping_add(bool3ary_150!(e, a, b))
233        .wrapping_add(v);
234    e = e.rotate_left(30);
235    
236    b = b
237        .wrapping_add(c.rotate_left(5))
238        .wrapping_add(bool3ary_150!(d, e, a))
239        .wrapping_add(w);
240    d = d.rotate_left(30);
241    
242    [b, c, d, e]
243}
244
245fn sha1rnds4m(abcd: [u32; 4], msg: [u32; 4]) -> [u32; 4] {
246    let [mut a, mut b, mut c, mut d] = abcd;
247    let [t, u, v, w] = msg;
248    let mut e = 0u32;
249    
250    macro_rules!bool3ary_232 {
251        ( $ a: expr, $ b: expr, $ c: expr) => {
252            ( $ a & $ b) ^ ( $ a & $ c) ^ ( $ b & $ c)
253        };
254    } // Majority, SHA1M
255    
256    e = e
257        .wrapping_add(a.rotate_left(5))
258        .wrapping_add(bool3ary_232!(b, c, d))
259        .wrapping_add(t);
260    b = b.rotate_left(30);
261    
262    d = d
263        .wrapping_add(e.rotate_left(5))
264        .wrapping_add(bool3ary_232!(a, b, c))
265        .wrapping_add(u);
266    a = a.rotate_left(30);
267    
268    c = c
269        .wrapping_add(d.rotate_left(5))
270        .wrapping_add(bool3ary_232!(e, a, b))
271        .wrapping_add(v);
272    e = e.rotate_left(30);
273    
274    b = b
275        .wrapping_add(c.rotate_left(5))
276        .wrapping_add(bool3ary_232!(d, e, a))
277        .wrapping_add(w);
278    d = d.rotate_left(30);
279    
280    [b, c, d, e]
281}
282
283macro_rules!rounds4 {
284    ( $ h0: ident, $ h1: ident, $ wk: expr, $ i: expr) => {
285        sha1_digest_round_x4( $ h0, sha1_first_half( $ h1, $ wk), $ i)
286    };
287}
288
289macro_rules!schedule {
290    ( $ v0: expr, $ v1: expr, $ v2: expr, $ v3: expr) => {
291        sha1msg2(xor(sha1msg1( $ v0, $ v1), $ v2), $ v3)
292    };
293}
294
295macro_rules!schedule_rounds4 {
296    (
297        $ h0: ident,
298        $ h1: ident,
299        $ w0: expr,
300        $ w1: expr,
301        $ w2: expr,
302        $ w3: expr,
303        $ w4: expr,
304        $ i: expr
305    ) => {
306        $ w4 = schedule!( $ w0, $ w1, $ w2, $ w3);
307        $ h1 = rounds4!( $ h0, $ h1, $ w4, $ i);
308    };
309}
310
311#[inline(always)]
312fn sha1_digest_block_u32(state: &mut [u32; 5], block: &[u32; 16]) {
313    let mut w0 = [block[0], block[1], block[2], block[3]];
314    let mut w1 = [block[4], block[5], block[6], block[7]];
315    let mut w2 = [block[8], block[9], block[10], block[11]];
316    let mut w3 = [block[12], block[13], block[14], block[15]];
317    let mut w4;
318    
319    let mut h0 = [state[0], state[1], state[2], state[3]];
320    let mut h1 = sha1_first_add(state[4], w0);
321    
322    // Rounds 0..20
323    h1 = sha1_digest_round_x4(h0, h1, 0);
324    h0 = rounds4!(h1, h0, w1, 0);
325    h1 = rounds4!(h0, h1, w2, 0);
326    h0 = rounds4!(h1, h0, w3, 0);
327    schedule_rounds4!(h0, h1, w0, w1, w2, w3, w4, 0);
328    
329    // Rounds 20..40
330    schedule_rounds4!(h1, h0, w1, w2, w3, w4, w0, 1);
331    schedule_rounds4!(h0, h1, w2, w3, w4, w0, w1, 1);
332    schedule_rounds4!(h1, h0, w3, w4, w0, w1, w2, 1);
333    schedule_rounds4!(h0, h1, w4, w0, w1, w2, w3, 1);
334    schedule_rounds4!(h1, h0, w0, w1, w2, w3, w4, 1);
335    
336    // Rounds 40..60
337    schedule_rounds4!(h0, h1, w1, w2, w3, w4, w0, 2);
338    schedule_rounds4!(h1, h0, w2, w3, w4, w0, w1, 2);
339    schedule_rounds4!(h0, h1, w3, w4, w0, w1, w2, 2);
340    schedule_rounds4!(h1, h0, w4, w0, w1, w2, w3, 2);
341    schedule_rounds4!(h0, h1, w0, w1, w2, w3, w4, 2);
342    
343    // Rounds 60..80
344    schedule_rounds4!(h1, h0, w1, w2, w3, w4, w0, 3);
345    schedule_rounds4!(h0, h1, w2, w3, w4, w0, w1, 3);
346    schedule_rounds4!(h1, h0, w3, w4, w0, w1, w2, 3);
347    schedule_rounds4!(h0, h1, w4, w0, w1, w2, w3, 3);
348    schedule_rounds4!(h1, h0, w0, w1, w2, w3, w4, 3);
349    
350    let e = h1[0].rotate_left(30);
351    let [a, b, c, d] = h0;
352    
353    state[0] = state[0].wrapping_add(a);
354    state[1] = state[1].wrapping_add(b);
355    state[2] = state[2].wrapping_add(c);
356    state[3] = state[3].wrapping_add(d);
357    state[4] = state[4].wrapping_add(e);
358}
359
360pub fn sha1_digest_bytes(state: &mut[u32; STATE_LEN], bytes: &[u8; U8_BLOCK_LEN]) {
361    let mut block_u32 = [0u32; 16];
362    for (i, n) in block_u32.iter_mut().enumerate() {
363        let off = i * 4;
364        *n = (bytes[off + 3] as u32)
365            | ((bytes[off + 2] as u32) << 8)
366            | ((bytes[off + 1] as u32) << 16)
367            | ((bytes[off] as u32) << 24);
368    }
369    sha1_digest_block_u32(state, &block_u32);
370}
371
372pub fn sha1_state_to_bytes(state: &[u32; STATE_LEN]) -> [u8; U8_STATE_LEN] {
373    let mut state_bytes = [0u8; STATE_LEN * 4];
374    for i in 0..STATE_LEN {
375        let bytes = state[i].to_be_bytes();
376        for j in 0..4 {
377            state_bytes[i * 4 + j] = bytes[j];
378        }
379    };
380    state_bytes
381}
382