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, digest, error::*, hmac};
23 use nss::aes;
24 
25 /// AES-256 in CBC mode with HMAC-SHA256 tags and 128 bit nonces.
26 /// This is a Sync 1.5 specific encryption scheme, do not use for new
27 /// applications, there are better options out there nowadays.
28 /// Important note: The HMAC tag verification is done against the
29 /// base64 representation of the ciphertext.
30 /// More details here: https://mozilla-services.readthedocs.io/en/latest/sync/storageformat5.html#record-encryption
31 pub static LEGACY_SYNC_AES_256_CBC_HMAC_SHA256: aead::Algorithm = aead::Algorithm {
32     key_len: 64, // 32 bytes for the AES key, 32 bytes for the HMAC key.
33     tag_len: 32,
34     nonce_len: 128 / 8,
35     open,
36     seal,
37 };
38 
39 // Warning: This does not run in constant time (which is fine for our usage).
open( key: &aead::Key, nonce: aead::Nonce, aad: &aead::Aad<'_>, ciphertext_and_tag: &[u8], ) -> Result<Vec<u8>>40 pub(crate) fn open(
41     key: &aead::Key,
42     nonce: aead::Nonce,
43     aad: &aead::Aad<'_>,
44     ciphertext_and_tag: &[u8],
45 ) -> Result<Vec<u8>> {
46     let ciphertext_len = ciphertext_and_tag
47         .len()
48         .checked_sub(key.algorithm().tag_len())
49         .ok_or_else(|| ErrorKind::InternalError)?;
50     let (ciphertext, hmac_signature) = ciphertext_and_tag.split_at(ciphertext_len);
51     let (aes_key, hmac_key_bytes) = extract_keys(&key);
52     // 1. Tag (HMAC signature) check.
53     let hmac_key = hmac::VerificationKey::new(&digest::SHA256, &hmac_key_bytes);
54     hmac::verify(
55         &hmac_key,
56         base64::encode(ciphertext).as_bytes(),
57         hmac_signature,
58     )?;
59     // 2. Decryption.
60     Ok(aes_cbc(
61         aes_key,
62         nonce,
63         aad,
64         ciphertext,
65         aead::Direction::Opening,
66     )?)
67 }
68 
seal( key: &aead::Key, nonce: aead::Nonce, aad: &aead::Aad<'_>, plaintext: &[u8], ) -> Result<Vec<u8>>69 pub(crate) fn seal(
70     key: &aead::Key,
71     nonce: aead::Nonce,
72     aad: &aead::Aad<'_>,
73     plaintext: &[u8],
74 ) -> Result<Vec<u8>> {
75     let (aes_key, hmac_key_bytes) = extract_keys(&key);
76     // 1. Encryption.
77     let mut ciphertext = aes_cbc(aes_key, nonce, aad, plaintext, aead::Direction::Sealing)?;
78     // 2. Tag (HMAC signature) generation.
79     let hmac_key = hmac::SigningKey::new(&digest::SHA256, &hmac_key_bytes);
80     let signature = hmac::sign(&hmac_key, base64::encode(&ciphertext).as_bytes())?;
81     ciphertext.extend(&signature.0.value);
82     Ok(ciphertext)
83 }
84 
extract_keys(key: &aead::Key) -> (&[u8], &[u8])85 fn extract_keys(key: &aead::Key) -> (&[u8], &[u8]) {
86     // Always split at 32 since we only do AES 256 w/ HMAC 256 tag.
87     let (aes_key, hmac_key_bytes) = key.key_value.split_at(32);
88     (aes_key, hmac_key_bytes)
89 }
90 
aes_cbc( aes_key: &[u8], nonce: aead::Nonce, aad: &aead::Aad<'_>, data: &[u8], direction: aead::Direction, ) -> Result<Vec<u8>>91 fn aes_cbc(
92     aes_key: &[u8],
93     nonce: aead::Nonce,
94     aad: &aead::Aad<'_>,
95     data: &[u8],
96     direction: aead::Direction,
97 ) -> Result<Vec<u8>> {
98     if !aad.0.is_empty() {
99         // CBC mode does not support AAD.
100         return Err(ErrorKind::InternalError.into());
101     }
102     Ok(aes::aes_cbc_crypt(
103         aes_key,
104         &nonce.0,
105         data,
106         direction.to_nss_operation(),
107     )?)
108 }
109 
110 #[cfg(test)]
111 mod test {
112     use super::*;
113 
114     // These are the test vectors used by the sync15 crate, but concatenated
115     // together rather than split into individual pieces.
116     const IV_B64: &str = "GX8L37AAb2FZJMzIoXlX8w==";
117 
118     const KEY_B64: &str = "9K/wLdXdw+nrTtXo4ZpECyHFNr4d7aYHqeg3KW9+m6Qwye0R+62At\
119                            NzwWVMtAWazz/Ew+YKV2o+Wr9BBcSPHvQ==";
120 
121     const CIPHERTEXT_AND_TAG_B64: &str =
122         "NMsdnRulLwQsVcwxKW9XwaUe7ouJk5Wn80QhbD80l0HEcZGCynh45qIbeYBik0lgcHbKm\
123          lIxTJNwU+OeqipN+/j7MqhjKOGIlvbpiPQQLC6/ffF2vbzL0nzMUuSyvaQzyGGkSYM2xU\
124          Ft06aNivoQTvU2GgGmUK6MvadoY38hhW2LCMkoZcNfgCqJ26lO1O0sEO6zHsk3IVz6vsK\
125          iJ2Hq6VCo7hu123wNegmujHWQSGyf8JeudZjKzfi0OFRRvvm4QAKyBWf0MgrW1F8SFDnV\
126          fkq8amCB7NhdwhgLWbN+21NitNwWYknoEWe1m6hmGZDgDT32uxzWxCV8QqqrpH/ZggViE\
127          r9uMgoy4lYaWqP7G5WKvvechc62aqnsNEYhH26A5QgzmlNyvB+KPFvPsYzxDnSCjOoRSL\
128          x7GG86wT59QZyx5sGKww3rcCNrwNZaRvek3OO4sOAs+SGCuRTjr6XuvA==";
129 
130     const CLEARTEXT_B64: &str =
131         "eyJpZCI6IjVxUnNnWFdSSlpYciIsImhpc3RVcmkiOiJmaWxlOi8vL1VzZXJzL2phc29u\
132          L0xpYnJhcnkvQXBwbGljYXRpb24lMjBTdXBwb3J0L0ZpcmVmb3gvUHJvZmlsZXMva3Nn\
133          ZDd3cGsuTG9jYWxTeW5jU2VydmVyL3dlYXZlL2xvZ3MvIiwidGl0bGUiOiJJbmRleCBv\
134          ZiBmaWxlOi8vL1VzZXJzL2phc29uL0xpYnJhcnkvQXBwbGljYXRpb24gU3VwcG9ydC9G\
135          aXJlZm94L1Byb2ZpbGVzL2tzZ2Q3d3BrLkxvY2FsU3luY1NlcnZlci93ZWF2ZS9sb2dz\
136          LyIsInZpc2l0cyI6W3siZGF0ZSI6MTMxOTE0OTAxMjM3MjQyNSwidHlwZSI6MX1dfQ==";
137 
138     #[test]
test_decrypt()139     fn test_decrypt() {
140         let key_bytes = base64::decode(KEY_B64).unwrap();
141         let key = aead::Key::new(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &key_bytes).unwrap();
142         let ciphertext_and_tag = base64::decode(&CIPHERTEXT_AND_TAG_B64).unwrap();
143 
144         let iv = base64::decode(IV_B64).unwrap();
145         let nonce =
146             aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv)
147                 .unwrap();
148         let cleartext_bytes = open(&key, nonce, &aead::Aad::empty(), &ciphertext_and_tag).unwrap();
149 
150         let expected_cleartext_bytes = base64::decode(&CLEARTEXT_B64).unwrap();
151         assert_eq!(&expected_cleartext_bytes, &cleartext_bytes);
152     }
153 
154     #[test]
test_encrypt()155     fn test_encrypt() {
156         let key_bytes = base64::decode(KEY_B64).unwrap();
157         let key = aead::Key::new(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &key_bytes).unwrap();
158         let cleartext = base64::decode(&CLEARTEXT_B64).unwrap();
159 
160         let iv = base64::decode(IV_B64).unwrap();
161         let nonce =
162             aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv)
163                 .unwrap();
164         let ciphertext_bytes = seal(&key, nonce, &aead::Aad::empty(), &cleartext).unwrap();
165 
166         let expected_ciphertext_bytes = base64::decode(&CIPHERTEXT_AND_TAG_B64).unwrap();
167         assert_eq!(&expected_ciphertext_bytes, &ciphertext_bytes);
168     }
169 
170     #[test]
test_roundtrip()171     fn test_roundtrip() {
172         let key_bytes = base64::decode(KEY_B64).unwrap();
173         let key = aead::Key::new(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &key_bytes).unwrap();
174         let cleartext = base64::decode(&CLEARTEXT_B64).unwrap();
175 
176         let iv = base64::decode(IV_B64).unwrap();
177         let nonce =
178             aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv)
179                 .unwrap();
180         let ciphertext_bytes = seal(&key, nonce, &aead::Aad::empty(), &cleartext).unwrap();
181         let nonce =
182             aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv)
183                 .unwrap();
184         let roundtriped_cleartext_bytes =
185             open(&key, nonce, &aead::Aad::empty(), &ciphertext_bytes).unwrap();
186         assert_eq!(roundtriped_cleartext_bytes, cleartext);
187     }
188 
189     #[test]
test_decrypt_fails_with_wrong_aes_key()190     fn test_decrypt_fails_with_wrong_aes_key() {
191         let mut key_bytes = base64::decode(KEY_B64).unwrap();
192         key_bytes[1] = b'X';
193 
194         let key = aead::Key::new(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &key_bytes).unwrap();
195         let ciphertext_and_tag = base64::decode(&CIPHERTEXT_AND_TAG_B64).unwrap();
196         let iv = base64::decode(IV_B64).unwrap();
197         let nonce =
198             aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv)
199                 .unwrap();
200 
201         let err = open(&key, nonce, &aead::Aad::empty(), &ciphertext_and_tag).unwrap_err();
202         match err.kind() {
203             ErrorKind::NSSError(_) | ErrorKind::InternalError => {}
204             _ => panic!("unexpected error kind"),
205         }
206     }
207 
208     #[test]
test_decrypt_fails_with_wrong_hmac_key()209     fn test_decrypt_fails_with_wrong_hmac_key() {
210         let mut key_bytes = base64::decode(KEY_B64).unwrap();
211         key_bytes[60] = b'X';
212 
213         let key = aead::Key::new(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &key_bytes).unwrap();
214         let ciphertext_and_tag = base64::decode(&CIPHERTEXT_AND_TAG_B64).unwrap();
215         let iv = base64::decode(IV_B64).unwrap();
216         let nonce =
217             aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv)
218                 .unwrap();
219 
220         let err = open(&key, nonce, &aead::Aad::empty(), &ciphertext_and_tag).unwrap_err();
221         match err.kind() {
222             ErrorKind::InternalError => {}
223             _ => panic!("unexpected error kind"),
224         }
225     }
226 
227     #[test]
test_decrypt_fails_with_modified_ciphertext()228     fn test_decrypt_fails_with_modified_ciphertext() {
229         let key_bytes = base64::decode(KEY_B64).unwrap();
230         let key = aead::Key::new(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &key_bytes).unwrap();
231         let iv = base64::decode(IV_B64).unwrap();
232         let nonce =
233             aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv)
234                 .unwrap();
235 
236         let mut ciphertext_and_tag = base64::decode(&CIPHERTEXT_AND_TAG_B64).unwrap();
237         ciphertext_and_tag[4] = b'Z';
238 
239         let err = open(&key, nonce, &aead::Aad::empty(), &ciphertext_and_tag).unwrap_err();
240         match err.kind() {
241             ErrorKind::InternalError => {}
242             _ => panic!("unexpected error kind"),
243         }
244     }
245 
246     #[test]
test_decrypt_fails_with_modified_tag()247     fn test_decrypt_fails_with_modified_tag() {
248         let key_bytes = base64::decode(KEY_B64).unwrap();
249         let key = aead::Key::new(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &key_bytes).unwrap();
250         let iv = base64::decode(IV_B64).unwrap();
251         let nonce =
252             aead::Nonce::try_assume_unique_for_key(&LEGACY_SYNC_AES_256_CBC_HMAC_SHA256, &iv)
253                 .unwrap();
254 
255         let mut ciphertext_and_tag = base64::decode(&CIPHERTEXT_AND_TAG_B64).unwrap();
256         let end = ciphertext_and_tag.len();
257         ciphertext_and_tag[end - 4] = b'Z';
258 
259         let err = open(&key, nonce, &aead::Aad::empty(), &ciphertext_and_tag).unwrap_err();
260         match err.kind() {
261             ErrorKind::InternalError => {}
262             _ => panic!("unexpected error kind"),
263         }
264     }
265 }
266