|
| 1 | +use crate::{AeadCore, AeadInOut, Buffer, Error, Nonce, Payload, Result, Tag}; |
| 2 | +use common::{Key, KeyInit, KeySizeUser, typenum::Unsigned}; |
| 3 | +use inout::InOutBuf; |
| 4 | + |
| 5 | +#[cfg(feature = "alloc")] |
| 6 | +use alloc::vec::Vec; |
| 7 | +#[cfg(feature = "getrandom")] |
| 8 | +use common::getrandom::SysRng; |
| 9 | +#[cfg(feature = "rand_core")] |
| 10 | +use common::{Generate, rand_core::TryCryptoRng}; |
| 11 | + |
| 12 | +/// AEAD which uses nonce-prefixed ciphertext messages. |
| 13 | +#[derive(Clone, Debug)] |
| 14 | +#[repr(transparent)] |
| 15 | +pub struct PrefixNonceAead<A> { |
| 16 | + /// Inner AEAD. |
| 17 | + aead: A, |
| 18 | +} |
| 19 | + |
| 20 | +impl<A: KeySizeUser> KeySizeUser for PrefixNonceAead<A> { |
| 21 | + type KeySize = A::KeySize; |
| 22 | +} |
| 23 | + |
| 24 | +impl<A: KeyInit> KeyInit for PrefixNonceAead<A> { |
| 25 | + fn new(key: &Key<Self>) -> Self { |
| 26 | + Self { aead: A::new(key) } |
| 27 | + } |
| 28 | +} |
| 29 | + |
| 30 | +impl<A: AeadInOut> PrefixNonceAead<A> { |
| 31 | + /// Encrypt the given `plaintext` under a randomly generated nonce, returning a byte vector. |
| 32 | + /// |
| 33 | + /// # Errors |
| 34 | + /// TODO |
| 35 | + #[cfg(all(feature = "alloc", feature = "getrandom"))] |
| 36 | + pub fn encrypt_to_vec<'msg, 'aad>( |
| 37 | + &self, |
| 38 | + plaintext: impl Into<Payload<'msg, 'aad>>, |
| 39 | + ) -> Result<Vec<u8>> { |
| 40 | + let plaintext = plaintext.into(); |
| 41 | + let mut out = Vec::with_capacity( |
| 42 | + A::NonceSize::USIZE |
| 43 | + .saturating_add(plaintext.msg.len()) |
| 44 | + .saturating_add(A::TagSize::USIZE), |
| 45 | + ); |
| 46 | + self.encrypt_to_buffer(plaintext, &mut out)?; |
| 47 | + Ok(out) |
| 48 | + } |
| 49 | + |
| 50 | + /// Encrypt the given `plaintext` under a randomly generated nonce, writing output to the given |
| 51 | + /// `ciphertext` buffer. |
| 52 | + /// |
| 53 | + /// # Errors |
| 54 | + /// TODO |
| 55 | + #[cfg(feature = "getrandom")] |
| 56 | + pub fn encrypt_to_buffer<'msg, 'aad>( |
| 57 | + &self, |
| 58 | + plaintext: impl Into<Payload<'msg, 'aad>>, |
| 59 | + ciphertext: &mut impl Buffer, |
| 60 | + ) -> Result<()> { |
| 61 | + self.encrypt_with_rng_to_buffer(&mut SysRng, plaintext, ciphertext) |
| 62 | + } |
| 63 | + |
| 64 | + /// Generate a random nonce from the provided RNG and encrypt the given `plaintext`, writing |
| 65 | + /// output to the given `ciphertext` buffer. |
| 66 | + /// |
| 67 | + /// # Errors |
| 68 | + /// TODO |
| 69 | + #[cfg(feature = "rand_core")] |
| 70 | + pub fn encrypt_with_rng_to_buffer<'msg, 'aad, R: TryCryptoRng + ?Sized>( |
| 71 | + &self, |
| 72 | + rng: &mut R, |
| 73 | + plaintext: impl Into<Payload<'msg, 'aad>>, |
| 74 | + ciphertext: &mut impl Buffer, |
| 75 | + ) -> Result<()> { |
| 76 | + let nonce = Nonce::<A>::try_generate_from_rng(rng).map_err(|_| Error)?; |
| 77 | + self.encrypt_with_nonce_to_buffer(&nonce, plaintext, ciphertext) |
| 78 | + } |
| 79 | + |
| 80 | + /// Encrypt the given `plaintext` under the provided `nonce`, prepending it to the `ciphertext`. |
| 81 | + /// |
| 82 | + /// # Errors |
| 83 | + /// TODO |
| 84 | + pub fn encrypt_with_nonce_to_buffer<'msg, 'aad>( |
| 85 | + &self, |
| 86 | + nonce: &Nonce<A>, |
| 87 | + plaintext: impl Into<Payload<'msg, 'aad>>, |
| 88 | + ciphertext: &mut impl Buffer, |
| 89 | + ) -> Result<()> { |
| 90 | + let plaintext = plaintext.into(); |
| 91 | + ciphertext.extend_from_slice(nonce)?; |
| 92 | + ciphertext.extend_from_slice(plaintext.msg)?; |
| 93 | + |
| 94 | + let tag = self.aead.encrypt_inout_detached( |
| 95 | + nonce, |
| 96 | + plaintext.aad, |
| 97 | + (&mut ciphertext.as_mut()[A::NonceSize::USIZE..]).into(), |
| 98 | + )?; |
| 99 | + |
| 100 | + ciphertext.extend_from_slice(&tag)?; |
| 101 | + Ok(()) |
| 102 | + } |
| 103 | + |
| 104 | + /// Decrypt a [`Buffer`] containing a ciphertext message in-place, leaving the plaintext message |
| 105 | + /// as its contents upon success. |
| 106 | + /// |
| 107 | + /// # Errors |
| 108 | + /// TODO |
| 109 | + pub fn decrypt_in_place(&self, aad: &[u8], buffer: &mut impl Buffer) -> Result<()> { |
| 110 | + let (nonce, buf, tag) = decode_mut_aead_msg::<A>(buffer.as_mut())?; |
| 111 | + let ct_len = buf.len(); |
| 112 | + self.aead |
| 113 | + .decrypt_inout_detached(&nonce, aad, buf.into(), &tag)?; |
| 114 | + |
| 115 | + // Place the decrypted plaintext message at the beginning of the buffer by copying it over |
| 116 | + // the prefix nonce |
| 117 | + let ct_end = A::NonceSize::USIZE.saturating_add(ct_len); |
| 118 | + buffer.as_mut().copy_within(A::NonceSize::USIZE..ct_end, 0); |
| 119 | + buffer.truncate(ct_len); |
| 120 | + Ok(()) |
| 121 | + } |
| 122 | + |
| 123 | + /// Decrypt the provided `ciphertext` message which includes a prepended nonce to the given |
| 124 | + /// byte slice output buffer. |
| 125 | + /// |
| 126 | + /// # Errors |
| 127 | + /// TODO |
| 128 | + pub fn decrypt_to_slice<'msg, 'aad>( |
| 129 | + &self, |
| 130 | + ciphertext: impl Into<Payload<'msg, 'aad>>, |
| 131 | + out: &mut [u8], |
| 132 | + ) -> Result<()> { |
| 133 | + let payload = ciphertext.into(); |
| 134 | + let (nonce, ct, tag) = decode_aead_msg::<A>(payload.msg)?; |
| 135 | + let buf = InOutBuf::new(ct, out).map_err(|_| Error)?; |
| 136 | + self.aead |
| 137 | + .decrypt_inout_detached(&nonce, payload.aad, buf, &tag) |
| 138 | + } |
| 139 | + |
| 140 | + /// Decrypt the provided `ciphertext` message which includes a prepended nonce, returning a byte |
| 141 | + /// vector upon success. |
| 142 | + /// |
| 143 | + /// # Errors |
| 144 | + /// TODO |
| 145 | + #[cfg(feature = "alloc")] |
| 146 | + pub fn decrypt_to_vec<'msg, 'aad>( |
| 147 | + &self, |
| 148 | + ciphertext: impl Into<Payload<'msg, 'aad>>, |
| 149 | + ) -> Result<Vec<u8>> { |
| 150 | + let ciphertext = ciphertext.into(); |
| 151 | + let plaintext_len = ciphertext |
| 152 | + .msg |
| 153 | + .len() |
| 154 | + .saturating_sub(A::NonceSize::USIZE) |
| 155 | + .saturating_sub(A::TagSize::USIZE); |
| 156 | + let mut out = vec![0u8; plaintext_len]; |
| 157 | + self.decrypt_to_slice(ciphertext, &mut out)?; |
| 158 | + Ok(out) |
| 159 | + } |
| 160 | +} |
| 161 | + |
| 162 | +/// Decode an AEAD message from the given byte slice. |
| 163 | +fn decode_aead_msg<A: AeadCore>(ciphertext: &[u8]) -> Result<(Nonce<A>, &[u8], Tag<A>)> { |
| 164 | + let (nonce, rest) = ciphertext |
| 165 | + .split_at_checked(A::NonceSize::USIZE) |
| 166 | + .ok_or(Error)?; |
| 167 | + let (ciphertext, tag) = rest.split_at_checked(A::TagSize::USIZE).ok_or(Error)?; |
| 168 | + let nonce = Nonce::<A>::try_from(nonce).map_err(|_| Error)?; |
| 169 | + let tag = Tag::<A>::try_from(tag).map_err(|_| Error)?; |
| 170 | + Ok((nonce, ciphertext, tag)) |
| 171 | +} |
| 172 | + |
| 173 | +/// Decode an AEAD message from a mutable input buffer, returning the mutable ciphertext message |
| 174 | +/// portion for use with in-place encryption. |
| 175 | +fn decode_mut_aead_msg<A: AeadCore>( |
| 176 | + ciphertext: &mut [u8], |
| 177 | +) -> Result<(Nonce<A>, &mut [u8], Tag<A>)> { |
| 178 | + let (nonce, ct, tag) = decode_aead_msg::<A>(ciphertext)?; |
| 179 | + let ct_len = ct.len(); |
| 180 | + Ok((nonce, &mut ciphertext[A::NonceSize::USIZE..][ct_len..], tag)) |
| 181 | +} |
0 commit comments