1 // Copyright 2019 Brian Smith.
2 //
3 // Permission to use, copy, modify, and/or distribute this software for any
4 // purpose with or without fee is hereby granted, provided that the above
5 // copyright notice and this permission notice appear in all copies.
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
10 // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 
15 use crate::c;
16 use core::{
17     num::Wrapping,
18     ops::{Add, AddAssign, BitAnd, BitOr, BitXor, Not, Shr},
19 };
20 
21 #[cfg(not(any(target_arch = "aarch64", target_arch = "arm", target_arch = "x86_64")))]
sha256_block_data_order( state: &mut super::State, data: *const u8, num: c::size_t, )22 pub(super) extern "C" fn sha256_block_data_order(
23     state: &mut super::State,
24     data: *const u8,
25     num: c::size_t,
26 ) {
27     let state = unsafe { &mut state.as32 };
28     *state = block_data_order(*state, data, num)
29 }
30 
31 #[cfg(not(any(target_arch = "aarch64", target_arch = "arm", target_arch = "x86_64")))]
sha512_block_data_order( state: &mut super::State, data: *const u8, num: c::size_t, )32 pub(super) extern "C" fn sha512_block_data_order(
33     state: &mut super::State,
34     data: *const u8,
35     num: c::size_t,
36 ) {
37     let state = unsafe { &mut state.as64 };
38     *state = block_data_order(*state, data, num)
39 }
40 
41 #[cfg_attr(
42     any(target_arch = "aarch64", target_arch = "arm", target_arch = "x86_64"),
43     allow(dead_code)
44 )]
45 #[inline]
block_data_order<S: Sha2>( mut H: [S; CHAINING_WORDS], M: *const u8, num: c::size_t, ) -> [S; CHAINING_WORDS]46 fn block_data_order<S: Sha2>(
47     mut H: [S; CHAINING_WORDS],
48     M: *const u8,
49     num: c::size_t,
50 ) -> [S; CHAINING_WORDS] {
51     let M = M as *const [S::InputBytes; 16];
52     let M: &[[S::InputBytes; 16]] = unsafe { core::slice::from_raw_parts(M, num) };
53 
54     for M in M {
55         // FIPS 180-4 {6.2.2, 6.4.2} Step 1
56         //
57         // TODO: Use `let W: [S::ZERO; S::ROUNDS]` instead of allocating
58         // `MAX_ROUNDS` items and then slicing to `K.len()`; depends on
59         // https://github.com/rust-lang/rust/issues/43408.
60         let mut W = [S::ZERO; MAX_ROUNDS];
61         let W: &[S] = {
62             let W = &mut W[..S::K.len()];
63             for (W, M) in W.iter_mut().zip(M) {
64                 *W = S::from_be_bytes(*M);
65             }
66             for t in M.len()..S::K.len() {
67                 W[t] = sigma_1(W[t - 2]) + W[t - 7] + sigma_0(W[t - 15]) + W[t - 16]
68             }
69 
70             W
71         };
72 
73         // FIPS 180-4 {6.2.2, 6.4.2} Step 2
74         let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h] = H;
75 
76         // FIPS 180-4 {6.2.2, 6.4.2} Step 3
77         for (Kt, Wt) in S::K.iter().zip(W.iter()) {
78             let T1 = h + SIGMA_1(e) + ch(e, f, g) + *Kt + *Wt;
79             let T2 = SIGMA_0(a) + maj(a, b, c);
80             h = g;
81             g = f;
82             f = e;
83             e = d + T1;
84             d = c;
85             c = b;
86             b = a;
87             a = T1 + T2;
88         }
89 
90         // FIPS 180-4 {6.2.2, 6.4.2} Step 4
91         H[0] += a;
92         H[1] += b;
93         H[2] += c;
94         H[3] += d;
95         H[4] += e;
96         H[5] += f;
97         H[6] += g;
98         H[7] += h;
99     }
100 
101     H
102 }
103 
104 // FIPS 180-4 {4.1.1, 4.1.2, 4.1.3}
105 #[inline(always)]
ch<W: Word>(x: W, y: W, z: W) -> W106 pub(super) fn ch<W: Word>(x: W, y: W, z: W) -> W {
107     (x & y) | (!x & z)
108 }
109 
110 // FIPS 180-4 {4.1.1, 4.1.2, 4.1.3}
111 #[inline(always)]
maj<W: Word>(x: W, y: W, z: W) -> W112 pub(super) fn maj<W: Word>(x: W, y: W, z: W) -> W {
113     (x & y) | (x & z) | (y & z)
114 }
115 
116 // FIPS 180-4 {4.1.2, 4.1.3}
117 #[inline(always)]
SIGMA_0<S: Sha2>(x: S) -> S118 fn SIGMA_0<S: Sha2>(x: S) -> S {
119     x.rotr(S::BIG_SIGMA_0.0) ^ x.rotr(S::BIG_SIGMA_0.1) ^ x.rotr(S::BIG_SIGMA_0.2)
120 }
121 
122 // FIPS 180-4 {4.1.2, 4.1.3}
123 #[inline(always)]
SIGMA_1<S: Sha2>(x: S) -> S124 fn SIGMA_1<S: Sha2>(x: S) -> S {
125     x.rotr(S::BIG_SIGMA_1.0) ^ x.rotr(S::BIG_SIGMA_1.1) ^ x.rotr(S::BIG_SIGMA_1.2)
126 }
127 
128 // FIPS 180-4 {4.1.2, 4.1.3}
129 #[inline(always)]
sigma_0<S: Sha2>(x: S) -> S130 fn sigma_0<S: Sha2>(x: S) -> S {
131     x.rotr(S::SMALL_SIGMA_0.0) ^ x.rotr(S::SMALL_SIGMA_0.1) ^ (x >> S::SMALL_SIGMA_0.2)
132 }
133 
134 // FIPS 180-4 {4.1.2, 4.1.3}
135 #[inline(always)]
sigma_1<S: Sha2>(x: S) -> S136 fn sigma_1<S: Sha2>(x: S) -> S {
137     x.rotr(S::SMALL_SIGMA_1.0) ^ x.rotr(S::SMALL_SIGMA_1.1) ^ (x >> S::SMALL_SIGMA_1.2)
138 }
139 
140 // Commonality between SHA-1 and SHA-2 words.
141 pub(super) trait Word:
142     'static
143     + Sized
144     + Copy
145     + Add<Output = Self>
146     + AddAssign
147     + BitAnd<Output = Self>
148     + BitOr<Output = Self>
149     + Not<Output = Self>
150 {
151     const ZERO: Self;
152 
153     type InputBytes: Copy;
154 
from_be_bytes(input: Self::InputBytes) -> Self155     fn from_be_bytes(input: Self::InputBytes) -> Self;
156 
rotr(self, count: u32) -> Self157     fn rotr(self, count: u32) -> Self;
158 }
159 
160 /// A SHA-2 input word.
161 trait Sha2: Word + BitXor<Output = Self> + Shr<usize, Output = Self> {
162     const BIG_SIGMA_0: (u32, u32, u32);
163     const BIG_SIGMA_1: (u32, u32, u32);
164     const SMALL_SIGMA_0: (u32, u32, usize);
165     const SMALL_SIGMA_1: (u32, u32, usize);
166 
167     const K: &'static [Self];
168 }
169 
170 const MAX_ROUNDS: usize = 80;
171 pub(super) const CHAINING_WORDS: usize = 8;
172 
173 impl Word for Wrapping<u32> {
174     const ZERO: Self = Self(0);
175     type InputBytes = [u8; 4];
176 
177     #[inline(always)]
from_be_bytes(input: Self::InputBytes) -> Self178     fn from_be_bytes(input: Self::InputBytes) -> Self {
179         Self(u32::from_be_bytes(input))
180     }
181 
182     #[inline(always)]
rotr(self, count: u32) -> Self183     fn rotr(self, count: u32) -> Self {
184         Self(self.0.rotate_right(count))
185     }
186 }
187 
188 // SHA-256
189 impl Sha2 for Wrapping<u32> {
190     // FIPS 180-4 4.1.2
191     const BIG_SIGMA_0: (u32, u32, u32) = (2, 13, 22);
192     const BIG_SIGMA_1: (u32, u32, u32) = (6, 11, 25);
193     const SMALL_SIGMA_0: (u32, u32, usize) = (7, 18, 3);
194     const SMALL_SIGMA_1: (u32, u32, usize) = (17, 19, 10);
195 
196     // FIPS 180-4 4.2.2
197     const K: &'static [Self] = &[
198         Self(0x428a2f98),
199         Self(0x71374491),
200         Self(0xb5c0fbcf),
201         Self(0xe9b5dba5),
202         Self(0x3956c25b),
203         Self(0x59f111f1),
204         Self(0x923f82a4),
205         Self(0xab1c5ed5),
206         Self(0xd807aa98),
207         Self(0x12835b01),
208         Self(0x243185be),
209         Self(0x550c7dc3),
210         Self(0x72be5d74),
211         Self(0x80deb1fe),
212         Self(0x9bdc06a7),
213         Self(0xc19bf174),
214         Self(0xe49b69c1),
215         Self(0xefbe4786),
216         Self(0x0fc19dc6),
217         Self(0x240ca1cc),
218         Self(0x2de92c6f),
219         Self(0x4a7484aa),
220         Self(0x5cb0a9dc),
221         Self(0x76f988da),
222         Self(0x983e5152),
223         Self(0xa831c66d),
224         Self(0xb00327c8),
225         Self(0xbf597fc7),
226         Self(0xc6e00bf3),
227         Self(0xd5a79147),
228         Self(0x06ca6351),
229         Self(0x14292967),
230         Self(0x27b70a85),
231         Self(0x2e1b2138),
232         Self(0x4d2c6dfc),
233         Self(0x53380d13),
234         Self(0x650a7354),
235         Self(0x766a0abb),
236         Self(0x81c2c92e),
237         Self(0x92722c85),
238         Self(0xa2bfe8a1),
239         Self(0xa81a664b),
240         Self(0xc24b8b70),
241         Self(0xc76c51a3),
242         Self(0xd192e819),
243         Self(0xd6990624),
244         Self(0xf40e3585),
245         Self(0x106aa070),
246         Self(0x19a4c116),
247         Self(0x1e376c08),
248         Self(0x2748774c),
249         Self(0x34b0bcb5),
250         Self(0x391c0cb3),
251         Self(0x4ed8aa4a),
252         Self(0x5b9cca4f),
253         Self(0x682e6ff3),
254         Self(0x748f82ee),
255         Self(0x78a5636f),
256         Self(0x84c87814),
257         Self(0x8cc70208),
258         Self(0x90befffa),
259         Self(0xa4506ceb),
260         Self(0xbef9a3f7),
261         Self(0xc67178f2),
262     ];
263 }
264 
265 impl Word for Wrapping<u64> {
266     const ZERO: Self = Self(0);
267     type InputBytes = [u8; 8];
268 
269     #[inline(always)]
from_be_bytes(input: Self::InputBytes) -> Self270     fn from_be_bytes(input: Self::InputBytes) -> Self {
271         Self(u64::from_be_bytes(input))
272     }
273 
274     #[inline(always)]
rotr(self, count: u32) -> Self275     fn rotr(self, count: u32) -> Self {
276         Self(self.0.rotate_right(count))
277     }
278 }
279 
280 // SHA-384 and SHA-512
281 impl Sha2 for Wrapping<u64> {
282     // FIPS 180-4 4.1.3
283     const BIG_SIGMA_0: (u32, u32, u32) = (28, 34, 39);
284     const BIG_SIGMA_1: (u32, u32, u32) = (14, 18, 41);
285     const SMALL_SIGMA_0: (u32, u32, usize) = (1, 8, 7);
286     const SMALL_SIGMA_1: (u32, u32, usize) = (19, 61, 6);
287 
288     // FIPS 180-4 4.2.3
289     const K: &'static [Self] = &[
290         Self(0x428a2f98d728ae22),
291         Self(0x7137449123ef65cd),
292         Self(0xb5c0fbcfec4d3b2f),
293         Self(0xe9b5dba58189dbbc),
294         Self(0x3956c25bf348b538),
295         Self(0x59f111f1b605d019),
296         Self(0x923f82a4af194f9b),
297         Self(0xab1c5ed5da6d8118),
298         Self(0xd807aa98a3030242),
299         Self(0x12835b0145706fbe),
300         Self(0x243185be4ee4b28c),
301         Self(0x550c7dc3d5ffb4e2),
302         Self(0x72be5d74f27b896f),
303         Self(0x80deb1fe3b1696b1),
304         Self(0x9bdc06a725c71235),
305         Self(0xc19bf174cf692694),
306         Self(0xe49b69c19ef14ad2),
307         Self(0xefbe4786384f25e3),
308         Self(0x0fc19dc68b8cd5b5),
309         Self(0x240ca1cc77ac9c65),
310         Self(0x2de92c6f592b0275),
311         Self(0x4a7484aa6ea6e483),
312         Self(0x5cb0a9dcbd41fbd4),
313         Self(0x76f988da831153b5),
314         Self(0x983e5152ee66dfab),
315         Self(0xa831c66d2db43210),
316         Self(0xb00327c898fb213f),
317         Self(0xbf597fc7beef0ee4),
318         Self(0xc6e00bf33da88fc2),
319         Self(0xd5a79147930aa725),
320         Self(0x06ca6351e003826f),
321         Self(0x142929670a0e6e70),
322         Self(0x27b70a8546d22ffc),
323         Self(0x2e1b21385c26c926),
324         Self(0x4d2c6dfc5ac42aed),
325         Self(0x53380d139d95b3df),
326         Self(0x650a73548baf63de),
327         Self(0x766a0abb3c77b2a8),
328         Self(0x81c2c92e47edaee6),
329         Self(0x92722c851482353b),
330         Self(0xa2bfe8a14cf10364),
331         Self(0xa81a664bbc423001),
332         Self(0xc24b8b70d0f89791),
333         Self(0xc76c51a30654be30),
334         Self(0xd192e819d6ef5218),
335         Self(0xd69906245565a910),
336         Self(0xf40e35855771202a),
337         Self(0x106aa07032bbd1b8),
338         Self(0x19a4c116b8d2d0c8),
339         Self(0x1e376c085141ab53),
340         Self(0x2748774cdf8eeb99),
341         Self(0x34b0bcb5e19b48a8),
342         Self(0x391c0cb3c5c95a63),
343         Self(0x4ed8aa4ae3418acb),
344         Self(0x5b9cca4f7763e373),
345         Self(0x682e6ff3d6b2b8a3),
346         Self(0x748f82ee5defb2fc),
347         Self(0x78a5636f43172f60),
348         Self(0x84c87814a1f0ab72),
349         Self(0x8cc702081a6439ec),
350         Self(0x90befffa23631e28),
351         Self(0xa4506cebde82bde9),
352         Self(0xbef9a3f7b2c67915),
353         Self(0xc67178f2e372532b),
354         Self(0xca273eceea26619c),
355         Self(0xd186b8c721c0c207),
356         Self(0xeada7dd6cde0eb1e),
357         Self(0xf57d4f7fee6ed178),
358         Self(0x06f067aa72176fba),
359         Self(0x0a637dc5a2c898a6),
360         Self(0x113f9804bef90dae),
361         Self(0x1b710b35131c471b),
362         Self(0x28db77f523047d84),
363         Self(0x32caab7b40c72493),
364         Self(0x3c9ebe0a15c9bebc),
365         Self(0x431d67c49c100d4c),
366         Self(0x4cc5d4becb3e42b6),
367         Self(0x597f299cfc657e2a),
368         Self(0x5fcb6fab3ad6faec),
369         Self(0x6c44198c4a475817),
370     ];
371 }
372 
373 #[cfg(any(target_arch = "aarch64", target_arch = "arm", target_arch = "x86_64"))]
374 prefixed_extern! {
375     pub(super) fn sha256_block_data_order(
376         state: &mut super::State,
377         data: *const u8,
378         num: c::size_t,
379     );
380     pub(super) fn sha512_block_data_order(
381         state: &mut super::State,
382         data: *const u8,
383         num: c::size_t,
384     );
385 }
386