1 // Copyright 2020, 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 //! This module implements safe wrappers for some crypto operations required by
16 //! Keystore 2.0.
17
18 mod error;
19 pub mod zvec;
20 pub use error::Error;
21 use keystore2_crypto_bindgen::{
22 extractSubjectFromCertificate, hmacSha256, randomBytes, AES_gcm_decrypt, AES_gcm_encrypt,
23 ECDHComputeKey, ECKEYGenerateKey, ECKEYMarshalPrivateKey, ECKEYParsePrivateKey,
24 ECPOINTOct2Point, ECPOINTPoint2Oct, EC_KEY_free, EC_KEY_get0_public_key, EC_POINT_free,
25 HKDFExpand, HKDFExtract, EC_KEY, EC_MAX_BYTES, EC_POINT, EVP_MAX_MD_SIZE, PBKDF2,
26 };
27 use std::convert::TryFrom;
28 use std::convert::TryInto;
29 use std::marker::PhantomData;
30 pub use zvec::ZVec;
31
32 /// Length of the expected initialization vector.
33 pub const GCM_IV_LENGTH: usize = 12;
34 /// Length of the expected AEAD TAG.
35 pub const TAG_LENGTH: usize = 16;
36 /// Length of an AES 256 key in bytes.
37 pub const AES_256_KEY_LENGTH: usize = 32;
38 /// Length of an AES 128 key in bytes.
39 pub const AES_128_KEY_LENGTH: usize = 16;
40 /// Length of the expected salt for key from password generation.
41 pub const SALT_LENGTH: usize = 16;
42 /// Length of an HMAC-SHA256 tag in bytes.
43 pub const HMAC_SHA256_LEN: usize = 32;
44
45 /// Older versions of keystore produced IVs with four extra
46 /// ignored zero bytes at the end; recognise and trim those.
47 pub const LEGACY_IV_LENGTH: usize = 16;
48
49 /// Generate an AES256 key, essentially 32 random bytes from the underlying
50 /// boringssl library discretely stuffed into a ZVec.
generate_aes256_key() -> Result<ZVec, Error>51 pub fn generate_aes256_key() -> Result<ZVec, Error> {
52 let mut key = ZVec::new(AES_256_KEY_LENGTH)?;
53 // Safety: key has the same length as the requested number of random bytes.
54 if unsafe { randomBytes(key.as_mut_ptr(), AES_256_KEY_LENGTH) } {
55 Ok(key)
56 } else {
57 Err(Error::RandomNumberGenerationFailed)
58 }
59 }
60
61 /// Generate a salt.
generate_salt() -> Result<Vec<u8>, Error>62 pub fn generate_salt() -> Result<Vec<u8>, Error> {
63 generate_random_data(SALT_LENGTH)
64 }
65
66 /// Generate random data of the given size.
generate_random_data(size: usize) -> Result<Vec<u8>, Error>67 pub fn generate_random_data(size: usize) -> Result<Vec<u8>, Error> {
68 let mut data = vec![0; size];
69 // Safety: data has the same length as the requested number of random bytes.
70 if unsafe { randomBytes(data.as_mut_ptr(), size) } {
71 Ok(data)
72 } else {
73 Err(Error::RandomNumberGenerationFailed)
74 }
75 }
76
77 /// Perform HMAC-SHA256.
hmac_sha256(key: &[u8], msg: &[u8]) -> Result<Vec<u8>, Error>78 pub fn hmac_sha256(key: &[u8], msg: &[u8]) -> Result<Vec<u8>, Error> {
79 let mut tag = vec![0; HMAC_SHA256_LEN];
80 // Safety: The first two pairs of arguments must point to const buffers with
81 // size given by the second arg of the pair. The final pair of arguments
82 // must point to an output buffer with size given by the second arg of the
83 // pair.
84 match unsafe {
85 hmacSha256(key.as_ptr(), key.len(), msg.as_ptr(), msg.len(), tag.as_mut_ptr(), tag.len())
86 } {
87 true => Ok(tag),
88 false => Err(Error::HmacSha256Failed),
89 }
90 }
91
92 /// Uses AES GCM to decipher a message given an initialization vector, aead tag, and key.
93 /// This function accepts 128 and 256-bit keys and uses AES128 and AES256 respectively based
94 /// on the key length.
95 /// This function returns the plaintext message in a ZVec because it is assumed that
96 /// it contains sensitive information that should be zeroed from memory before its buffer is
97 /// freed. Input key is taken as a slice for flexibility, but it is recommended that it is held
98 /// in a ZVec as well.
aes_gcm_decrypt(data: &[u8], iv: &[u8], tag: &[u8], key: &[u8]) -> Result<ZVec, Error>99 pub fn aes_gcm_decrypt(data: &[u8], iv: &[u8], tag: &[u8], key: &[u8]) -> Result<ZVec, Error> {
100 // Old versions of aes_gcm_encrypt produced 16 byte IVs, but the last four bytes were ignored
101 // so trim these to the correct size.
102 let iv = match iv.len() {
103 GCM_IV_LENGTH => iv,
104 LEGACY_IV_LENGTH => &iv[..GCM_IV_LENGTH],
105 _ => return Err(Error::InvalidIvLength),
106 };
107 if tag.len() != TAG_LENGTH {
108 return Err(Error::InvalidAeadTagLength);
109 }
110
111 match key.len() {
112 AES_128_KEY_LENGTH | AES_256_KEY_LENGTH => {}
113 _ => return Err(Error::InvalidKeyLength),
114 }
115
116 let mut result = ZVec::new(data.len())?;
117
118 // Safety: The first two arguments must point to buffers with a size given by the third
119 // argument. We pass the length of the key buffer along with the key.
120 // The `iv` buffer must be 12 bytes and the `tag` buffer 16, which we check above.
121 match unsafe {
122 AES_gcm_decrypt(
123 data.as_ptr(),
124 result.as_mut_ptr(),
125 data.len(),
126 key.as_ptr(),
127 key.len(),
128 iv.as_ptr(),
129 tag.as_ptr(),
130 )
131 } {
132 true => Ok(result),
133 false => Err(Error::DecryptionFailed),
134 }
135 }
136
137 /// Uses AES GCM to encrypt a message given a key.
138 /// This function accepts 128 and 256-bit keys and uses AES128 and AES256 respectively based on
139 /// the key length. The function generates an initialization vector. The return value is a tuple
140 /// of `(ciphertext, iv, tag)`.
aes_gcm_encrypt(plaintext: &[u8], key: &[u8]) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>), Error>141 pub fn aes_gcm_encrypt(plaintext: &[u8], key: &[u8]) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>), Error> {
142 let mut iv = vec![0; GCM_IV_LENGTH];
143 // Safety: iv is GCM_IV_LENGTH bytes long.
144 if !unsafe { randomBytes(iv.as_mut_ptr(), GCM_IV_LENGTH) } {
145 return Err(Error::RandomNumberGenerationFailed);
146 }
147
148 match key.len() {
149 AES_128_KEY_LENGTH | AES_256_KEY_LENGTH => {}
150 _ => return Err(Error::InvalidKeyLength),
151 }
152
153 let mut ciphertext: Vec<u8> = vec![0; plaintext.len()];
154 let mut tag: Vec<u8> = vec![0; TAG_LENGTH];
155 // Safety: The first two arguments must point to buffers with a size given by the third
156 // argument. We pass the length of the key buffer along with the key.
157 // The `iv` buffer must be 12 bytes and the `tag` buffer 16, which we check above.
158 if unsafe {
159 AES_gcm_encrypt(
160 plaintext.as_ptr(),
161 ciphertext.as_mut_ptr(),
162 plaintext.len(),
163 key.as_ptr(),
164 key.len(),
165 iv.as_ptr(),
166 tag.as_mut_ptr(),
167 )
168 } {
169 Ok((ciphertext, iv, tag))
170 } else {
171 Err(Error::EncryptionFailed)
172 }
173 }
174
175 /// A high-entropy synthetic password from which an AES key may be derived.
176 pub enum Password<'a> {
177 /// Borrow an existing byte array
178 Ref(&'a [u8]),
179 /// Use an owned ZVec to store the key
180 Owned(ZVec),
181 }
182
183 impl<'a> From<&'a [u8]> for Password<'a> {
from(pw: &'a [u8]) -> Self184 fn from(pw: &'a [u8]) -> Self {
185 Self::Ref(pw)
186 }
187 }
188
189 impl<'a> Password<'a> {
get_key(&'a self) -> &'a [u8]190 fn get_key(&'a self) -> &'a [u8] {
191 match self {
192 Self::Ref(b) => b,
193 Self::Owned(z) => z,
194 }
195 }
196
197 /// Derives a key from the given password and salt, using PBKDF2 with 8192 iterations.
198 ///
199 /// The salt length must be 16 bytes, and the output key length must be 16 or 32 bytes.
200 ///
201 /// This function exists only for backwards compatibility reasons. Keystore now receives only
202 /// high-entropy synthetic passwords, which do not require key stretching.
derive_key_pbkdf2(&self, salt: &[u8], out_len: usize) -> Result<ZVec, Error>203 pub fn derive_key_pbkdf2(&self, salt: &[u8], out_len: usize) -> Result<ZVec, Error> {
204 if salt.len() != SALT_LENGTH {
205 return Err(Error::InvalidSaltLength);
206 }
207 match out_len {
208 AES_128_KEY_LENGTH | AES_256_KEY_LENGTH => {}
209 _ => return Err(Error::InvalidKeyLength),
210 }
211
212 let pw = self.get_key();
213 let mut result = ZVec::new(out_len)?;
214
215 // Safety: We checked that the salt is exactly 16 bytes long. The other pointers are valid,
216 // and have matching lengths.
217 unsafe {
218 PBKDF2(
219 result.as_mut_ptr(),
220 result.len(),
221 pw.as_ptr() as *const std::os::raw::c_char,
222 pw.len(),
223 salt.as_ptr(),
224 )
225 };
226
227 Ok(result)
228 }
229
230 /// Derives a key from the given high-entropy synthetic password and salt, using HKDF.
derive_key_hkdf(&self, salt: &[u8], out_len: usize) -> Result<ZVec, Error>231 pub fn derive_key_hkdf(&self, salt: &[u8], out_len: usize) -> Result<ZVec, Error> {
232 let prk = hkdf_extract(self.get_key(), salt)?;
233 let info = [];
234 hkdf_expand(out_len, &prk, &info)
235 }
236
237 /// Try to make another Password object with the same data.
try_clone(&self) -> Result<Password<'static>, Error>238 pub fn try_clone(&self) -> Result<Password<'static>, Error> {
239 Ok(Password::Owned(ZVec::try_from(self.get_key())?))
240 }
241 }
242
243 /// Calls the boringssl HKDF_extract function.
hkdf_extract(secret: &[u8], salt: &[u8]) -> Result<ZVec, Error>244 pub fn hkdf_extract(secret: &[u8], salt: &[u8]) -> Result<ZVec, Error> {
245 let max_size: usize = EVP_MAX_MD_SIZE.try_into().unwrap();
246 let mut buf = ZVec::new(max_size)?;
247 let mut out_len = 0;
248 // Safety: HKDF_extract writes at most EVP_MAX_MD_SIZE bytes.
249 // Secret and salt point to valid buffers.
250 let result = unsafe {
251 HKDFExtract(
252 buf.as_mut_ptr(),
253 &mut out_len,
254 secret.as_ptr(),
255 secret.len(),
256 salt.as_ptr(),
257 salt.len(),
258 )
259 };
260 if !result {
261 return Err(Error::HKDFExtractFailed);
262 }
263 // According to the boringssl API, this should never happen.
264 if out_len > max_size {
265 return Err(Error::HKDFExtractFailed);
266 }
267 // HKDF_extract may write fewer than the maximum number of bytes, so we
268 // truncate the buffer.
269 buf.reduce_len(out_len);
270 Ok(buf)
271 }
272
273 /// Calls the boringssl HKDF_expand function.
hkdf_expand(out_len: usize, prk: &[u8], info: &[u8]) -> Result<ZVec, Error>274 pub fn hkdf_expand(out_len: usize, prk: &[u8], info: &[u8]) -> Result<ZVec, Error> {
275 let mut buf = ZVec::new(out_len)?;
276 // Safety: HKDF_expand writes out_len bytes to the buffer.
277 // prk and info are valid buffers.
278 let result = unsafe {
279 HKDFExpand(buf.as_mut_ptr(), out_len, prk.as_ptr(), prk.len(), info.as_ptr(), info.len())
280 };
281 if !result {
282 return Err(Error::HKDFExpandFailed);
283 }
284 Ok(buf)
285 }
286
287 /// A wrapper around the boringssl EC_KEY type that frees it on drop.
288 pub struct ECKey(*mut EC_KEY);
289
290 impl Drop for ECKey {
drop(&mut self)291 fn drop(&mut self) {
292 // Safety: We only create ECKey objects for valid EC_KEYs
293 // and they are the sole owners of those keys.
294 unsafe { EC_KEY_free(self.0) };
295 }
296 }
297
298 // Wrappers around the boringssl EC_POINT type.
299 // The EC_POINT can either be owned (and therefore mutable) or a pointer to an
300 // EC_POINT owned by someone else (and thus immutable). The former are freed
301 // on drop.
302
303 /// An owned EC_POINT object.
304 pub struct OwnedECPoint(*mut EC_POINT);
305
306 /// A pointer to an EC_POINT object.
307 pub struct BorrowedECPoint<'a> {
308 data: *const EC_POINT,
309 phantom: PhantomData<&'a EC_POINT>,
310 }
311
312 impl OwnedECPoint {
313 /// Get the wrapped EC_POINT object.
get_point(&self) -> &EC_POINT314 pub fn get_point(&self) -> &EC_POINT {
315 // Safety: We only create OwnedECPoint objects for valid EC_POINTs.
316 unsafe { self.0.as_ref().unwrap() }
317 }
318 }
319
320 impl<'a> BorrowedECPoint<'a> {
321 /// Get the wrapped EC_POINT object.
get_point(&self) -> &EC_POINT322 pub fn get_point(&self) -> &EC_POINT {
323 // Safety: We only create BorrowedECPoint objects for valid EC_POINTs.
324 unsafe { self.data.as_ref().unwrap() }
325 }
326 }
327
328 impl Drop for OwnedECPoint {
drop(&mut self)329 fn drop(&mut self) {
330 // Safety: We only create OwnedECPoint objects for valid
331 // EC_POINTs and they are the sole owners of those points.
332 unsafe { EC_POINT_free(self.0) };
333 }
334 }
335
336 /// Calls the boringssl ECDH_compute_key function.
ecdh_compute_key(pub_key: &EC_POINT, priv_key: &ECKey) -> Result<ZVec, Error>337 pub fn ecdh_compute_key(pub_key: &EC_POINT, priv_key: &ECKey) -> Result<ZVec, Error> {
338 let mut buf = ZVec::new(EC_MAX_BYTES)?;
339 let result =
340 // Safety: Our ECDHComputeKey wrapper passes EC_MAX_BYES to ECDH_compute_key, which
341 // writes at most that many bytes to the output.
342 // The two keys are valid objects.
343 unsafe { ECDHComputeKey(buf.as_mut_ptr() as *mut std::ffi::c_void, pub_key, priv_key.0) };
344 if result == -1 {
345 return Err(Error::ECDHComputeKeyFailed);
346 }
347 let out_len = result.try_into().unwrap();
348 // According to the boringssl API, this should never happen.
349 if out_len > buf.len() {
350 return Err(Error::ECDHComputeKeyFailed);
351 }
352 // ECDH_compute_key may write fewer than the maximum number of bytes, so we
353 // truncate the buffer.
354 buf.reduce_len(out_len);
355 Ok(buf)
356 }
357
358 /// Calls the boringssl EC_KEY_generate_key function.
ec_key_generate_key() -> Result<ECKey, Error>359 pub fn ec_key_generate_key() -> Result<ECKey, Error> {
360 // Safety: Creates a new key on its own.
361 let key = unsafe { ECKEYGenerateKey() };
362 if key.is_null() {
363 return Err(Error::ECKEYGenerateKeyFailed);
364 }
365 Ok(ECKey(key))
366 }
367
368 /// Calls the boringssl EC_KEY_marshal_private_key function.
ec_key_marshal_private_key(key: &ECKey) -> Result<ZVec, Error>369 pub fn ec_key_marshal_private_key(key: &ECKey) -> Result<ZVec, Error> {
370 let len = 73; // Empirically observed length of private key
371 let mut buf = ZVec::new(len)?;
372 // Safety: the key is valid.
373 // This will not write past the specified length of the buffer; if the
374 // len above is too short, it returns 0.
375 let written_len = unsafe { ECKEYMarshalPrivateKey(key.0, buf.as_mut_ptr(), buf.len()) };
376 if written_len == len {
377 Ok(buf)
378 } else {
379 Err(Error::ECKEYMarshalPrivateKeyFailed)
380 }
381 }
382
383 /// Calls the boringssl EC_KEY_parse_private_key function.
ec_key_parse_private_key(buf: &[u8]) -> Result<ECKey, Error>384 pub fn ec_key_parse_private_key(buf: &[u8]) -> Result<ECKey, Error> {
385 // Safety: this will not read past the specified length of the buffer.
386 // It fails if less than the whole buffer is consumed.
387 let key = unsafe { ECKEYParsePrivateKey(buf.as_ptr(), buf.len()) };
388 if key.is_null() {
389 Err(Error::ECKEYParsePrivateKeyFailed)
390 } else {
391 Ok(ECKey(key))
392 }
393 }
394
395 /// Calls the boringssl EC_KEY_get0_public_key function.
ec_key_get0_public_key(key: &ECKey) -> BorrowedECPoint396 pub fn ec_key_get0_public_key(key: &ECKey) -> BorrowedECPoint {
397 // Safety: The key is valid.
398 // This returns a pointer to a key, so we create an immutable variant.
399 BorrowedECPoint { data: unsafe { EC_KEY_get0_public_key(key.0) }, phantom: PhantomData }
400 }
401
402 /// Calls the boringssl EC_POINT_point2oct.
ec_point_point_to_oct(point: &EC_POINT) -> Result<Vec<u8>, Error>403 pub fn ec_point_point_to_oct(point: &EC_POINT) -> Result<Vec<u8>, Error> {
404 // We fix the length to 133 (1 + 2 * field_elem_size), as we get an error if it's too small.
405 let len = 133;
406 let mut buf = vec![0; len];
407 // Safety: EC_POINT_point2oct writes at most len bytes. The point is valid.
408 let result = unsafe { ECPOINTPoint2Oct(point, buf.as_mut_ptr(), len) };
409 if result == 0 {
410 return Err(Error::ECPoint2OctFailed);
411 }
412 // According to the boringssl API, this should never happen.
413 if result > len {
414 return Err(Error::ECPoint2OctFailed);
415 }
416 buf.resize(result, 0);
417 Ok(buf)
418 }
419
420 /// Calls the boringssl EC_POINT_oct2point function.
ec_point_oct_to_point(buf: &[u8]) -> Result<OwnedECPoint, Error>421 pub fn ec_point_oct_to_point(buf: &[u8]) -> Result<OwnedECPoint, Error> {
422 // Safety: The buffer is valid.
423 let result = unsafe { ECPOINTOct2Point(buf.as_ptr(), buf.len()) };
424 if result.is_null() {
425 return Err(Error::ECPoint2OctFailed);
426 }
427 // Our C wrapper creates a new EC_POINT, so we mark this mutable and free
428 // it on drop.
429 Ok(OwnedECPoint(result))
430 }
431
432 /// Uses BoringSSL to extract the DER-encoded subject from a DER-encoded X.509 certificate.
parse_subject_from_certificate(cert_buf: &[u8]) -> Result<Vec<u8>, Error>433 pub fn parse_subject_from_certificate(cert_buf: &[u8]) -> Result<Vec<u8>, Error> {
434 // Try with a 200-byte output buffer, should be enough in all but bizarre cases.
435 let mut retval = vec![0; 200];
436
437 // Safety: extractSubjectFromCertificate reads at most cert_buf.len() bytes from cert_buf and
438 // writes at most retval.len() bytes to retval.
439 let mut size = unsafe {
440 extractSubjectFromCertificate(
441 cert_buf.as_ptr(),
442 cert_buf.len(),
443 retval.as_mut_ptr(),
444 retval.len(),
445 )
446 };
447
448 if size == 0 {
449 return Err(Error::ExtractSubjectFailed);
450 }
451
452 if size < 0 {
453 // Our buffer wasn't big enough. Make one that is just the right size and try again.
454 let negated_size = usize::try_from(-size).map_err(|_e| Error::ExtractSubjectFailed)?;
455 retval = vec![0; negated_size];
456
457 // Safety: extractSubjectFromCertificate reads at most cert_buf.len() bytes from cert_buf
458 // and writes at most retval.len() bytes to retval.
459 size = unsafe {
460 extractSubjectFromCertificate(
461 cert_buf.as_ptr(),
462 cert_buf.len(),
463 retval.as_mut_ptr(),
464 retval.len(),
465 )
466 };
467
468 if size <= 0 {
469 return Err(Error::ExtractSubjectFailed);
470 }
471 }
472
473 // Reduce buffer size to the amount written.
474 let safe_size = usize::try_from(size).map_err(|_e| Error::ExtractSubjectFailed)?;
475 retval.truncate(safe_size);
476
477 Ok(retval)
478 }
479
480 #[cfg(test)]
481 mod tests {
482
483 use super::*;
484 use keystore2_crypto_bindgen::{AES_gcm_decrypt, AES_gcm_encrypt, CreateKeyId, PBKDF2};
485
486 #[test]
test_wrapper_roundtrip()487 fn test_wrapper_roundtrip() {
488 let key = generate_aes256_key().unwrap();
489 let message = b"totally awesome message";
490 let (cipher_text, iv, tag) = aes_gcm_encrypt(message, &key).unwrap();
491 let message2 = aes_gcm_decrypt(&cipher_text, &iv, &tag, &key).unwrap();
492 assert_eq!(message[..], message2[..])
493 }
494
495 #[test]
test_encrypt_decrypt()496 fn test_encrypt_decrypt() {
497 let input = vec![0; 16];
498 let mut out = vec![0; 16];
499 let mut out2 = vec![0; 16];
500 let key = [0; 16];
501 let iv = [0; 12];
502 let mut tag = vec![0; 16];
503 // SAFETY: The various pointers are obtained from references so they are valid, and
504 // `AES_gcm_encrypt` and `AES_gcm_decrypt` don't do anything with them after they return.
505 unsafe {
506 let res = AES_gcm_encrypt(
507 input.as_ptr(),
508 out.as_mut_ptr(),
509 16,
510 key.as_ptr(),
511 16,
512 iv.as_ptr(),
513 tag.as_mut_ptr(),
514 );
515 assert!(res);
516 assert_ne!(out, input);
517 assert_ne!(tag, input);
518 let res = AES_gcm_decrypt(
519 out.as_ptr(),
520 out2.as_mut_ptr(),
521 16,
522 key.as_ptr(),
523 16,
524 iv.as_ptr(),
525 tag.as_ptr(),
526 );
527 assert!(res);
528 assert_eq!(out2, input);
529 }
530 }
531
532 #[test]
test_create_key_id()533 fn test_create_key_id() {
534 let blob = [0; 16];
535 let mut out: u64 = 0;
536 // SAFETY: The pointers are obtained from references so they are valid, the length matches
537 // the length of the array, and `CreateKeyId` doesn't access them after it returns.
538 unsafe {
539 let res = CreateKeyId(blob.as_ptr(), blob.len(), &mut out);
540 assert!(res);
541 assert_ne!(out, 0);
542 }
543 }
544
545 #[test]
test_pbkdf2()546 fn test_pbkdf2() {
547 let mut key = vec![0; 16];
548 let pw = [0; 16];
549 let salt = [0; 16];
550 // SAFETY: The pointers are obtained from references so they are valid, the salt is the
551 // expected length, the other lengths match the lengths of the arrays, and `PBKDF2` doesn't
552 // access them after it returns.
553 unsafe {
554 PBKDF2(key.as_mut_ptr(), key.len(), pw.as_ptr(), pw.len(), salt.as_ptr());
555 }
556 assert_ne!(key, vec![0; 16]);
557 }
558
559 #[test]
test_hkdf()560 fn test_hkdf() {
561 let result = hkdf_extract(&[0; 16], &[0; 16]);
562 assert!(result.is_ok());
563 for out_len in 4..=8 {
564 let result = hkdf_expand(out_len, &[0; 16], &[0; 16]);
565 assert!(result.is_ok());
566 assert_eq!(result.unwrap().len(), out_len);
567 }
568 }
569
570 #[test]
test_ec() -> Result<(), Error>571 fn test_ec() -> Result<(), Error> {
572 let priv0 = ec_key_generate_key()?;
573 assert!(!priv0.0.is_null());
574 let pub0 = ec_key_get0_public_key(&priv0);
575
576 let priv1 = ec_key_generate_key()?;
577 let pub1 = ec_key_get0_public_key(&priv1);
578
579 let priv0s = ec_key_marshal_private_key(&priv0)?;
580 let pub0s = ec_point_point_to_oct(pub0.get_point())?;
581 let pub1s = ec_point_point_to_oct(pub1.get_point())?;
582
583 let priv0 = ec_key_parse_private_key(&priv0s)?;
584 let pub0 = ec_point_oct_to_point(&pub0s)?;
585 let pub1 = ec_point_oct_to_point(&pub1s)?;
586
587 let left_key = ecdh_compute_key(pub0.get_point(), &priv1)?;
588 let right_key = ecdh_compute_key(pub1.get_point(), &priv0)?;
589
590 assert_eq!(left_key, right_key);
591 Ok(())
592 }
593
594 #[test]
test_hmac_sha256()595 fn test_hmac_sha256() {
596 let key = b"This is the key";
597 let msg1 = b"This is a message";
598 let msg2 = b"This is another message";
599 let tag1a = hmac_sha256(key, msg1).unwrap();
600 assert_eq!(tag1a.len(), HMAC_SHA256_LEN);
601 let tag1b = hmac_sha256(key, msg1).unwrap();
602 assert_eq!(tag1a, tag1b);
603 let tag2 = hmac_sha256(key, msg2).unwrap();
604 assert_eq!(tag2.len(), HMAC_SHA256_LEN);
605 assert_ne!(tag1a, tag2);
606 }
607 }
608