blob: 456c879cb94de1b21cd1d13d277b86d3ad192be5 [file] [log] [blame]
Alice Wang8b8e6e62023-10-02 09:10:13 +00001// 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
Alice Wang8b8e6e62023-10-02 09:10:13 +000017use alloc::vec;
18use alloc::vec::Vec;
Alice Wang78b35f82023-10-06 11:57:35 +000019use bssl_avf::{hkdf, rand_bytes, Aead, AeadContext, Digester, AES_GCM_NONCE_LENGTH};
Alice Wang8b8e6e62023-10-02 09:10:13 +000020use core::result;
21use serde::{Deserialize, Serialize};
22use service_vm_comm::RequestProcessingError;
23// TODO(b/241428146): This will be used once the retrieval mechanism is available.
24#[cfg(test)]
25use zeroize::Zeroizing;
26
27type Result<T> = result::Result<T, RequestProcessingError>;
28
29/// The KEK (Key Encryption Key) info is used as information to derive the KEK using HKDF.
30const KEK_INFO: &[u8] = b"rialto keyblob kek";
31
32/// An all-zero nonce is utilized to encrypt the private key. This is because each key
33/// undergoes encryption using a distinct KEK, which is derived from a secret and a random
34/// salt. Since the uniqueness of the IV/key combination is already guaranteed by the uniqueness
35/// of the KEK, there is no need for an additional random nonce.
36const PRIVATE_KEY_NONCE: &[u8; AES_GCM_NONCE_LENGTH] = &[0; AES_GCM_NONCE_LENGTH];
37
38/// Since Rialto functions as both the sender and receiver of the message, no additional data is
39/// needed.
40const PRIVATE_KEY_AD: &[u8] = &[];
41
42// Encrypted key blob.
43#[derive(Clone, Debug, Deserialize, Serialize)]
44pub(crate) enum EncryptedKeyBlob {
45 /// Version 1 key blob.
46 V1(EncryptedKeyBlobV1),
47}
48
49/// Encrypted key blob version 1.
50#[derive(Clone, Debug, Deserialize, Serialize)]
51pub(crate) struct EncryptedKeyBlobV1 {
52 /// Salt used to derive the KEK.
53 kek_salt: [u8; 32],
54
55 /// Private key encrypted with AES-256-GCM.
56 encrypted_private_key: Vec<u8>,
57}
58
59impl EncryptedKeyBlob {
60 pub(crate) fn new(private_key: &[u8], kek_secret: &[u8]) -> Result<Self> {
61 EncryptedKeyBlobV1::new(private_key, kek_secret).map(Self::V1)
62 }
63
64 // TODO(b/241428146): Use this function to decrypt the retrieved keyblob once the retrieval
65 // mechanism is available.
66 #[cfg(test)]
67 pub(crate) fn decrypt_private_key(&self, kek_secret: &[u8]) -> Result<Zeroizing<Vec<u8>>> {
68 match self {
69 Self::V1(blob) => blob.decrypt_private_key(kek_secret),
70 }
71 }
Alice Wang8b8e6e62023-10-02 09:10:13 +000072}
73
74impl EncryptedKeyBlobV1 {
75 fn new(private_key: &[u8], kek_secret: &[u8]) -> Result<Self> {
76 let mut kek_salt = [0u8; 32];
77 rand_bytes(&mut kek_salt)?;
78 let kek = hkdf::<32>(kek_secret, &kek_salt, KEK_INFO, Digester::sha512())?;
79
80 let tag_len = None;
Alice Wang78b35f82023-10-06 11:57:35 +000081 let aead_ctx = AeadContext::new(Aead::aes_256_gcm(), kek.as_slice(), tag_len)?;
Alice Wang8b8e6e62023-10-02 09:10:13 +000082 let mut out = vec![0u8; private_key.len() + aead_ctx.aead().max_overhead()];
83 let ciphertext = aead_ctx.seal(private_key, PRIVATE_KEY_NONCE, PRIVATE_KEY_AD, &mut out)?;
84
85 Ok(Self { kek_salt, encrypted_private_key: ciphertext.to_vec() })
86 }
87
88 #[cfg(test)]
89 fn decrypt_private_key(&self, kek_secret: &[u8]) -> Result<Zeroizing<Vec<u8>>> {
90 let kek = hkdf::<32>(kek_secret, &self.kek_salt, KEK_INFO, Digester::sha512())?;
91 let mut out = Zeroizing::new(vec![0u8; self.encrypted_private_key.len()]);
92 let tag_len = None;
Alice Wang78b35f82023-10-06 11:57:35 +000093 let aead_ctx = AeadContext::new(Aead::aes_256_gcm(), kek.as_slice(), tag_len)?;
Alice Wang8b8e6e62023-10-02 09:10:13 +000094 let plaintext = aead_ctx.open(
95 &self.encrypted_private_key,
96 PRIVATE_KEY_NONCE,
97 PRIVATE_KEY_AD,
98 &mut out,
99 )?;
100 Ok(Zeroizing::new(plaintext.to_vec()))
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use bssl_avf::{ApiName, CipherError, Error};
108
109 /// The test data are generated randomly with /dev/urandom.
110 const TEST_KEY: [u8; 32] = [
111 0x76, 0xf7, 0xd5, 0x36, 0x1f, 0x78, 0x58, 0x2e, 0x55, 0x2f, 0x88, 0x9d, 0xa3, 0x3e, 0xba,
112 0xfb, 0xc1, 0x2b, 0x17, 0x85, 0x24, 0xdc, 0x0e, 0xc4, 0xbf, 0x6d, 0x2e, 0xe8, 0xa8, 0x36,
113 0x93, 0x62,
114 ];
115 const TEST_SECRET1: [u8; 32] = [
116 0xac, 0xb1, 0x6b, 0xdf, 0x45, 0x30, 0x20, 0xa5, 0x60, 0x6d, 0x81, 0x07, 0x30, 0x68, 0x6e,
117 0x01, 0x3d, 0x5e, 0x86, 0xd6, 0xc6, 0x17, 0xfa, 0xd6, 0xe0, 0xff, 0xd4, 0xf0, 0xb0, 0x7c,
118 0x5c, 0x8f,
119 ];
120 const TEST_SECRET2: [u8; 32] = [
121 0x04, 0x6e, 0xca, 0x30, 0x5e, 0x6c, 0x8f, 0xe5, 0x1a, 0x47, 0x12, 0xbc, 0x45, 0xd7, 0xa8,
122 0x38, 0xfb, 0x06, 0xc6, 0x44, 0xa1, 0x21, 0x40, 0x0b, 0x48, 0x88, 0xe2, 0x31, 0x64, 0x42,
123 0x9d, 0x1c,
124 ];
125
126 #[test]
127 fn decrypting_keyblob_succeeds_with_the_same_kek() -> Result<()> {
Alice Wang5dddeea2023-10-13 12:56:22 +0000128 let encrypted_key_blob =
129 cbor_util::serialize(&EncryptedKeyBlob::new(&TEST_KEY, &TEST_SECRET1)?)?;
130 let encrypted_key_blob: EncryptedKeyBlob = cbor_util::deserialize(&encrypted_key_blob)?;
Alice Wang8b8e6e62023-10-02 09:10:13 +0000131 let decrypted_key = encrypted_key_blob.decrypt_private_key(&TEST_SECRET1)?;
132
133 assert_eq!(TEST_KEY, decrypted_key.as_slice());
134 Ok(())
135 }
136
137 #[test]
138 fn decrypting_keyblob_fails_with_a_different_kek() -> Result<()> {
Alice Wang5dddeea2023-10-13 12:56:22 +0000139 let encrypted_key_blob =
140 cbor_util::serialize(&EncryptedKeyBlob::new(&TEST_KEY, &TEST_SECRET1)?)?;
141 let encrypted_key_blob: EncryptedKeyBlob = cbor_util::deserialize(&encrypted_key_blob)?;
Alice Wang8b8e6e62023-10-02 09:10:13 +0000142 let err = encrypted_key_blob.decrypt_private_key(&TEST_SECRET2).unwrap_err();
143
144 let expected_err: RequestProcessingError =
145 Error::CallFailed(ApiName::EVP_AEAD_CTX_open, CipherError::BadDecrypt.into()).into();
146 assert_eq!(expected_err, err);
147 Ok(())
148 }
149}