underhill_attestation/
crypto.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Implementation of the required cryptographic functions for the crate.
5
6use openhcl_attestation_protocol::vmgs::AES_GCM_KEY_LENGTH;
7use openhcl_attestation_protocol::vmgs::HMAC_SHA_256_KEY_LENGTH;
8use openssl::pkey::Private;
9use openssl::rsa::Rsa;
10use openssl_kdf::kdf::Kbkdf;
11use thiserror::Error;
12
13#[derive(Debug, Error)]
14pub(crate) enum KbkdfError {
15    #[error("KDF derivation failed")]
16    Derive(#[from] openssl_kdf::kdf::KdfError),
17}
18
19#[derive(Debug, Error)]
20pub(crate) enum Pkcs11RsaAesKeyUnwrapError {
21    #[error("expected wrapped AES key blob to be {0} bytes, but found {1} bytes")]
22    UndersizedWrappedAesKey(usize, usize),
23    #[error("wrapped RSA key blob cannot be empty")]
24    EmptyWrappedRsaKey,
25    #[error("RSA unwrap failed")]
26    RsaUnwrap(#[from] RsaOaepError),
27    #[error("AES unwrap failed")]
28    AesUnwrap(#[from] AesKeyWrapWithPaddingError),
29    #[error("failed to convert PKCS #8 DER format to PKey")]
30    ConvertPkcs8DerToPkey(#[source] openssl::error::ErrorStack),
31    #[error("failed to get an RSA key from PKey")]
32    PkeyToRsa(#[from] openssl::error::ErrorStack),
33}
34
35#[derive(Debug, Error)]
36pub(crate) enum RsaOaepError {
37    #[error("failed to convert an RSA key to PKey")]
38    RsaToPkey(#[source] openssl::error::ErrorStack),
39    #[error("Pkeyctx::new() failed")]
40    PkeyCtxNew(#[source] openssl::error::ErrorStack),
41    #[error("PkeyCtx encrypt_init() failed")]
42    PkeyCtxEncryptInit(#[source] openssl::error::ErrorStack),
43    #[error("PkeyCtx decrypt_init() failed")]
44    PkeyCtxDecryptInit(#[source] openssl::error::ErrorStack),
45    #[error("PkeyCtx set_rsa_padding() failed")]
46    PkeyCtxSetRsaPadding(#[source] openssl::error::ErrorStack),
47    #[error("PkeyCtx set_rsa_oaep_md() failed")]
48    PkeyCtxSetRsaOaepMd(#[source] openssl::error::ErrorStack),
49    #[error("Encryption failed, OAEP hash algorithm {1:?}")]
50    Encrypt(#[source] openssl::error::ErrorStack, RsaOaepHashAlgorithm),
51    #[error("Decryption failed, OAEP hash algorithm {1:?}")]
52    Decrypt(#[source] openssl::error::ErrorStack, RsaOaepHashAlgorithm),
53}
54
55#[derive(Debug, Error)]
56pub(crate) enum AesKeyWrapWithPaddingError {
57    #[error("invalid wrapping key size {0}")]
58    InvalidWrappingKeySize(usize),
59    #[error("Invalid unwrapping key size {0}")]
60    InvalidUnwrappingKeySize(usize),
61    #[error("CipherCtx::new failed")]
62    CipherCtxNew(#[source] openssl::error::ErrorStack),
63    #[error("CipherCtx encrypt_init() failed")]
64    CipherCtxEncryptInit(#[source] openssl::error::ErrorStack),
65    #[error("CipherCtx decrypt_init() failed")]
66    CipherCtxDecryptInit(#[source] openssl::error::ErrorStack),
67    #[error("AES key wrap with padding update failed")]
68    WrapUpdate(#[source] openssl::error::ErrorStack),
69    #[error("AES key unwrap with padding update failed")]
70    UnwrapUpdate(#[source] openssl::error::ErrorStack),
71}
72
73#[derive(Debug, Error)]
74pub(crate) enum Aes256CbcError {
75    #[error("CipherCtx::new failed")]
76    CipherCtxNew(#[source] openssl::error::ErrorStack),
77    #[error("CipherCtx encrypt_init() failed")]
78    CipherCtxEncryptInit(#[source] openssl::error::ErrorStack),
79    #[error("CipherCtx decrypt_init() failed")]
80    CipherCtxDecryptInit(#[source] openssl::error::ErrorStack),
81    #[error("AES-256-CBC encrypt failed")]
82    Encrypt(#[source] openssl::error::ErrorStack),
83    #[error("AES-256-CBC decrypt failed")]
84    Decrypt(#[source] openssl::error::ErrorStack),
85}
86
87#[derive(Debug, Error)]
88pub(crate) enum HmacSha256Error {
89    #[error("failed to convert an HMAC key to PKey")]
90    HmacKeyToPkey(#[source] openssl::error::ErrorStack),
91    #[error("MdCtx::new failed")]
92    MdCtxNew(#[source] openssl::error::ErrorStack),
93    #[error("HMAC init failed")]
94    HmacInit(#[source] openssl::error::ErrorStack),
95    #[error("HMAC update failed")]
96    HmacUpdate(#[source] openssl::error::ErrorStack),
97    #[error("HMAC final failed")]
98    HmacFinal(#[source] openssl::error::ErrorStack),
99    #[error("failed to get the required HMAC output size")]
100    GetHmacRequiredSize(#[source] openssl::error::ErrorStack),
101    #[error("HMAC SHA 256 failed")]
102    OpenSSL(#[from] openssl::error::ErrorStack),
103    #[error("invalid output size {0}, expected {1}")]
104    InvalidOutputSize(usize, usize),
105}
106
107/// KBKDF from SP800-108, using EVP_KDF functionality of OpenSSL
108pub fn derive_key(
109    key: &[u8],
110    context: &[u8],
111    label: &[u8],
112) -> Result<[u8; AES_GCM_KEY_LENGTH], KbkdfError> {
113    // SP800-108's Label is called "Salt" in OpenSSL
114    let mut kdf = Kbkdf::new(
115        openssl::hash::MessageDigest::sha256(),
116        label.to_vec(),
117        key.to_vec(),
118    );
119    kdf.set_context(context.to_vec());
120    let mut output = [0; AES_GCM_KEY_LENGTH];
121    openssl_kdf::kdf::derive(kdf, &mut output)?;
122    Ok(output)
123}
124
125/// PKCS#11 RSA AES key unwrap implementation
126pub fn pkcs11_rsa_aes_key_unwrap(
127    unwrapping_rsa_key: &Rsa<Private>,
128    wrapped_key_blob: &[u8],
129) -> Result<Rsa<Private>, Pkcs11RsaAesKeyUnwrapError> {
130    let modulus_size = unwrapping_rsa_key.size() as usize;
131
132    let (wrapped_aes_key, wrapped_rsa_key) = wrapped_key_blob
133        .split_at_checked(modulus_size)
134        .ok_or_else(|| {
135            Pkcs11RsaAesKeyUnwrapError::UndersizedWrappedAesKey(
136                modulus_size,
137                wrapped_key_blob.len(),
138            )
139        })?;
140
141    if wrapped_rsa_key.is_empty() {
142        return Err(Pkcs11RsaAesKeyUnwrapError::EmptyWrappedRsaKey);
143    }
144
145    let unwrapped_aes_key = rsa_oaep_decrypt(
146        unwrapping_rsa_key,
147        wrapped_aes_key,
148        RsaOaepHashAlgorithm::Sha1,
149    )
150    .map_err(Pkcs11RsaAesKeyUnwrapError::RsaUnwrap)?;
151    let unwrapped_rsa_key = aes_key_unwrap_with_padding(&unwrapped_aes_key, wrapped_rsa_key)
152        .map_err(Pkcs11RsaAesKeyUnwrapError::AesUnwrap)?;
153    let unwrapped_rsa_key = openssl::pkey::PKey::private_key_from_pkcs8(&unwrapped_rsa_key)
154        .map_err(Pkcs11RsaAesKeyUnwrapError::ConvertPkcs8DerToPkey)?;
155    let unwrapped_rsa_key = unwrapped_rsa_key
156        .rsa()
157        .map_err(Pkcs11RsaAesKeyUnwrapError::PkeyToRsa)?;
158
159    Ok(unwrapped_rsa_key)
160}
161
162/// Support RSA-OAEP with SHA-1 or SHA-256 from OpenSSL
163#[derive(Debug)]
164pub enum RsaOaepHashAlgorithm {
165    /// SHA-1
166    Sha1,
167    /// SHA-256
168    Sha256,
169}
170
171/// RSA-OAEP encrypt
172pub fn rsa_oaep_encrypt(
173    rsa: &Rsa<Private>,
174    input: &[u8],
175    hash_algorithm: RsaOaepHashAlgorithm,
176) -> Result<Vec<u8>, RsaOaepError> {
177    let pkey = openssl::pkey::PKey::from_rsa(rsa.to_owned()).map_err(RsaOaepError::RsaToPkey)?;
178    let mut ctx = openssl::pkey_ctx::PkeyCtx::new(&pkey).map_err(RsaOaepError::PkeyCtxNew)?;
179
180    ctx.encrypt_init()
181        .map_err(RsaOaepError::PkeyCtxEncryptInit)?;
182    ctx.set_rsa_padding(openssl::rsa::Padding::PKCS1_OAEP)
183        .map_err(RsaOaepError::PkeyCtxSetRsaPadding)?;
184
185    match hash_algorithm {
186        RsaOaepHashAlgorithm::Sha1 => ctx.set_rsa_oaep_md(openssl::md::Md::sha1()),
187        RsaOaepHashAlgorithm::Sha256 => ctx.set_rsa_oaep_md(openssl::md::Md::sha256()),
188    }
189    .map_err(RsaOaepError::PkeyCtxSetRsaOaepMd)?;
190
191    let mut output = vec![];
192    ctx.encrypt_to_vec(input, &mut output)
193        .map_err(|e| RsaOaepError::Encrypt(e, hash_algorithm))?;
194
195    Ok(output)
196}
197
198/// RSA-OAEP decrypt
199pub fn rsa_oaep_decrypt(
200    rsa: &Rsa<Private>,
201    input: &[u8],
202    hash_algorithm: RsaOaepHashAlgorithm,
203) -> Result<Vec<u8>, RsaOaepError> {
204    let pkey = openssl::pkey::PKey::from_rsa(rsa.to_owned()).map_err(RsaOaepError::RsaToPkey)?;
205    let mut ctx = openssl::pkey_ctx::PkeyCtx::new(&pkey).map_err(RsaOaepError::PkeyCtxNew)?;
206
207    ctx.decrypt_init()
208        .map_err(RsaOaepError::PkeyCtxDecryptInit)?;
209    ctx.set_rsa_padding(openssl::rsa::Padding::PKCS1_OAEP)
210        .map_err(RsaOaepError::PkeyCtxSetRsaPadding)?;
211
212    match hash_algorithm {
213        RsaOaepHashAlgorithm::Sha1 => ctx.set_rsa_oaep_md(openssl::md::Md::sha1()),
214        RsaOaepHashAlgorithm::Sha256 => ctx.set_rsa_oaep_md(openssl::md::Md::sha256()),
215    }
216    .map_err(RsaOaepError::PkeyCtxSetRsaOaepMd)?;
217
218    let mut output = vec![];
219    ctx.decrypt_to_vec(input, &mut output)
220        .map_err(|e| RsaOaepError::Decrypt(e, hash_algorithm))?;
221
222    Ok(output)
223}
224
225/// Key wrap with padding scheme (RFC 5649) implementation from OpenSSL
226pub fn aes_key_wrap_with_padding(
227    wrapping_key: &[u8],
228    payload: &[u8],
229) -> Result<Vec<u8>, AesKeyWrapWithPaddingError> {
230    let cipher = match wrapping_key.len() {
231        16 => openssl::cipher::Cipher::aes_128_wrap_pad(),
232        24 => openssl::cipher::Cipher::aes_192_wrap_pad(),
233        32 => openssl::cipher::Cipher::aes_256_wrap_pad(),
234        key_size => Err(AesKeyWrapWithPaddingError::InvalidWrappingKeySize(key_size))?,
235    };
236    let padding = 8 - payload.len() % 8;
237    let mut output = vec![0; payload.len() + padding + cipher.block_size()];
238    let mut ctx =
239        openssl::cipher_ctx::CipherCtx::new().map_err(AesKeyWrapWithPaddingError::CipherCtxNew)?;
240
241    ctx.set_flags(openssl::cipher_ctx::CipherCtxFlags::FLAG_WRAP_ALLOW);
242    ctx.encrypt_init(Some(cipher), Some(wrapping_key), None)
243        .map_err(AesKeyWrapWithPaddingError::CipherCtxEncryptInit)?;
244
245    let count = ctx
246        .cipher_update(payload, Some(&mut output))
247        .map_err(AesKeyWrapWithPaddingError::WrapUpdate)?;
248    // DEVNOTE: Skip the `cipher_final()`, which is effectively a no-op for this operation
249    // according to OpenSSL implementation.
250    output.truncate(count);
251
252    Ok(output)
253}
254
255/// Key unwrap with padding scheme (RFC 5649) implementation from OpenSSL
256pub fn aes_key_unwrap_with_padding(
257    unwrapping_key: &[u8],
258    wrapped_payload: &[u8],
259) -> Result<Vec<u8>, AesKeyWrapWithPaddingError> {
260    let cipher = match unwrapping_key.len() {
261        16 => openssl::cipher::Cipher::aes_128_wrap_pad(),
262        24 => openssl::cipher::Cipher::aes_192_wrap_pad(),
263        32 => openssl::cipher::Cipher::aes_256_wrap_pad(),
264        key_size => Err(AesKeyWrapWithPaddingError::InvalidUnwrappingKeySize(
265            key_size,
266        ))?,
267    };
268    let mut output = vec![0; wrapped_payload.len() + cipher.block_size()];
269    let mut ctx =
270        openssl::cipher_ctx::CipherCtx::new().map_err(AesKeyWrapWithPaddingError::CipherCtxNew)?;
271
272    ctx.set_flags(openssl::cipher_ctx::CipherCtxFlags::FLAG_WRAP_ALLOW);
273    ctx.decrypt_init(Some(cipher), Some(unwrapping_key), None)
274        .map_err(AesKeyWrapWithPaddingError::CipherCtxDecryptInit)?;
275
276    let count = ctx
277        .cipher_update(wrapped_payload, Some(&mut output))
278        .map_err(AesKeyWrapWithPaddingError::UnwrapUpdate)?;
279    // DEVNOTE: Skip the `cipher_final()`, which is effectively a no-op for this operation
280    // according to OpenSSL implementation.
281    output.truncate(count);
282
283    Ok(output)
284}
285
286/// AES-256 CBC encrypt
287pub fn aes_256_cbc_encrypt(key: &[u8], data: &[u8], iv: &[u8]) -> Result<Vec<u8>, Aes256CbcError> {
288    let cipher = openssl::cipher::Cipher::aes_256_cbc();
289    let mut output = vec![0u8; data.len() + cipher.block_size()];
290    let mut ctx = openssl::cipher_ctx::CipherCtx::new().map_err(Aes256CbcError::CipherCtxNew)?;
291
292    ctx.encrypt_init(Some(cipher), Some(key), Some(iv))
293        .map_err(Aes256CbcError::CipherCtxEncryptInit)?;
294    ctx.set_padding(false);
295
296    let count = ctx
297        .cipher_update(data, Some(&mut output))
298        .map_err(Aes256CbcError::Encrypt)?;
299    let rest = ctx
300        .cipher_final(&mut output[count..])
301        .map_err(Aes256CbcError::Encrypt)?;
302    output.truncate(count + rest);
303
304    Ok(output)
305}
306
307/// AES-256 CBC decrypt
308pub fn aes_256_cbc_decrypt(key: &[u8], data: &[u8], iv: &[u8]) -> Result<Vec<u8>, Aes256CbcError> {
309    let cipher = openssl::cipher::Cipher::aes_256_cbc();
310    let mut output = vec![0u8; data.len() + cipher.block_size()];
311    let mut ctx = openssl::cipher_ctx::CipherCtx::new().map_err(Aes256CbcError::CipherCtxNew)?;
312
313    ctx.decrypt_init(Some(cipher), Some(key), Some(iv))
314        .map_err(Aes256CbcError::CipherCtxDecryptInit)?;
315    ctx.set_padding(false);
316
317    let count = ctx
318        .cipher_update(data, Some(&mut output))
319        .map_err(Aes256CbcError::Decrypt)?;
320    let rest = ctx
321        .cipher_final(&mut output[count..])
322        .map_err(Aes256CbcError::Decrypt)?;
323    output.truncate(count + rest);
324
325    Ok(output)
326}
327
328/// HMAC-SHA-256
329pub fn hmac_sha_256(
330    key: &[u8],
331    data: &[u8],
332) -> Result<[u8; HMAC_SHA_256_KEY_LENGTH], HmacSha256Error> {
333    let pkey = openssl::pkey::PKey::hmac(key).map_err(HmacSha256Error::HmacKeyToPkey)?;
334    let mut ctx = openssl::md_ctx::MdCtx::new().map_err(HmacSha256Error::MdCtxNew)?;
335
336    ctx.digest_sign_init(Some(openssl::md::Md::sha256()), &pkey)
337        .map_err(HmacSha256Error::HmacInit)?;
338    ctx.digest_sign_update(data)
339        .map_err(HmacSha256Error::HmacUpdate)?;
340
341    let size = ctx
342        .digest_sign_final(None)
343        .map_err(HmacSha256Error::GetHmacRequiredSize)?;
344    if size != HMAC_SHA_256_KEY_LENGTH {
345        Err(HmacSha256Error::InvalidOutputSize(
346            size,
347            HMAC_SHA_256_KEY_LENGTH,
348        ))?
349    }
350
351    let mut output = [0u8; HMAC_SHA_256_KEY_LENGTH];
352    ctx.digest_sign_final(Some(&mut output))
353        .map_err(HmacSha256Error::HmacFinal)?;
354
355    Ok(output)
356}
357
358/// SHA-256
359pub fn sha_256(data: &[u8]) -> [u8; 32] {
360    let mut hasher = openssl::sha::Sha256::new();
361    hasher.update(data);
362    hasher.finish()
363}
364
365#[cfg(test)]
366mod tests {
367    use super::*;
368
369    #[test]
370    fn kdf_kat_one() {
371        let key = [0; 32];
372        let context = [
373            0x28, 0x84, 0x18, 0x6c, 0xfe, 0xd2, 0x50, 0x41, 0x10, 0x69, 0x8b, 0x45, 0xd4, 0x80,
374            0x72, 0x88, 0xdf, 0x67, 0x4c, 0x48, 0x26, 0x19, 0x7a, 0x98, 0x69, 0x88, 0xaf, 0x96,
375            0x05, 0x62, 0xf5, 0x7f,
376        ];
377        let expected_result = [
378            0x9d, 0xb5, 0x8b, 0xb7, 0x0c, 0xa6, 0xcb, 0x6f, 0xaa, 0xe3, 0x81, 0x74, 0x64, 0x21,
379            0x76, 0xfa, 0x0d, 0xed, 0x28, 0x67, 0x30, 0x76, 0x90, 0x83, 0x83, 0xa0, 0x1a, 0xd7,
380            0x2e, 0xc3, 0xe2, 0x3b,
381        ];
382
383        let result = derive_key(&key, &context, crate::VMGS_KEY_DERIVE_LABEL).unwrap();
384
385        assert_eq!(result, expected_result);
386    }
387
388    #[test]
389    fn kdf_kat_two() {
390        let key = [0; 32];
391        let context = [
392            0xd6, 0x8a, 0x8d, 0x52, 0x7c, 0x5c, 0xa5, 0x9b, 0x19, 0x5a, 0xe7, 0x45, 0x6c, 0x3f,
393            0xef, 0x4d, 0x0e, 0xb0, 0xbe, 0x16, 0xc7, 0x8d, 0x77, 0xbd, 0x28, 0x5a, 0xa1, 0x45,
394            0x3e, 0x24, 0xeb, 0x3f,
395        ];
396        let expected_result = [
397            0x0a, 0xda, 0x54, 0x91, 0xd6, 0x09, 0x92, 0x87, 0x2f, 0xd7, 0x1a, 0x15, 0x71, 0x24,
398            0x82, 0x36, 0x25, 0xb4, 0xb9, 0x54, 0xc2, 0xf4, 0xeb, 0x47, 0x02, 0x88, 0x42, 0x7b,
399            0x1f, 0x8e, 0xdf, 0x3d,
400        ];
401
402        let result = derive_key(&key, &context, crate::VMGS_KEY_DERIVE_LABEL).unwrap();
403
404        assert_eq!(result, expected_result);
405    }
406
407    #[test]
408    fn test_aes_key_wrap_with_padding_kat() {
409        const KEK: [u8; 24] = [
410            0x58, 0x40, 0xdf, 0x6e, 0x29, 0xb0, 0x2a, 0xf1, 0xab, 0x49, 0x3b, 0x70, 0x5b, 0xf1,
411            0x6e, 0xa1, 0xae, 0x83, 0x38, 0xf4, 0xdc, 0xc1, 0x76, 0xa8,
412        ];
413        const KEY20: [u8; 20] = [
414            0xc3, 0x7b, 0x7e, 0x64, 0x92, 0x58, 0x43, 0x40, 0xbe, 0xd1, 0x22, 0x07, 0x80, 0x89,
415            0x41, 0x15, 0x50, 0x68, 0xf7, 0x38,
416        ];
417        const WRAP20: [u8; 32] = [
418            0x13, 0x8b, 0xde, 0xaa, 0x9b, 0x8f, 0xa7, 0xfc, 0x61, 0xf9, 0x77, 0x42, 0xe7, 0x22,
419            0x48, 0xee, 0x5a, 0xe6, 0xae, 0x53, 0x60, 0xd1, 0xae, 0x6a, 0x5f, 0x54, 0xf3, 0x73,
420            0xfa, 0x54, 0x3b, 0x6a,
421        ];
422        const KEY7: [u8; 7] = [0x46, 0x6f, 0x72, 0x50, 0x61, 0x73, 0x69];
423        const WRAP7: [u8; 16] = [
424            0xaf, 0xbe, 0xb0, 0xf0, 0x7d, 0xfb, 0xf5, 0x41, 0x92, 0x00, 0xf2, 0xcc, 0xb5, 0x0b,
425            0xb2, 0x4f,
426        ];
427
428        let result = aes_key_wrap_with_padding(&KEK, &KEY20);
429        assert!(result.is_ok());
430        let wrapped_key = result.unwrap();
431        assert_eq!(wrapped_key, WRAP20);
432
433        let result = aes_key_unwrap_with_padding(&KEK, &WRAP20);
434        assert!(result.is_ok());
435        let unwrapped_key = result.unwrap();
436        assert_eq!(unwrapped_key, KEY20);
437
438        let result = aes_key_wrap_with_padding(&KEK, &KEY7);
439        assert!(result.is_ok());
440        let wrapped_key = result.unwrap();
441        assert_eq!(wrapped_key, WRAP7);
442
443        let result = aes_key_unwrap_with_padding(&KEK, &WRAP7);
444        assert!(result.is_ok());
445        let unwrapped_key = result.unwrap();
446        assert_eq!(unwrapped_key, KEY7);
447    }
448
449    #[test]
450    fn test_aes_key_wrap_with_padding() {
451        const KEY: [u8; 32] = [
452            0x3f, 0xf4, 0xdb, 0xdb, 0x74, 0xd9, 0x3d, 0x22, 0x35, 0xc6, 0x7c, 0x9e, 0x17, 0x6a,
453            0x88, 0x7f, 0xf9, 0x11, 0xd6, 0x5b, 0x5a, 0x56, 0x06, 0xa7, 0xfb, 0x52, 0x58, 0xfc,
454            0x4e, 0x76, 0xce, 0x49,
455        ];
456
457        const AES_WRAPPED_KEY: [u8; 40] = [
458            0x56, 0x53, 0xe9, 0x29, 0xa9, 0x35, 0x0c, 0x32, 0xd0, 0x24, 0x22, 0xb4, 0x98, 0xe1,
459            0x13, 0xe7, 0x4a, 0x81, 0xc1, 0xf3, 0xb2, 0xa6, 0x27, 0x70, 0x6e, 0x0d, 0x12, 0x97,
460            0xfd, 0xa5, 0x07, 0x0a, 0x5e, 0xb0, 0xd2, 0xde, 0xb2, 0x8a, 0x06, 0x72,
461        ];
462
463        const WRAPPING_KEY: [u8; 32] = [
464            0x10, 0x84, 0xD2, 0x2F, 0x53, 0x5F, 0xD3, 0x10, 0xE2, 0xC6, 0x17, 0x31, 0x3D, 0xCA,
465            0xE7, 0xEF, 0x19, 0xDD, 0x45, 0x2A, 0xED, 0x1C, 0xE6, 0xB1, 0xBE, 0xF5, 0xB9, 0xD0,
466            0x1B, 0xF1, 0x5F, 0x44,
467        ];
468
469        let result = aes_key_wrap_with_padding(&WRAPPING_KEY, &KEY);
470        assert!(result.is_ok());
471        let wrapped_key = result.unwrap();
472        assert_eq!(wrapped_key, AES_WRAPPED_KEY);
473
474        let result = aes_key_unwrap_with_padding(&WRAPPING_KEY, &AES_WRAPPED_KEY);
475        assert!(result.is_ok());
476        let unwrapped_key = result.unwrap();
477        assert_eq!(unwrapped_key, KEY);
478    }
479
480    #[test]
481    fn fail_to_unwrap_pkcs11_rsa_aep_with_undersized_wrapped_key_blob() {
482        let rsa = Rsa::generate(2048).unwrap();
483
484        // undersized aes key blob
485        let wrapped_key_blob = vec![0; 256 - 1];
486        let result = pkcs11_rsa_aes_key_unwrap(&rsa, &wrapped_key_blob);
487        assert!(result.is_err());
488        assert_eq!(
489            result.unwrap_err().to_string(),
490            "expected wrapped AES key blob to be 256 bytes, but found 255 bytes".to_string()
491        );
492
493        // empty rsa key blob
494        let wrapped_key_blob = vec![0; 256];
495        let result = pkcs11_rsa_aes_key_unwrap(&rsa, &wrapped_key_blob);
496        assert!(result.is_err());
497        assert_eq!(
498            result.unwrap_err().to_string(),
499            "wrapped RSA key blob cannot be empty".to_string()
500        );
501    }
502
503    #[test]
504    fn test_pkcs11_rsa_aes_key_unwrap() {
505        let target_key = Rsa::generate(2048).unwrap();
506        let pkcs8_target_key = openssl::pkey::PKey::from_rsa(target_key.clone())
507            .unwrap()
508            .private_key_to_pkcs8()
509            .unwrap();
510
511        let mut wrapping_aes_key = [0u8; 32];
512        openssl::rand::rand_bytes(&mut wrapping_aes_key[..]).unwrap();
513
514        let wrapping_rsa_key = Rsa::generate(2048).unwrap();
515        let wrapped_aes_key = rsa_oaep_encrypt(
516            &wrapping_rsa_key,
517            &wrapping_aes_key,
518            RsaOaepHashAlgorithm::Sha1,
519        )
520        .unwrap();
521        let wrapped_target_key =
522            aes_key_wrap_with_padding(&wrapping_aes_key, &pkcs8_target_key).unwrap();
523        let wrapped_key_blob = [wrapped_aes_key, wrapped_target_key].concat();
524        let unwrapped_target_key =
525            pkcs11_rsa_aes_key_unwrap(&wrapping_rsa_key, wrapped_key_blob.as_slice()).unwrap();
526        assert_eq!(
527            unwrapped_target_key.private_key_to_der().unwrap(),
528            target_key.private_key_to_der().unwrap()
529        );
530    }
531
532    #[test]
533    fn test_hmac_sha_256() {
534        let key: Vec<u8> = (0..32).collect();
535
536        const EMPTY_HMAC: [u8; 32] = [
537            0xd3, 0x8b, 0x42, 0x09, 0x6d, 0x80, 0xf4, 0x5f, 0x82, 0x6b, 0x44, 0xa9, 0xd5, 0x60,
538            0x7d, 0xe7, 0x24, 0x96, 0xa4, 0x15, 0xd3, 0xf4, 0xa1, 0xa8, 0xc8, 0x8e, 0x3b, 0xb9,
539            0xda, 0x8d, 0xc1, 0xcb,
540        ];
541
542        let hmac = hmac_sha_256(key.as_slice(), &[]).unwrap();
543        assert_eq!(hmac, EMPTY_HMAC);
544
545        const PANGRAM: [u8; 32] = [
546            0xf8, 0x7a, 0xd2, 0x56, 0x15, 0x1f, 0xc7, 0xb4, 0xc5, 0xdf, 0xfa, 0x4a, 0xdb, 0x3e,
547            0xbe, 0x91, 0x1a, 0x8e, 0xeb, 0x8a, 0x8e, 0xbd, 0xee, 0x3c, 0x2a, 0x4a, 0x8e, 0x5f,
548            0x5e, 0xc0, 0x2c, 0x32,
549        ];
550
551        let hmac = hmac_sha_256(
552            key.as_slice(),
553            b"The quick brown fox jumps over the lazy dog",
554        )
555        .unwrap();
556        assert_eq!(hmac, PANGRAM);
557    }
558
559    #[test]
560    fn test_sha256() {
561        const EMPTY_HASH: [u8; 32] = [
562            0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f,
563            0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b,
564            0x78, 0x52, 0xb8, 0x55,
565        ];
566
567        let hash = sha_256(&[]);
568        assert_eq!(hash, EMPTY_HASH);
569
570        const PANGRAM: [u8; 32] = [
571            0xd7, 0xa8, 0xfb, 0xb3, 0x07, 0xd7, 0x80, 0x94, 0x69, 0xca, 0x9a, 0xbc, 0xb0, 0x08,
572            0x2e, 0x4f, 0x8d, 0x56, 0x51, 0xe4, 0x6d, 0x3c, 0xdb, 0x76, 0x2d, 0x02, 0xd0, 0xbf,
573            0x37, 0xc9, 0xe5, 0x92,
574        ];
575
576        let hash = sha_256(b"The quick brown fox jumps over the lazy dog");
577        assert_eq!(hash, PANGRAM);
578    }
579}