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 15 //! Authenticated Encryption with Associated Data (AEAD). 16 //! 17 //! See [Authenticated encryption: relations among notions and analysis of the 18 //! generic composition paradigm][AEAD] for an introduction to the concept of 19 //! AEADs. 20 //! 21 //! [AEAD]: https://eprint.iacr.org/2000/025.pdf 22 //! [`crypto.cipher.AEAD`]: https://golang.org/pkg/crypto/cipher/#AEAD 23 24 use super::{Aad, Algorithm, BoundKey, LessSafeKey, NonceSequence, UnboundKey}; 25 use crate::error; 26 use core::ops::RangeFrom; 27 28 /// An AEAD key for authenticating and decrypting ("opening"), bound to a nonce 29 /// sequence. 30 /// 31 /// Intentionally not `Clone` or `Copy` since cloning would allow duplication 32 /// of the nonce sequence. 33 pub struct OpeningKey<N: NonceSequence> { 34 key: LessSafeKey, 35 nonce_sequence: N, 36 } 37 38 impl<N: NonceSequence> BoundKey<N> for OpeningKey<N> { new(key: UnboundKey, nonce_sequence: N) -> Self39 fn new(key: UnboundKey, nonce_sequence: N) -> Self { 40 Self { 41 key: key.into_inner(), 42 nonce_sequence, 43 } 44 } 45 46 #[inline] algorithm(&self) -> &'static Algorithm47 fn algorithm(&self) -> &'static Algorithm { 48 self.key.algorithm() 49 } 50 } 51 52 impl<N: NonceSequence> core::fmt::Debug for OpeningKey<N> { fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error>53 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { 54 self.key.fmt_debug("OpeningKey", f) 55 } 56 } 57 58 impl<N: NonceSequence> OpeningKey<N> { 59 /// Authenticates and decrypts (“opens”) data in place. 60 /// 61 /// `aad` is the additional authenticated data (AAD), if any. 62 /// 63 /// On input, `in_out` must be the ciphertext followed by the tag. When 64 /// `open_in_place()` returns `Ok(plaintext)`, the input ciphertext 65 /// has been overwritten by the plaintext; `plaintext` will refer to the 66 /// plaintext without the tag. 67 /// 68 /// When `open_in_place()` returns `Err(..)`, `in_out` may have been 69 /// overwritten in an unspecified way. 70 #[inline] open_in_place<'in_out, A>( &mut self, aad: Aad<A>, in_out: &'in_out mut [u8], ) -> Result<&'in_out mut [u8], error::Unspecified> where A: AsRef<[u8]>,71 pub fn open_in_place<'in_out, A>( 72 &mut self, 73 aad: Aad<A>, 74 in_out: &'in_out mut [u8], 75 ) -> Result<&'in_out mut [u8], error::Unspecified> 76 where 77 A: AsRef<[u8]>, 78 { 79 self.key 80 .open_in_place(self.nonce_sequence.advance()?, aad, in_out) 81 } 82 83 /// Authenticates and decrypts (“opens”) data in place, with a shift. 84 /// 85 /// `aad` is the additional authenticated data (AAD), if any. 86 /// 87 /// On input, `in_out[ciphertext_and_tag]` must be the ciphertext followed 88 /// by the tag. When `open_within()` returns `Ok(plaintext)`, the plaintext 89 /// will be at `in_out[0..plaintext.len()]`. In other words, the following 90 /// two code fragments are equivalent for valid values of 91 /// `ciphertext_and_tag`, except `open_within` will often be more efficient: 92 /// 93 /// 94 /// ```skip 95 /// let plaintext = key.open_within(aad, in_out, cipertext_and_tag)?; 96 /// ``` 97 /// 98 /// ```skip 99 /// let ciphertext_and_tag_len = in_out[ciphertext_and_tag].len(); 100 /// in_out.copy_within(ciphertext_and_tag, 0); 101 /// let plaintext = key.open_in_place(aad, &mut in_out[..ciphertext_and_tag_len])?; 102 /// ``` 103 /// 104 /// Similarly, `key.open_within(aad, in_out, 0..)` is equivalent to 105 /// `key.open_in_place(aad, in_out)`. 106 /// 107 /// When `open_in_place()` returns `Err(..)`, `in_out` may have been 108 /// overwritten in an unspecified way. 109 /// 110 /// The shifting feature is useful in the case where multiple packets are 111 /// being reassembled in place. Consider this example where the peer has 112 /// sent the message “Split stream reassembled in place” split into 113 /// three sealed packets: 114 /// 115 /// ```ascii-art 116 /// Packet 1 Packet 2 Packet 3 117 /// Input: [Header][Ciphertext][Tag][Header][Ciphertext][Tag][Header][Ciphertext][Tag] 118 /// | +--------------+ | 119 /// +------+ +-----+ +----------------------------------+ 120 /// v v v 121 /// Output: [Plaintext][Plaintext][Plaintext] 122 /// “Split stream reassembled in place” 123 /// ``` 124 /// 125 /// This reassembly can be accomplished with three calls to `open_within()`. 126 #[inline] open_within<'in_out, A>( &mut self, aad: Aad<A>, in_out: &'in_out mut [u8], ciphertext_and_tag: RangeFrom<usize>, ) -> Result<&'in_out mut [u8], error::Unspecified> where A: AsRef<[u8]>,127 pub fn open_within<'in_out, A>( 128 &mut self, 129 aad: Aad<A>, 130 in_out: &'in_out mut [u8], 131 ciphertext_and_tag: RangeFrom<usize>, 132 ) -> Result<&'in_out mut [u8], error::Unspecified> 133 where 134 A: AsRef<[u8]>, 135 { 136 self.key.open_within( 137 self.nonce_sequence.advance()?, 138 aad, 139 in_out, 140 ciphertext_and_tag, 141 ) 142 } 143 } 144