1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use crate::{aead, error::*};
use nss::aes;
pub static AES_128_GCM: aead::Algorithm = aead::Algorithm {
key_len: 16,
tag_len: 16,
nonce_len: 96 / 8,
open,
seal,
};
pub static AES_256_GCM: aead::Algorithm = aead::Algorithm {
key_len: 32,
tag_len: 16,
nonce_len: 96 / 8,
open,
seal,
};
pub(crate) fn open(
key: &aead::Key,
nonce: aead::Nonce,
aad: &aead::Aad<'_>,
ciphertext_and_tag: &[u8],
) -> Result<Vec<u8>> {
aes_gcm(
key,
nonce,
aad,
ciphertext_and_tag,
aead::Direction::Opening,
)
}
pub(crate) fn seal(
key: &aead::Key,
nonce: aead::Nonce,
aad: &aead::Aad<'_>,
plaintext: &[u8],
) -> Result<Vec<u8>> {
aes_gcm(key, nonce, aad, plaintext, aead::Direction::Sealing)
}
fn aes_gcm(
key: &aead::Key,
nonce: aead::Nonce,
aad: &aead::Aad<'_>,
data: &[u8],
direction: aead::Direction,
) -> Result<Vec<u8>> {
Ok(aes::aes_gcm_crypt(
&key.key_value,
&nonce.0,
&aad.0,
data,
direction.to_nss_operation(),
)?)
}
#[cfg(test)]
mod test {
use super::*;
const NONCE_HEX: &str = "cafebabefacedbaddecaf888";
const KEY_HEX: &str = "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308";
const AAD_HEX: &str = "feedfacedeadbeeffeedfacedeadbeefabaddad2";
const TAG_HEX: &str = "76fc6ece0f4e1768cddf8853bb2d551b";
const CIPHERTEXT_HEX: &str =
"522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662";
const CLEARTEXT_HEX: &str =
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39";
#[test]
fn test_decrypt() {
let key_bytes = hex::decode(KEY_HEX).unwrap();
let key = aead::Key::new(&AES_256_GCM, &key_bytes).unwrap();
let mut ciphertext_and_tag = hex::decode(&CIPHERTEXT_HEX).unwrap();
let tag = hex::decode(&TAG_HEX).unwrap();
ciphertext_and_tag.extend(&tag);
let iv = hex::decode(NONCE_HEX).unwrap();
let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
let aad_bytes = hex::decode(AAD_HEX).unwrap();
let aad = aead::Aad::from(&aad_bytes);
let cleartext_bytes = open(&key, nonce, &aad, &ciphertext_and_tag).unwrap();
let encoded_cleartext = hex::encode(cleartext_bytes);
assert_eq!(&CLEARTEXT_HEX, &encoded_cleartext);
}
#[test]
fn test_encrypt() {
let key_bytes = hex::decode(KEY_HEX).unwrap();
let key = aead::Key::new(&AES_256_GCM, &key_bytes).unwrap();
let cleartext = hex::decode(&CLEARTEXT_HEX).unwrap();
let iv = hex::decode(NONCE_HEX).unwrap();
let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
let aad_bytes = hex::decode(AAD_HEX).unwrap();
let aad = aead::Aad::from(&aad_bytes);
let ciphertext_bytes = seal(&key, nonce, &aad, &cleartext).unwrap();
let expected_tag = hex::decode(&TAG_HEX).unwrap();
let mut expected_ciphertext = hex::decode(&CIPHERTEXT_HEX).unwrap();
expected_ciphertext.extend(&expected_tag);
assert_eq!(&expected_ciphertext, &ciphertext_bytes);
}
#[test]
fn test_roundtrip() {
let key_bytes = hex::decode(KEY_HEX).unwrap();
let key = aead::Key::new(&AES_256_GCM, &key_bytes).unwrap();
let cleartext = hex::decode(&CLEARTEXT_HEX).unwrap();
let iv = hex::decode(NONCE_HEX).unwrap();
let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
let ciphertext_bytes = seal(&key, nonce, &aead::Aad::empty(), &cleartext).unwrap();
let nonce = aead::Nonce::try_assume_unique_for_key(&AES_256_GCM, &iv).unwrap();
let roundtriped_cleartext_bytes =
open(&key, nonce, &aead::Aad::empty(), &ciphertext_bytes).unwrap();
assert_eq!(roundtriped_cleartext_bytes, cleartext);
}
}