1 // Copyright 2015-2021 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 #![allow(missing_docs)] 15 16 use criterion::criterion_main; 17 use ring::{aead, error}; 18 19 // All the AEADs we're testing use 96-bit nonces. 20 pub const NONCE: [u8; 96 / 8] = [0u8; 96 / 8]; 21 22 // A TLS 1.2 finished message is always 12 bytes long. 23 const TLS12_FINISHED_LEN: usize = 12; 24 25 // A TLS 1.3 finished message is "[t]he size of the HMAC output for the 26 // Hash used for the handshake," which is usually SHA-256. 27 const TLS13_FINISHED_LEN: usize = 32; 28 29 // In TLS 1.2, 13 bytes of additional data are used for AEAD cipher suites. 30 const TLS12_AD: [u8; 13] = [ 31 23, // Type: application_data 32 3, 3, // Version = TLS 1.2. 33 0x12, 0x34, // Length = 0x1234. 34 0, 0, 0, 0, 0, 0, 0, 1, // Record #1 35 ]; 36 37 // In TLS 1.3, 5 bytes of additional data are used for AEAD cihper suites. 38 const TLS13_AD: [u8; 5] = [ 39 0x17, // app data type 40 0x3, // version 41 0x3, // .. 42 0x0, // Length 43 0x7, // .. 44 ]; 45 46 struct NonceSequence(u64); 47 impl NonceSequence { new() -> Self48 const fn new() -> Self { 49 Self(0) 50 } 51 } 52 53 impl aead::NonceSequence for NonceSequence { advance(&mut self) -> Result<aead::Nonce, error::Unspecified>54 fn advance(&mut self) -> Result<aead::Nonce, error::Unspecified> { 55 let mut result = [0u8; aead::NONCE_LEN]; 56 result[4..].copy_from_slice(&u64::to_be_bytes(self.0)); 57 self.0 = self.0.checked_add(1).ok_or(error::Unspecified)?; 58 Ok(aead::Nonce::assume_unique_for_key(result)) 59 } 60 } 61 62 macro_rules! function_bench_name { 63 ( $benchmark_name:ident, $algorithm:expr, $operation:ident) => {{ 64 const FUNC_NAME_BASE: &str = concat!( 65 "aead_", 66 stringify!($operation), 67 "_", 68 stringify!($benchmark_name), 69 "_", 70 stringify!($algorithm) 71 ); 72 73 FUNC_NAME_BASE.replace("&aead::", "") 74 }}; 75 } 76 77 macro_rules! bench { 78 ( $benchmark_name:ident, $algorithm:expr, $chunk_len:expr, $ad:expr ) => { 79 pub(super) fn $benchmark_name(c: &mut criterion::Criterion) { 80 use super::{NonceSequence, NONCE}; 81 use criterion::{black_box, BatchSize}; 82 use ring::{ 83 aead::{self, BoundKey}, 84 rand::{SecureRandom, SystemRandom}, 85 }; 86 87 let rng = SystemRandom::new(); 88 89 let mut key_bytes = vec![0u8; $algorithm.key_len()]; 90 rng.fill(&mut key_bytes).unwrap(); 91 92 { 93 let key = aead::UnboundKey::new($algorithm, &key_bytes).unwrap(); 94 let mut key = aead::SealingKey::new(key, NonceSequence::new()); 95 96 let mut in_out = black_box(vec![0u8; $chunk_len + $algorithm.tag_len()]); 97 98 c.bench_function( 99 &function_bench_name!($benchmark_name, $algorithm, seal), 100 |b| { 101 b.iter(|| -> Result<(), ring::error::Unspecified> { 102 let aad = aead::Aad::from(black_box($ad)); 103 let _tag = key.seal_in_place_separate_tag(aad, &mut in_out)?; 104 Ok(()) 105 }) 106 }, 107 ); 108 } 109 110 { 111 let key = 112 aead::LessSafeKey::new(aead::UnboundKey::new($algorithm, &key_bytes).unwrap()); 113 114 let ciphertext = { 115 let nonce = aead::Nonce::assume_unique_for_key(NONCE); 116 let mut in_out = vec![0u8; $chunk_len + $algorithm.tag_len()]; 117 let aad = aead::Aad::from($ad); 118 key.seal_in_place_append_tag(nonce, aad, &mut in_out) 119 .unwrap(); 120 in_out 121 }; 122 123 let num_batches = (std::cmp::max(1, 8192 / ciphertext.len()) * 10) as u64; 124 125 c.bench_function( 126 &function_bench_name!($benchmark_name, $algorithm, open), 127 |b| { 128 b.iter_batched( 129 || ciphertext.clone(), 130 |mut ciphertext| -> Result<(), ring::error::Unspecified> { 131 // Optimizes out 132 let nonce = aead::Nonce::assume_unique_for_key(NONCE); 133 134 let aad = aead::Aad::from(black_box($ad)); 135 let _result = key.open_in_place(nonce, aad, &mut ciphertext)?; 136 137 Ok(()) 138 }, 139 BatchSize::NumBatches(num_batches), 140 ) 141 }, 142 ); 143 } 144 } 145 }; 146 } 147 148 macro_rules! benches { 149 ( $name:ident, $algorithm:expr ) => { 150 mod $name { 151 use criterion::criterion_group; 152 153 // A TLS 1.2 finished message. 154 bench!( 155 tls12_finished, 156 $algorithm, 157 super::TLS12_FINISHED_LEN, 158 super::TLS12_AD 159 ); 160 161 // A TLS 1.3 finished message. 162 bench!( 163 tls13_finished, 164 $algorithm, 165 super::TLS13_FINISHED_LEN, 166 super::TLS13_AD 167 ); 168 169 // For comparison with BoringSSL. 170 bench!(tls12_16, $algorithm, 16, super::TLS12_AD); 171 172 // ~1 packet of data in TLS. 173 bench!(tls12_1350, $algorithm, 1350, super::TLS12_AD); 174 bench!(tls13_1350, $algorithm, 1350, super::TLS13_AD); 175 176 // For comparison with BoringSSL. 177 bench!(tls12_8192, $algorithm, 8192, super::TLS12_AD); 178 bench!(tls13_8192, $algorithm, 8192, super::TLS13_AD); 179 180 criterion_group!( 181 $name, 182 tls12_finished, 183 tls13_finished, 184 tls12_16, 185 tls12_1350, 186 tls13_1350, 187 tls12_8192, 188 tls13_8192 189 ); 190 } 191 192 // Export Criterion benchmark groups 193 pub use $name::*; 194 }; 195 } 196 197 benches!(aes_128_gcm, &aead::AES_128_GCM); 198 benches!(aes_256_gcm, &aead::AES_256_GCM); 199 benches!(chacha20_poly1305, &aead::CHACHA20_POLY1305); 200 201 criterion_main!(aes_128_gcm, aes_256_gcm, chacha20_poly1305); 202