crypto/ciphers/
macros.rs

1// Copyright 2020 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4#[allow(unused_macros)]
5macro_rules! impl_aead {
6    ($impl:ident, $name:expr, $key_len:ident, $nonce_len:ident, $tag_len:ident) => {
7        impl $crate::ciphers::traits::Aead for $impl {
8            type KeyLength = $key_len;
9            type NonceLength = $nonce_len;
10            type TagLength = $tag_len;
11
12            const NAME: &'static str = $name;
13
14            /// Warning: type conversions on the tag type can be tricky. instead of `&mut tag.try_into().unwrap()` use
15            /// `(&mut tag).try_into().unwrap()`
16            fn encrypt(
17                key: &$crate::ciphers::traits::Key<Self>,
18                nonce: &$crate::ciphers::traits::Nonce<Self>,
19                associated_data: &[u8],
20                plaintext: &[u8],
21                ciphertext: &mut [u8],
22                tag: &mut $crate::ciphers::traits::Tag<Self>,
23            ) -> crate::Result<usize> {
24                use aead::{AeadInPlace, KeyInit};
25
26                if plaintext.len() > ciphertext.len() {
27                    return Err($crate::Error::BufferSize {
28                        name: "ciphertext",
29                        needs: plaintext.len(),
30                        has: ciphertext.len(),
31                    });
32                }
33
34                ciphertext[..plaintext.len()].copy_from_slice(plaintext);
35
36                let out: $crate::ciphers::traits::Tag<Self> = Self::new(key)
37                    .encrypt_in_place_detached(nonce, associated_data, ciphertext)
38                    .map_err(|_| $crate::Error::CipherError { alg: Self::NAME })?;
39
40                tag.copy_from_slice(&out);
41
42                Ok(plaintext.len())
43            }
44
45            fn decrypt(
46                key: &$crate::ciphers::traits::Key<Self>,
47                nonce: &$crate::ciphers::traits::Nonce<Self>,
48                associated_data: &[u8],
49                plaintext: &mut [u8],
50                ciphertext: &[u8],
51                tag: &$crate::ciphers::traits::Tag<Self>,
52            ) -> crate::Result<usize> {
53                use aead::{AeadInPlace, KeyInit};
54
55                if ciphertext.len() > plaintext.len() {
56                    return Err($crate::Error::BufferSize {
57                        name: "plaintext",
58                        needs: ciphertext.len(),
59                        has: plaintext.len(),
60                    });
61                }
62
63                plaintext[..ciphertext.len()].copy_from_slice(ciphertext);
64
65                Self::new(key)
66                    .decrypt_in_place_detached(nonce, associated_data, plaintext, tag)
67                    .map_err(|_| $crate::Error::CipherError { alg: Self::NAME })?;
68
69                Ok(ciphertext.len())
70            }
71        }
72
73        /// A helper function to encrypt `plaintext` with `key`.
74        /// The return value is arbitrarily chosen as `nonce || tag || ciphertext` for historic reasons, mainly
75        /// compatibility with out wallet libraries. The nonce is randomly chosen.
76        #[cfg(all(feature = "random", feature = "std"))]
77        pub fn aead_encrypt(key: &[u8], plaintext: &[u8]) -> crate::Result<Vec<u8>> {
78            if key.len() != <$impl as $crate::ciphers::traits::Aead>::KEY_LENGTH {
79                return Err($crate::Error::BufferSize {
80                    name: "key",
81                    needs: <$impl as $crate::ciphers::traits::Aead>::KEY_LENGTH,
82                    has: key.len(),
83                });
84            }
85
86            let mut nonce = [0; <$impl as $crate::ciphers::traits::Aead>::NONCE_LENGTH];
87            let mut tag = vec![0; <$impl as $crate::ciphers::traits::Aead>::TAG_LENGTH];
88            let mut ciphertext = vec![0; plaintext.len()];
89
90            crate::utils::rand::fill(&mut nonce)?;
91
92            <$impl as $crate::ciphers::traits::Aead>::encrypt(
93                $crate::ciphers::traits::Key::<$impl>::from_slice(&key),
94                $crate::ciphers::traits::Nonce::<$impl>::from_slice(&nonce),
95                &[],
96                plaintext,
97                &mut ciphertext,
98                $crate::ciphers::traits::Tag::<$impl>::from_mut_slice(&mut tag),
99            )?;
100
101            let mut ret = nonce.to_vec();
102            ret.append(&mut tag);
103            ret.append(&mut ciphertext);
104
105            Ok(ret)
106        }
107
108        /// A helper function to decrypt `ciphertext` with `key`.
109        /// The input value is assumed to be `nonce || tag || ciphertext` for historic reason, mainly compatibility with
110        /// out wallet libraries.
111        #[cfg(feature = "std")]
112        pub fn aead_decrypt(key: &[u8], ciphertext: &[u8]) -> crate::Result<Vec<u8>> {
113            if key.len() != <$impl as $crate::ciphers::traits::Aead>::KEY_LENGTH {
114                return Err($crate::Error::BufferSize {
115                    name: "key",
116                    needs: <$impl as $crate::ciphers::traits::Aead>::KEY_LENGTH,
117                    has: key.len(),
118                });
119            }
120
121            let nonce = &ciphertext[..<$impl as $crate::ciphers::traits::Aead>::NONCE_LENGTH];
122            let tag = &ciphertext[<$impl as $crate::ciphers::traits::Aead>::NONCE_LENGTH
123                ..<$impl as $crate::ciphers::traits::Aead>::NONCE_LENGTH
124                    + <$impl as $crate::ciphers::traits::Aead>::TAG_LENGTH];
125            let ciphertext = &ciphertext[<$impl as $crate::ciphers::traits::Aead>::NONCE_LENGTH
126                + <$impl as $crate::ciphers::traits::Aead>::TAG_LENGTH..];
127            let mut plaintext = vec![0u8; ciphertext.len()];
128
129            <$impl as $crate::ciphers::traits::Aead>::decrypt(
130                $crate::ciphers::traits::Key::<$impl>::from_slice(&key),
131                $crate::ciphers::traits::Nonce::<$impl>::from_slice(&nonce),
132                &[],
133                &mut plaintext,
134                ciphertext,
135                $crate::ciphers::traits::Tag::<$impl>::from_slice(&tag),
136            )?;
137
138            Ok(plaintext)
139        }
140    };
141}