rc_crypto/aead/
aes_gcm.rs

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
22use crate::{aead, error::*};
23use nss::aes;
24
25/// AES-128 in GCM mode with 128-bit tags and 96 bit nonces.
26pub 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.
35pub 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
43pub(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
58pub(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
67fn 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)]
84mod test {
85    use super::*;
86    use nss::ensure_initialized;
87
88    // Test vector from the AES-GCM spec.
89    const NONCE_HEX: &str = "cafebabefacedbaddecaf888";
90    const KEY_HEX: &str = "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308";
91    const AAD_HEX: &str = "feedfacedeadbeeffeedfacedeadbeefabaddad2";
92    const TAG_HEX: &str = "76fc6ece0f4e1768cddf8853bb2d551b";
93    const CIPHERTEXT_HEX: &str =
94        "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662";
95    const CLEARTEXT_HEX: &str =
96        "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39";
97
98    #[test]
99    fn test_decrypt() {
100        ensure_initialized();
101        let key_bytes = hex::decode(KEY_HEX).unwrap();
102        let key = aead::Key::new(&AES_256_GCM, &key_bytes).unwrap();
103        let mut ciphertext_and_tag = hex::decode(CIPHERTEXT_HEX).unwrap();
104        let tag = hex::decode(TAG_HEX).unwrap();
105        ciphertext_and_tag.extend(&tag);
106
107        let iv = hex::decode(NONCE_HEX).unwrap();
108        let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
109        let aad_bytes = hex::decode(AAD_HEX).unwrap();
110        let aad = aead::Aad::from(&aad_bytes);
111        let cleartext_bytes = open(&key, nonce, &aad, &ciphertext_and_tag).unwrap();
112        let encoded_cleartext = hex::encode(cleartext_bytes);
113        assert_eq!(&CLEARTEXT_HEX, &encoded_cleartext);
114    }
115
116    #[test]
117    fn test_encrypt() {
118        ensure_initialized();
119        let key_bytes = hex::decode(KEY_HEX).unwrap();
120        let key = aead::Key::new(&AES_256_GCM, &key_bytes).unwrap();
121        let cleartext = hex::decode(CLEARTEXT_HEX).unwrap();
122
123        let iv = hex::decode(NONCE_HEX).unwrap();
124        let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
125        let aad_bytes = hex::decode(AAD_HEX).unwrap();
126        let aad = aead::Aad::from(&aad_bytes);
127        let ciphertext_bytes = seal(&key, nonce, &aad, &cleartext).unwrap();
128
129        let expected_tag = hex::decode(TAG_HEX).unwrap();
130        let mut expected_ciphertext = hex::decode(CIPHERTEXT_HEX).unwrap();
131        expected_ciphertext.extend(&expected_tag);
132        assert_eq!(&expected_ciphertext, &ciphertext_bytes);
133    }
134
135    #[test]
136    fn test_roundtrip() {
137        ensure_initialized();
138        let key_bytes = hex::decode(KEY_HEX).unwrap();
139        let key = aead::Key::new(&AES_256_GCM, &key_bytes).unwrap();
140        let cleartext = hex::decode(CLEARTEXT_HEX).unwrap();
141
142        let iv = hex::decode(NONCE_HEX).unwrap();
143        let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
144        let ciphertext_bytes = seal(&key, nonce, &aead::Aad::empty(), &cleartext).unwrap();
145        let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
146        let roundtriped_cleartext_bytes =
147            open(&key, nonce, &aead::Aad::empty(), &ciphertext_bytes).unwrap();
148        assert_eq!(roundtriped_cleartext_bytes, cleartext);
149    }
150}