1 // Copyright 2021, 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 //! Implement ECDH-based encryption. 16 17 use crate::ks_err; 18 use anyhow::{Context, Result}; 19 use keystore2_crypto::{ 20 aes_gcm_decrypt, aes_gcm_encrypt, ec_key_generate_key, ec_key_get0_public_key, 21 ec_key_marshal_private_key, ec_key_parse_private_key, ec_point_oct_to_point, 22 ec_point_point_to_oct, ecdh_compute_key, generate_salt, hkdf_expand, hkdf_extract, ECKey, ZVec, 23 AES_256_KEY_LENGTH, 24 }; 25 26 /// Private key for ECDH encryption. 27 pub struct ECDHPrivateKey(ECKey); 28 29 impl ECDHPrivateKey { 30 /// Randomly generate a fresh keypair. generate() -> Result<ECDHPrivateKey>31 pub fn generate() -> Result<ECDHPrivateKey> { 32 ec_key_generate_key().map(ECDHPrivateKey).context(ks_err!("generation failed")) 33 } 34 35 /// Deserialize bytes into an ECDH keypair from_private_key(buf: &[u8]) -> Result<ECDHPrivateKey>36 pub fn from_private_key(buf: &[u8]) -> Result<ECDHPrivateKey> { 37 ec_key_parse_private_key(buf).map(ECDHPrivateKey).context(ks_err!("parsing failed")) 38 } 39 40 /// Serialize the ECDH key into bytes private_key(&self) -> Result<ZVec>41 pub fn private_key(&self) -> Result<ZVec> { 42 ec_key_marshal_private_key(&self.0).context(ks_err!("marshalling failed")) 43 } 44 45 /// Generate the serialization of the corresponding public key public_key(&self) -> Result<Vec<u8>>46 pub fn public_key(&self) -> Result<Vec<u8>> { 47 let point = ec_key_get0_public_key(&self.0); 48 ec_point_point_to_oct(point.get_point()).context(ks_err!("marshalling failed")) 49 } 50 51 /// Use ECDH to agree an AES key with another party whose public key we have. 52 /// Sender and recipient public keys are passed separately because they are 53 /// switched in encryption vs decryption. agree_key( &self, salt: &[u8], other_public_key: &[u8], sender_public_key: &[u8], recipient_public_key: &[u8], ) -> Result<ZVec>54 fn agree_key( 55 &self, 56 salt: &[u8], 57 other_public_key: &[u8], 58 sender_public_key: &[u8], 59 recipient_public_key: &[u8], 60 ) -> Result<ZVec> { 61 let hkdf = hkdf_extract(sender_public_key, salt) 62 .context(ks_err!("hkdf_extract on sender_public_key failed"))?; 63 let hkdf = hkdf_extract(recipient_public_key, &hkdf) 64 .context(ks_err!("hkdf_extract on recipient_public_key failed"))?; 65 let other_public_key = ec_point_oct_to_point(other_public_key) 66 .context(ks_err!("ec_point_oct_to_point failed"))?; 67 let secret = ecdh_compute_key(other_public_key.get_point(), &self.0) 68 .context(ks_err!("ecdh_compute_key failed"))?; 69 let prk = hkdf_extract(&secret, &hkdf).context(ks_err!("hkdf_extract on secret failed"))?; 70 71 let aes_key = hkdf_expand(AES_256_KEY_LENGTH, &prk, b"AES-256-GCM key") 72 .context(ks_err!("hkdf_expand failed"))?; 73 Ok(aes_key) 74 } 75 76 /// Encrypt a message to the party with the given public key encrypt_message( recipient_public_key: &[u8], message: &[u8], ) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>)>77 pub fn encrypt_message( 78 recipient_public_key: &[u8], 79 message: &[u8], 80 ) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>)> { 81 let sender_key = Self::generate().context(ks_err!("generate failed"))?; 82 let sender_public_key = sender_key.public_key().context(ks_err!("public_key failed"))?; 83 let salt = generate_salt().context(ks_err!("generate_salt failed"))?; 84 let aes_key = sender_key 85 .agree_key(&salt, recipient_public_key, &sender_public_key, recipient_public_key) 86 .context(ks_err!("agree_key failed"))?; 87 let (ciphertext, iv, tag) = 88 aes_gcm_encrypt(message, &aes_key).context(ks_err!("aes_gcm_encrypt failed"))?; 89 Ok((sender_public_key, salt, iv, ciphertext, tag)) 90 } 91 92 /// Decrypt a message sent to us decrypt_message( &self, sender_public_key: &[u8], salt: &[u8], iv: &[u8], ciphertext: &[u8], tag: &[u8], ) -> Result<ZVec>93 pub fn decrypt_message( 94 &self, 95 sender_public_key: &[u8], 96 salt: &[u8], 97 iv: &[u8], 98 ciphertext: &[u8], 99 tag: &[u8], 100 ) -> Result<ZVec> { 101 let recipient_public_key = self.public_key()?; 102 let aes_key = self 103 .agree_key(salt, sender_public_key, sender_public_key, &recipient_public_key) 104 .context(ks_err!("agree_key failed"))?; 105 aes_gcm_decrypt(ciphertext, iv, tag, &aes_key).context(ks_err!("aes_gcm_decrypt failed")) 106 } 107 } 108 109 #[cfg(test)] 110 mod test { 111 use super::*; 112 113 #[test] test_crypto_roundtrip() -> Result<()>114 fn test_crypto_roundtrip() -> Result<()> { 115 let message = b"Hello world"; 116 let recipient = ECDHPrivateKey::generate()?; 117 let (sender_public_key, salt, iv, ciphertext, tag) = 118 ECDHPrivateKey::encrypt_message(&recipient.public_key()?, message)?; 119 let recipient = ECDHPrivateKey::from_private_key(&recipient.private_key()?)?; 120 let decrypted = 121 recipient.decrypt_message(&sender_public_key, &salt, &iv, &ciphertext, &tag)?; 122 let dc: &[u8] = &decrypted; 123 assert_eq!(message, dc); 124 Ok(()) 125 } 126 } 127