1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 // This file contains code that was copied from the ring crate which is under
6 // the ISC license, reproduced below:
7 
8 // Copyright 2015-2017 Brian Smith.
9 
10 // Permission to use, copy, modify, and/or distribute this software for any
11 // purpose with or without fee is hereby granted, provided that the above
12 // copyright notice and this permission notice appear in all copies.
13 
14 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
15 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
17 // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19 // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 
22 use crate::{aead, error::*};
23 use nss::aes;
24 
25 /// AES-128 in GCM mode with 128-bit tags and 96 bit nonces.
26 pub static AES_128_GCM: aead::Algorithm = aead::Algorithm {
27     key_len: 16,
28     tag_len: 16,
29     nonce_len: 96 / 8,
30     open,
31     seal,
32 };
33 
34 /// AES-256 in GCM mode with 128-bit tags and 96 bit nonces.
35 pub static AES_256_GCM: aead::Algorithm = aead::Algorithm {
36     key_len: 32,
37     tag_len: 16,
38     nonce_len: 96 / 8,
39     open,
40     seal,
41 };
42 
open( key: &aead::Key, nonce: aead::Nonce, aad: &aead::Aad<'_>, ciphertext_and_tag: &[u8], ) -> Result<Vec<u8>>43 pub(crate) fn open(
44     key: &aead::Key,
45     nonce: aead::Nonce,
46     aad: &aead::Aad<'_>,
47     ciphertext_and_tag: &[u8],
48 ) -> Result<Vec<u8>> {
49     aes_gcm(
50         key,
51         nonce,
52         aad,
53         ciphertext_and_tag,
54         aead::Direction::Opening,
55     )
56 }
57 
seal( key: &aead::Key, nonce: aead::Nonce, aad: &aead::Aad<'_>, plaintext: &[u8], ) -> Result<Vec<u8>>58 pub(crate) fn seal(
59     key: &aead::Key,
60     nonce: aead::Nonce,
61     aad: &aead::Aad<'_>,
62     plaintext: &[u8],
63 ) -> Result<Vec<u8>> {
64     aes_gcm(key, nonce, aad, plaintext, aead::Direction::Sealing)
65 }
66 
aes_gcm( key: &aead::Key, nonce: aead::Nonce, aad: &aead::Aad<'_>, data: &[u8], direction: aead::Direction, ) -> Result<Vec<u8>>67 fn aes_gcm(
68     key: &aead::Key,
69     nonce: aead::Nonce,
70     aad: &aead::Aad<'_>,
71     data: &[u8],
72     direction: aead::Direction,
73 ) -> Result<Vec<u8>> {
74     Ok(aes::aes_gcm_crypt(
75         &key.key_value,
76         &nonce.0,
77         &aad.0,
78         data,
79         direction.to_nss_operation(),
80     )?)
81 }
82 
83 #[cfg(test)]
84 mod test {
85     use super::*;
86 
87     // Test vector from the AES-GCM spec.
88     const NONCE_HEX: &str = "cafebabefacedbaddecaf888";
89     const KEY_HEX: &str = "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308";
90     const AAD_HEX: &str = "feedfacedeadbeeffeedfacedeadbeefabaddad2";
91     const TAG_HEX: &str = "76fc6ece0f4e1768cddf8853bb2d551b";
92     const CIPHERTEXT_HEX: &str =
93         "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662";
94     const CLEARTEXT_HEX: &str =
95         "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39";
96 
97     #[test]
test_decrypt()98     fn test_decrypt() {
99         let key_bytes = hex::decode(KEY_HEX).unwrap();
100         let key = aead::Key::new(&AES_256_GCM, &key_bytes).unwrap();
101         let mut ciphertext_and_tag = hex::decode(&CIPHERTEXT_HEX).unwrap();
102         let tag = hex::decode(&TAG_HEX).unwrap();
103         ciphertext_and_tag.extend(&tag);
104 
105         let iv = hex::decode(NONCE_HEX).unwrap();
106         let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
107         let aad_bytes = hex::decode(AAD_HEX).unwrap();
108         let aad = aead::Aad::from(&aad_bytes);
109         let cleartext_bytes = open(&key, nonce, &aad, &ciphertext_and_tag).unwrap();
110         let encoded_cleartext = hex::encode(cleartext_bytes);
111         assert_eq!(&CLEARTEXT_HEX, &encoded_cleartext);
112     }
113 
114     #[test]
test_encrypt()115     fn test_encrypt() {
116         let key_bytes = hex::decode(KEY_HEX).unwrap();
117         let key = aead::Key::new(&AES_256_GCM, &key_bytes).unwrap();
118         let cleartext = hex::decode(&CLEARTEXT_HEX).unwrap();
119 
120         let iv = hex::decode(NONCE_HEX).unwrap();
121         let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
122         let aad_bytes = hex::decode(AAD_HEX).unwrap();
123         let aad = aead::Aad::from(&aad_bytes);
124         let ciphertext_bytes = seal(&key, nonce, &aad, &cleartext).unwrap();
125 
126         let expected_tag = hex::decode(&TAG_HEX).unwrap();
127         let mut expected_ciphertext = hex::decode(&CIPHERTEXT_HEX).unwrap();
128         expected_ciphertext.extend(&expected_tag);
129         assert_eq!(&expected_ciphertext, &ciphertext_bytes);
130     }
131 
132     #[test]
test_roundtrip()133     fn test_roundtrip() {
134         let key_bytes = hex::decode(KEY_HEX).unwrap();
135         let key = aead::Key::new(&AES_256_GCM, &key_bytes).unwrap();
136         let cleartext = hex::decode(&CLEARTEXT_HEX).unwrap();
137 
138         let iv = hex::decode(NONCE_HEX).unwrap();
139         let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
140         let ciphertext_bytes = seal(&key, nonce, &aead::Aad::empty(), &cleartext).unwrap();
141         let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
142         let roundtriped_cleartext_bytes =
143             open(&key, nonce, &aead::Aad::empty(), &ciphertext_bytes).unwrap();
144         assert_eq!(roundtriped_cleartext_bytes, cleartext);
145     }
146 }
147