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 cpu_features: cpu::Features,
25 }
26
27 pub(super) const BLOCK_LEN: usize = 16;
28 pub(super) const KEY_LEN: usize = 2 * BLOCK_LEN;
29
30 impl Key {
31 #[inline]
new(key_and_nonce: [u8; KEY_LEN], cpu_features: cpu::Features) -> Self32 pub(super) fn new(key_and_nonce: [u8; KEY_LEN], cpu_features: cpu::Features) -> Self {
33 Self {
34 key_and_nonce,
35 cpu_features,
36 }
37 }
38 }
39
40 pub struct Context {
41 state: poly1305_state,
42 #[allow(dead_code)]
43 cpu_features: cpu::Features,
44 }
45
46 // Keep in sync with `poly1305_state` in ring-core/poly1305.h.
47 //
48 // The C code, in particular the way the `poly1305_aligned_state` functions
49 // are used, is only correct when the state buffer is 64-byte aligned.
50 #[repr(C, align(64))]
51 struct poly1305_state([u8; OPAQUE_LEN]);
52 const OPAQUE_LEN: usize = 512;
53
54 // Abstracts the dispatching logic that chooses the NEON implementation if and
55 // only if it would work.
56 macro_rules! dispatch {
57 ( $features:expr =>
58 ( $f:ident | $neon_f:ident )
59 ( $( $p:ident : $t:ty ),+ )
60 ( $( $a:expr ),+ ) ) => {
61 match () {
62 // Apple's 32-bit ARM ABI is incompatible with the assembly code.
63 #[cfg(all(target_arch = "arm", not(target_vendor = "apple")))]
64 () if cpu::arm::NEON.available($features) => {
65 prefixed_extern! {
66 fn $neon_f( $( $p : $t ),+ );
67 }
68 unsafe { $neon_f( $( $a ),+ ) }
69 }
70 () => {
71 prefixed_extern! {
72 fn $f( $( $p : $t ),+ );
73 }
74 unsafe { $f( $( $a ),+ ) }
75 }
76 }
77 }
78 }
79
80 impl Context {
81 #[inline]
82 pub(super) fn from_key(
83 Key {
84 key_and_nonce,
85 cpu_features,
86 }: Key,
87 ) -> Self {
88 let mut ctx = Self {
89 state: poly1305_state([0u8; OPAQUE_LEN]),
90 cpu_features,
91 };
92
93 dispatch!(
94 cpu_features =>
95 (CRYPTO_poly1305_init | CRYPTO_poly1305_init_neon)
96 (statep: &mut poly1305_state, key: &[u8; KEY_LEN])
97 (&mut ctx.state, &key_and_nonce));
98
99 ctx
100 }
101
102 #[inline(always)]
update(&mut self, input: &[u8])103 pub fn update(&mut self, input: &[u8]) {
104 dispatch!(
105 self.cpu_features =>
106 (CRYPTO_poly1305_update | CRYPTO_poly1305_update_neon)
107 (statep: &mut poly1305_state, input: *const u8, in_len: c::size_t)
108 (&mut self.state, input.as_ptr(), input.len()));
109 }
110
finish(mut self) -> Tag111 pub(super) fn finish(mut self) -> Tag {
112 let mut tag = Tag([0u8; TAG_LEN]);
113 dispatch!(
114 self.cpu_features =>
115 (CRYPTO_poly1305_finish | CRYPTO_poly1305_finish_neon)
116 (statep: &mut poly1305_state, mac: &mut [u8; TAG_LEN])
117 (&mut self.state, &mut tag.0));
118 tag
119 }
120 }
121
122 /// Implements the original, non-IETF padding semantics.
123 ///
124 /// This is used by chacha20_poly1305_openssh and the standalone
125 /// poly1305 test vectors.
sign(key: Key, input: &[u8]) -> Tag126 pub(super) fn sign(key: Key, input: &[u8]) -> Tag {
127 let mut ctx = Context::from_key(key);
128 ctx.update(input);
129 ctx.finish()
130 }
131
132 #[cfg(test)]
133 mod tests {
134 use super::*;
135 use crate::test;
136
137 // Adapted from BoringSSL's crypto/poly1305/poly1305_test.cc.
138 #[test]
test_poly1305()139 pub fn test_poly1305() {
140 let cpu_features = cpu::features();
141 test::run(test_file!("poly1305_test.txt"), |section, test_case| {
142 assert_eq!(section, "");
143 let key = test_case.consume_bytes("Key");
144 let key: &[u8; KEY_LEN] = key.as_slice().try_into().unwrap();
145 let input = test_case.consume_bytes("Input");
146 let expected_mac = test_case.consume_bytes("MAC");
147 let key = Key::new(*key, cpu_features);
148 let Tag(actual_mac) = sign(key, &input);
149 assert_eq!(expected_mac, actual_mac.as_ref());
150
151 Ok(())
152 })
153 }
154 }
155