1 // Copyright 2024 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://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, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 15 //! Defines the Crypto trait and related types. 16 17 use crate::byte_array_wrapper; 18 use crate::constants::*; 19 use crate::error::DpeResult; 20 use crate::memory::{Message, SizedMessage}; 21 use zeroize::ZeroizeOnDrop; 22 23 byte_array_wrapper!(MacKey, HASH_SIZE, "MAC key"); 24 byte_array_wrapper!(EncryptionKey, ENCRYPTION_KEY_SIZE, "encryption key"); 25 byte_array_wrapper!(DhPublicKey, DH_PUBLIC_KEY_SIZE, "DH public key"); 26 byte_array_wrapper!(DhPrivateKey, DH_PRIVATE_KEY_SIZE, "DH private key"); 27 byte_array_wrapper!(Hash, HASH_SIZE, "hash"); 28 byte_array_wrapper!( 29 SigningPublicKey, 30 SIGNING_PUBLIC_KEY_SIZE, 31 "signing public key" 32 ); 33 byte_array_wrapper!( 34 SigningPrivateKey, 35 SIGNING_PRIVATE_KEY_SIZE, 36 "signing private key" 37 ); 38 byte_array_wrapper!( 39 SealingPublicKey, 40 SEALING_PUBLIC_KEY_SIZE, 41 "sealing public key" 42 ); 43 byte_array_wrapper!( 44 SealingPrivateKey, 45 SEALING_PRIVATE_KEY_SIZE, 46 "sealing private key" 47 ); 48 49 /// A session handshake message. 50 pub type HandshakeMessage = SizedMessage<MAX_HANDSHAKE_MESSAGE_SIZE>; 51 /// A session handshake payload. 52 pub type HandshakePayload = SizedMessage<MAX_HANDSHAKE_PAYLOAD_SIZE>; 53 /// A signature. 54 pub type Signature = SizedMessage<MAX_SIGNATURE_SIZE>; 55 56 /// A trait for committing previously staged changes. 57 pub trait Commit { 58 /// Commits a previously staged changes. When used with session cipher 59 /// state, the staged changes are typically counter increments that result 60 /// from encrypt or decrypt operations. commit(&mut self)61 fn commit(&mut self); 62 } 63 64 /// A trait for maintaining a counter. 65 pub trait Counter { 66 /// Returns the current counter value. n(&self) -> u6467 fn n(&self) -> u64; 68 /// Sets the counter value to `n`. set_n(&mut self, n: u64)69 fn set_n(&mut self, n: u64); 70 } 71 72 /// Provides cryptographic operations for encrypted sessions. 73 pub trait SessionCrypto { 74 /// A type to represent session cipher states. These are owned by and opaque 75 /// to the caller in `new_session_handshake` and `derive_session_handshake`. 76 type SessionCipherState: Commit + Counter; 77 78 /// Performs a session responder handshake for a new session. 79 /// 80 /// # Parameters 81 /// 82 /// * `static_dh_key`: The DPE session identity, which the client is 83 /// expected to already know. 84 /// * `initiator_handshake`: The handshake message received from the client. 85 /// * `payload`: The payload to include in the `responder_handshake`. 86 /// * `responder_handshake`: Receives the handshake message to be sent back 87 /// to the client. 88 /// * `decrypt_cipher_state`: Receives cipher state for decrypting incoming 89 /// session messages. This is intended to be passed to 90 /// [`SessionCrypto::session_decrypt`]. 91 /// * `encrypt_cipher_state`: Receives cipher state for encrypting outgoing 92 /// session messages. This is intended to be passed to 93 /// [`SessionCrypto::session_encrypt`]. 94 /// * `psk_seed`: Receives a PSK seed that can be used to construct a PSK to 95 /// be used when deriving a session (see 96 /// [`SessionCrypto::derive_session_handshake`]). 97 /// 98 /// # Errors 99 /// 100 /// This method allows implementers to return an error but it is expected to 101 /// be infallible. 102 #[allow(clippy::too_many_arguments)] new_session_handshake( static_dh_key: &DhPrivateKey, initiator_handshake: &HandshakeMessage, payload: &HandshakePayload, responder_handshake: &mut HandshakeMessage, decrypt_cipher_state: &mut Self::SessionCipherState, encrypt_cipher_state: &mut Self::SessionCipherState, psk_seed: &mut Hash, ) -> DpeResult<()>103 fn new_session_handshake( 104 static_dh_key: &DhPrivateKey, 105 initiator_handshake: &HandshakeMessage, 106 payload: &HandshakePayload, 107 responder_handshake: &mut HandshakeMessage, 108 decrypt_cipher_state: &mut Self::SessionCipherState, 109 encrypt_cipher_state: &mut Self::SessionCipherState, 110 psk_seed: &mut Hash, 111 ) -> DpeResult<()>; 112 113 /// Performs a session responder handshake for a derived session. In 114 /// contrast to a new session handshake, a derived session does not use a 115 /// static key, but a pre-shared key (PSK) derived from an existing session. 116 /// 117 /// # Parameters 118 /// 119 /// * `psk`: A PSK derived from an existing session. 120 /// * `initiator_handshake`: The handshake message received from the client. 121 /// * `payload`: The payload to include in the `responder_handshake`. 122 /// * `responder_handshake`: Receives the handshake message to be sent back 123 /// to the client. 124 /// * `decrypt_cipher_state`: Receives cipher state for decrypting incoming 125 /// session messages. This is intended to be passed to 126 /// [`SessionCrypto::session_decrypt`]. 127 /// * `encrypt_cipher_state`: Receives cipher state for encrypting outgoing 128 /// session messages. This is intended to be passed to 129 /// [`SessionCrypto::session_encrypt`]. 130 /// * `psk_seed`: Receives a PSK seed that can be used to construct a PSK to 131 /// be used when deriving another session. 132 /// 133 /// # Errors 134 /// 135 /// This method allows implementers to return an error but it is expected to 136 /// be infallible. 137 #[allow(clippy::too_many_arguments)] derive_session_handshake( psk: &Hash, initiator_handshake: &HandshakeMessage, payload: &HandshakePayload, responder_handshake: &mut HandshakeMessage, decrypt_cipher_state: &mut Self::SessionCipherState, encrypt_cipher_state: &mut Self::SessionCipherState, psk_seed: &mut Hash, ) -> DpeResult<()>138 fn derive_session_handshake( 139 psk: &Hash, 140 initiator_handshake: &HandshakeMessage, 141 payload: &HandshakePayload, 142 responder_handshake: &mut HandshakeMessage, 143 decrypt_cipher_state: &mut Self::SessionCipherState, 144 encrypt_cipher_state: &mut Self::SessionCipherState, 145 psk_seed: &mut Hash, 146 ) -> DpeResult<()>; 147 148 /// Derives a PSK from session state: `psk_seed`, `decrypt_cipher_state`, 149 /// and `encrypt_cipher_state`. The returned PSK is appropriate as an 150 /// argument to [`derive_session_handshake`]. 151 /// 152 /// # Errors 153 /// 154 /// This method allows implementers to return an error but it is expected to 155 /// be infallible. 156 /// 157 /// [`derive_session_handshake`]: #method.derive_session_handshake derive_psk_from_session( psk_seed: &Hash, decrypt_cipher_state: &Self::SessionCipherState, encrypt_cipher_state: &Self::SessionCipherState, ) -> DpeResult<Hash>158 fn derive_psk_from_session( 159 psk_seed: &Hash, 160 decrypt_cipher_state: &Self::SessionCipherState, 161 encrypt_cipher_state: &Self::SessionCipherState, 162 ) -> DpeResult<Hash>; 163 164 /// Encrypts an outgoing session message with the given `cipher_state`. The 165 /// `in_place_buffer` both provides the plaintext message and receives the 166 /// corresponding ciphertext. 167 /// 168 /// # Errors 169 /// 170 /// This method fails with an OutOfMemory error if the encryption overhead 171 /// does not fit in the buffer. session_encrypt( cipher_state: &mut Self::SessionCipherState, in_place_buffer: &mut Message, ) -> DpeResult<()>172 fn session_encrypt( 173 cipher_state: &mut Self::SessionCipherState, 174 in_place_buffer: &mut Message, 175 ) -> DpeResult<()>; 176 177 /// Decrypts an incoming session message with the given `cipher_state`. The 178 /// `in_place_buffer` both provides the ciphertext message and receives the 179 /// corresponding plaintext. 180 /// 181 /// # Errors 182 /// 183 /// This method fails with an InvalidArgument error if the ciphertext cannot 184 /// be decrypted (e.g. if tag authentication fails). session_decrypt( cipher_state: &mut Self::SessionCipherState, in_place_buffer: &mut Message, ) -> DpeResult<()>185 fn session_decrypt( 186 cipher_state: &mut Self::SessionCipherState, 187 in_place_buffer: &mut Message, 188 ) -> DpeResult<()>; 189 } 190 191 /// Provides cryptographic operations. These operations are specifically for DPE 192 /// concepts, defined by a DPE profile, and to be invoked by a DPE instance. 193 pub trait Crypto { 194 /// An associated [`SessionCrypto`] type. 195 type S: SessionCrypto; 196 197 /// Returns a hash of `input`. 198 /// 199 /// # Errors 200 /// 201 /// This method is infallible. hash(input: &[u8]) -> Hash202 fn hash(input: &[u8]) -> Hash; 203 204 /// Returns a hash over all items in `iter`, in order. 205 /// 206 /// # Errors 207 /// 208 /// This method is infallible. hash_iter<'a>(iter: impl Iterator<Item = &'a [u8]>) -> Hash209 fn hash_iter<'a>(iter: impl Iterator<Item = &'a [u8]>) -> Hash; 210 211 /// Runs a key derivation function (KDF) to derive a key the length of the 212 /// `derived_key` buffer. The inputs are interpreted as documented by the 213 /// [HKDF](<https://datatracker.ietf.org/doc/html/rfc5869>) scheme. The 214 /// implementation doesn't need to be HKDF specifically but needs to work 215 /// with HKDF-style inputs. 216 /// 217 /// # Parameters 218 /// 219 /// * `kdf_ikm`: input keying material 220 /// * `kdf_info`: HKDF-style info (optional) 221 /// * `kdf_salt`: HKDF-style salt (optional) 222 /// * `derived_key`: Receives the derived key 223 /// 224 /// # Errors 225 /// 226 /// Fails with an `InternalError` if `derived_key` is too large. kdf( kdf_ikm: &[u8], kdf_info: &[u8], kdf_salt: &[u8], derived_key: &mut [u8], ) -> DpeResult<()>227 fn kdf( 228 kdf_ikm: &[u8], 229 kdf_info: &[u8], 230 kdf_salt: &[u8], 231 derived_key: &mut [u8], 232 ) -> DpeResult<()>; 233 234 /// Derives an asymmetric key pair for signing from a given `seed`. 235 /// 236 /// # Errors 237 /// 238 /// This method allows implementers to return an error but it is expected to 239 /// be infallible. signing_keypair_from_seed( seed: &Hash, ) -> DpeResult<(SigningPublicKey, SigningPrivateKey)>240 fn signing_keypair_from_seed( 241 seed: &Hash, 242 ) -> DpeResult<(SigningPublicKey, SigningPrivateKey)>; 243 244 /// Derives an asymmetric key pair for sealing from a given `seed`. 245 /// 246 /// # Errors 247 /// 248 /// This method allows implementers to return an error but it is expected to 249 /// be infallible. sealing_keypair_from_seed( seed: &Hash, ) -> DpeResult<(SealingPublicKey, SealingPrivateKey)>250 fn sealing_keypair_from_seed( 251 seed: &Hash, 252 ) -> DpeResult<(SealingPublicKey, SealingPrivateKey)>; 253 254 /// Computes a MAC over `data` using the given `key`. 255 /// 256 /// # Errors 257 /// 258 /// This method allows implementers to return an error but it is expected to 259 /// be infallible. mac(key: &MacKey, data: &[u8]) -> DpeResult<Hash>260 fn mac(key: &MacKey, data: &[u8]) -> DpeResult<Hash>; 261 262 /// Generates a signature over `tbs` using the given `key`. 263 /// 264 /// # Errors 265 /// 266 /// This method allows implementers to return an error but it is expected to 267 /// be infallible. sign(key: &SigningPrivateKey, tbs: &[u8]) -> DpeResult<Signature>268 fn sign(key: &SigningPrivateKey, tbs: &[u8]) -> DpeResult<Signature>; 269 270 /// Encrypts data using the given `key` in a way that it can be decrypted by 271 /// the `unseal` method with the same `key`. The `in_place_buffer` both 272 /// provides the plaintext input and receives the ciphertext output. 273 /// 274 /// # Errors 275 /// 276 /// Fails with OutOfMemory if the ciphertext, including overhead, does not 277 /// fit in the buffer. seal( key: &EncryptionKey, in_place_buffer: &mut Message, ) -> DpeResult<()>278 fn seal( 279 key: &EncryptionKey, 280 in_place_buffer: &mut Message, 281 ) -> DpeResult<()>; 282 283 /// Decrypts and authenticates data previously generated by the `seal` 284 /// method using the given 'key'. The `in_place_buffer` both provides the 285 /// ciphertext input and receives the plaintext output. 286 /// 287 /// # Errors 288 /// 289 /// Fails with InvalidArgument if authenticated decryption fails. unseal( key: &EncryptionKey, in_place_buffer: &mut Message, ) -> DpeResult<()>290 fn unseal( 291 key: &EncryptionKey, 292 in_place_buffer: &mut Message, 293 ) -> DpeResult<()>; 294 295 /// Encrypts data using an asymmetric scheme and the given `public_key` in 296 /// a way that it can be decrypted by the `unseal_asymmetric` method given 297 /// the corresponding private key. While this method is useful for testing, 298 /// a DPE does not use this during normal operation. The `in_place_buffer` 299 /// both provides the plaintext input and receives the ciphertext output. 300 /// 301 /// # Errors 302 /// 303 /// Fails with OutOfMemory if the ciphertext, including overhead, does not 304 /// fit in the buffer. seal_asymmetric( public_key: &SealingPublicKey, in_place_buffer: &mut Message, ) -> DpeResult<()>305 fn seal_asymmetric( 306 public_key: &SealingPublicKey, 307 in_place_buffer: &mut Message, 308 ) -> DpeResult<()>; 309 310 /// Decrypts data using an asymmetric scheme and the give `key`. The 311 /// `in_place_buffer` both provides the ciphertext input and receives the 312 /// plaintext output. 313 /// 314 /// # Errors 315 /// 316 /// Fails with InvalidArgument if the ciphertext cannot be decrypted. unseal_asymmetric( key: &SealingPrivateKey, in_place_buffer: &mut Message, ) -> DpeResult<()>317 fn unseal_asymmetric( 318 key: &SealingPrivateKey, 319 in_place_buffer: &mut Message, 320 ) -> DpeResult<()>; 321 } 322