1 | // Copyright 2015-2016 Brian Smith. |
2 | // Portions Copyright (c) 2014, 2015, Google Inc. |
3 | // |
4 | // Permission to use, copy, modify, and/or distribute this software for any |
5 | // purpose with or without fee is hereby granted, provided that the above |
6 | // copyright notice and this permission notice appear in all copies. |
7 | // |
8 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES |
9 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
11 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
13 | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
14 | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | |
16 | // TODO: enforce maximum input length. |
17 | |
18 | use super::{Tag, TAG_LEN}; |
19 | use crate::{c, cpu}; |
20 | |
21 | /// A Poly1305 key. |
22 | pub(super) struct Key { |
23 | key_and_nonce: [u8; KEY_LEN], |
24 | } |
25 | |
26 | pub(super) const BLOCK_LEN: usize = 16; |
27 | pub(super) const KEY_LEN: usize = 2 * BLOCK_LEN; |
28 | |
29 | impl Key { |
30 | #[inline ] |
31 | pub(super) fn new(key_and_nonce: [u8; KEY_LEN]) -> Self { |
32 | Self { key_and_nonce } |
33 | } |
34 | } |
35 | |
36 | pub struct Context { |
37 | state: poly1305_state, |
38 | #[allow (dead_code)] |
39 | cpu_features: cpu::Features, |
40 | } |
41 | |
42 | // Keep in sync with `poly1305_state` in ring-core/poly1305.h. |
43 | // |
44 | // The C code, in particular the way the `poly1305_aligned_state` functions |
45 | // are used, is only correct when the state buffer is 64-byte aligned. |
46 | #[repr (C, align(64))] |
47 | struct poly1305_state([u8; OPAQUE_LEN]); |
48 | const OPAQUE_LEN: usize = 512; |
49 | |
50 | // Abstracts the dispatching logic that chooses the NEON implementation if and |
51 | // only if it would work. |
52 | macro_rules! dispatch { |
53 | ( $features:expr => |
54 | ( $f:ident | $neon_f:ident ) |
55 | ( $( $p:ident : $t:ty ),+ ) |
56 | ( $( $a:expr ),+ ) ) => { |
57 | match () { |
58 | // Apple's 32-bit ARM ABI is incompatible with the assembly code. |
59 | #[cfg(all(target_arch = "arm" , not(target_vendor = "apple" )))] |
60 | () if cpu::arm::NEON.available($features) => { |
61 | prefixed_extern! { |
62 | fn $neon_f( $( $p : $t ),+ ); |
63 | } |
64 | unsafe { $neon_f( $( $a ),+ ) } |
65 | } |
66 | () => { |
67 | prefixed_extern! { |
68 | fn $f( $( $p : $t ),+ ); |
69 | } |
70 | unsafe { $f( $( $a ),+ ) } |
71 | } |
72 | } |
73 | } |
74 | } |
75 | |
76 | impl Context { |
77 | #[inline ] |
78 | pub(super) fn from_key(Key { key_and_nonce }: Key, cpu_features: cpu::Features) -> Self { |
79 | let mut ctx = Self { |
80 | state: poly1305_state([0u8; OPAQUE_LEN]), |
81 | cpu_features, |
82 | }; |
83 | |
84 | dispatch!( |
85 | cpu_features => |
86 | (CRYPTO_poly1305_init | CRYPTO_poly1305_init_neon) |
87 | (statep: &mut poly1305_state, key: &[u8; KEY_LEN]) |
88 | (&mut ctx.state, &key_and_nonce)); |
89 | |
90 | ctx |
91 | } |
92 | |
93 | #[inline (always)] |
94 | pub fn update(&mut self, input: &[u8]) { |
95 | dispatch!( |
96 | self.cpu_features => |
97 | (CRYPTO_poly1305_update | CRYPTO_poly1305_update_neon) |
98 | (statep: &mut poly1305_state, input: *const u8, in_len: c::size_t) |
99 | (&mut self.state, input.as_ptr(), input.len())); |
100 | } |
101 | |
102 | pub(super) fn finish(mut self) -> Tag { |
103 | let mut tag = Tag([0u8; TAG_LEN]); |
104 | dispatch!( |
105 | self.cpu_features => |
106 | (CRYPTO_poly1305_finish | CRYPTO_poly1305_finish_neon) |
107 | (statep: &mut poly1305_state, mac: &mut [u8; TAG_LEN]) |
108 | (&mut self.state, &mut tag.0)); |
109 | tag |
110 | } |
111 | } |
112 | |
113 | /// Implements the original, non-IETF padding semantics. |
114 | /// |
115 | /// This is used by chacha20_poly1305_openssh and the standalone |
116 | /// poly1305 test vectors. |
117 | pub(super) fn sign(key: Key, input: &[u8], cpu_features: cpu::Features) -> Tag { |
118 | let mut ctx: Context = Context::from_key(key, cpu_features); |
119 | ctx.update(input); |
120 | ctx.finish() |
121 | } |
122 | |
123 | #[cfg (test)] |
124 | mod tests { |
125 | use super::*; |
126 | use crate::test; |
127 | |
128 | // Adapted from BoringSSL's crypto/poly1305/poly1305_test.cc. |
129 | #[test ] |
130 | pub fn test_poly1305() { |
131 | let cpu_features = cpu::features(); |
132 | test::run(test_file!("poly1305_test.txt" ), |section, test_case| { |
133 | assert_eq!(section, "" ); |
134 | let key = test_case .consume_bytes("Key" ); |
135 | let key: &[u8; KEY_LEN] = key.as_slice().try_into().unwrap(); |
136 | let input = test_case .consume_bytes("Input" ); |
137 | let expected_mac = test_case .consume_bytes("MAC" ); |
138 | let key = Key::new(*key); |
139 | let Tag(actual_mac) = sign(key, &input, cpu_features); |
140 | assert_eq!(expected_mac, actual_mac.as_ref()); |
141 | |
142 | Ok(()) |
143 | }) |
144 | } |
145 | } |
146 | |