1 // Copyright 2023, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Handles the encryption and decryption of the key blob.
16 
17 use alloc::vec;
18 use alloc::vec::Vec;
19 use bssl_avf::{hkdf, rand_bytes, Aead, AeadContext, Digester, AES_GCM_NONCE_LENGTH};
20 use core::result;
21 use serde::{Deserialize, Serialize};
22 use service_vm_comm::RequestProcessingError;
23 use zeroize::Zeroizing;
24 
25 type Result<T> = result::Result<T, RequestProcessingError>;
26 
27 /// The KEK (Key Encryption Key) info is used as information to derive the KEK using HKDF.
28 const KEK_INFO: &[u8] = b"rialto keyblob kek";
29 
30 /// An all-zero nonce is utilized to encrypt the private key. This is because each key
31 /// undergoes encryption using a distinct KEK, which is derived from a secret and a random
32 /// salt. Since the uniqueness of the IV/key combination is already guaranteed by the uniqueness
33 /// of the KEK, there is no need for an additional random nonce.
34 const PRIVATE_KEY_NONCE: &[u8; AES_GCM_NONCE_LENGTH] = &[0; AES_GCM_NONCE_LENGTH];
35 
36 /// Since Rialto functions as both the sender and receiver of the message, no additional data is
37 /// needed.
38 const PRIVATE_KEY_AD: &[u8] = &[];
39 
40 // Encrypted key blob.
41 #[derive(Clone, Debug, Deserialize, Serialize)]
42 pub(crate) enum EncryptedKeyBlob {
43     /// Version 1 key blob.
44     V1(EncryptedKeyBlobV1),
45 }
46 
47 /// Encrypted key blob version 1.
48 #[derive(Clone, Debug, Deserialize, Serialize)]
49 pub(crate) struct EncryptedKeyBlobV1 {
50     /// Salt used to derive the KEK.
51     kek_salt: [u8; 32],
52 
53     /// Private key encrypted with AES-256-GCM.
54     encrypted_private_key: Vec<u8>,
55 }
56 
57 impl EncryptedKeyBlob {
new(private_key: &[u8], kek_secret: &[u8]) -> Result<Self>58     pub(crate) fn new(private_key: &[u8], kek_secret: &[u8]) -> Result<Self> {
59         EncryptedKeyBlobV1::new(private_key, kek_secret).map(Self::V1)
60     }
61 
decrypt_private_key(&self, kek_secret: &[u8]) -> Result<Zeroizing<Vec<u8>>>62     pub(crate) fn decrypt_private_key(&self, kek_secret: &[u8]) -> Result<Zeroizing<Vec<u8>>> {
63         match self {
64             Self::V1(blob) => blob.decrypt_private_key(kek_secret),
65         }
66     }
67 }
68 
69 impl EncryptedKeyBlobV1 {
new(private_key: &[u8], kek_secret: &[u8]) -> Result<Self>70     fn new(private_key: &[u8], kek_secret: &[u8]) -> Result<Self> {
71         let mut kek_salt = [0u8; 32];
72         rand_bytes(&mut kek_salt)?;
73         let kek = hkdf::<32>(kek_secret, &kek_salt, KEK_INFO, Digester::sha512())?;
74 
75         let tag_len = None;
76         let aead_ctx = AeadContext::new(Aead::aes_256_gcm(), kek.as_slice(), tag_len)?;
77         let mut out = vec![0u8; private_key.len() + aead_ctx.aead().max_overhead()];
78         let ciphertext = aead_ctx.seal(private_key, PRIVATE_KEY_NONCE, PRIVATE_KEY_AD, &mut out)?;
79 
80         Ok(Self { kek_salt, encrypted_private_key: ciphertext.to_vec() })
81     }
82 
decrypt_private_key(&self, kek_secret: &[u8]) -> Result<Zeroizing<Vec<u8>>>83     fn decrypt_private_key(&self, kek_secret: &[u8]) -> Result<Zeroizing<Vec<u8>>> {
84         let kek = hkdf::<32>(kek_secret, &self.kek_salt, KEK_INFO, Digester::sha512())?;
85         let mut out = Zeroizing::new(vec![0u8; self.encrypted_private_key.len()]);
86         let tag_len = None;
87         let aead_ctx = AeadContext::new(Aead::aes_256_gcm(), kek.as_slice(), tag_len)?;
88         let plaintext = aead_ctx.open(
89             &self.encrypted_private_key,
90             PRIVATE_KEY_NONCE,
91             PRIVATE_KEY_AD,
92             &mut out,
93         )?;
94         Ok(Zeroizing::new(plaintext.to_vec()))
95     }
96 }
97 
decrypt_private_key( encrypted_key_blob: &[u8], kek_secret: &[u8], ) -> Result<Zeroizing<Vec<u8>>>98 pub(crate) fn decrypt_private_key(
99     encrypted_key_blob: &[u8],
100     kek_secret: &[u8],
101 ) -> Result<Zeroizing<Vec<u8>>> {
102     let key_blob: EncryptedKeyBlob = cbor_util::deserialize(encrypted_key_blob)?;
103     let private_key = key_blob.decrypt_private_key(kek_secret)?;
104     Ok(private_key)
105 }
106 
107 #[cfg(test)]
108 mod tests {
109     use super::*;
110     use bssl_avf::{ApiName, CipherError, Error};
111 
112     /// The test data are generated randomly with /dev/urandom.
113     const TEST_KEY: [u8; 32] = [
114         0x76, 0xf7, 0xd5, 0x36, 0x1f, 0x78, 0x58, 0x2e, 0x55, 0x2f, 0x88, 0x9d, 0xa3, 0x3e, 0xba,
115         0xfb, 0xc1, 0x2b, 0x17, 0x85, 0x24, 0xdc, 0x0e, 0xc4, 0xbf, 0x6d, 0x2e, 0xe8, 0xa8, 0x36,
116         0x93, 0x62,
117     ];
118     const TEST_SECRET1: [u8; 32] = [
119         0xac, 0xb1, 0x6b, 0xdf, 0x45, 0x30, 0x20, 0xa5, 0x60, 0x6d, 0x81, 0x07, 0x30, 0x68, 0x6e,
120         0x01, 0x3d, 0x5e, 0x86, 0xd6, 0xc6, 0x17, 0xfa, 0xd6, 0xe0, 0xff, 0xd4, 0xf0, 0xb0, 0x7c,
121         0x5c, 0x8f,
122     ];
123     const TEST_SECRET2: [u8; 32] = [
124         0x04, 0x6e, 0xca, 0x30, 0x5e, 0x6c, 0x8f, 0xe5, 0x1a, 0x47, 0x12, 0xbc, 0x45, 0xd7, 0xa8,
125         0x38, 0xfb, 0x06, 0xc6, 0x44, 0xa1, 0x21, 0x40, 0x0b, 0x48, 0x88, 0xe2, 0x31, 0x64, 0x42,
126         0x9d, 0x1c,
127     ];
128 
129     #[test]
decrypting_keyblob_succeeds_with_the_same_kek() -> Result<()>130     fn decrypting_keyblob_succeeds_with_the_same_kek() -> Result<()> {
131         let encrypted_key_blob =
132             cbor_util::serialize(&EncryptedKeyBlob::new(&TEST_KEY, &TEST_SECRET1)?)?;
133         let decrypted_key = decrypt_private_key(&encrypted_key_blob, &TEST_SECRET1)?;
134 
135         assert_eq!(TEST_KEY, decrypted_key.as_slice());
136         Ok(())
137     }
138 
139     #[test]
decrypting_keyblob_fails_with_a_different_kek() -> Result<()>140     fn decrypting_keyblob_fails_with_a_different_kek() -> Result<()> {
141         let encrypted_key_blob =
142             cbor_util::serialize(&EncryptedKeyBlob::new(&TEST_KEY, &TEST_SECRET1)?)?;
143         let err = decrypt_private_key(&encrypted_key_blob, &TEST_SECRET2).unwrap_err();
144 
145         let expected_err: RequestProcessingError =
146             Error::CallFailed(ApiName::EVP_AEAD_CTX_open, CipherError::BadDecrypt.into()).into();
147         assert_eq!(expected_err, err);
148         Ok(())
149     }
150 }
151