blob: 3523a9dc24f85302150a6f7015e4723f8778962e [file] [log] [blame]
Joel Galensonca0efb12020-10-01 14:32:30 -07001// 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
Janis Danisevskis9d90b812020-11-25 21:02:11 -080015//! This module implements safe wrappers for some crypto operations required by
16//! Keystore 2.0.
17
18mod error;
19mod zvec;
20pub use error::Error;
21use keystore2_crypto_bindgen::{
Shawn Willden8fde4c22021-02-14 13:58:22 -070022 extractSubjectFromCertificate, generateKeyFromPassword, randomBytes, AES_gcm_decrypt,
Paul Crowley7bb5edd2021-03-20 20:26:43 -070023 AES_gcm_encrypt, ECDHComputeKey, ECKEYGenerateKey, ECKEYMarshalPrivateKey,
24 ECKEYParsePrivateKey, ECPOINTOct2Point, ECPOINTPoint2Oct, EC_KEY_free, EC_KEY_get0_public_key,
25 EC_POINT_free, HKDFExpand, HKDFExtract, EC_KEY, EC_MAX_BYTES, EC_POINT, EVP_MAX_MD_SIZE,
Janis Danisevskis9d90b812020-11-25 21:02:11 -080026};
Shawn Willden8fde4c22021-02-14 13:58:22 -070027use std::convert::TryFrom;
Joel Galenson05914582021-01-08 09:30:41 -080028use std::convert::TryInto;
29use std::marker::PhantomData;
Janis Danisevskis9d90b812020-11-25 21:02:11 -080030pub use zvec::ZVec;
31
32/// Length of the expected initialization vector.
33pub const IV_LENGTH: usize = 16;
34/// Length of the expected AEAD TAG.
35pub const TAG_LENGTH: usize = 16;
36/// Length of an AES 256 key in bytes.
37pub const AES_256_KEY_LENGTH: usize = 32;
38/// Length of an AES 128 key in bytes.
39pub const AES_128_KEY_LENGTH: usize = 16;
40/// Length of the expected salt for key from password generation.
41pub const SALT_LENGTH: usize = 16;
42
43// This is the number of bytes of the GCM IV that is expected to be initialized
44// with random bytes.
45const GCM_IV_LENGTH: usize = 12;
46
47/// Generate an AES256 key, essentially 32 random bytes from the underlying
48/// boringssl library discretely stuffed into a ZVec.
49pub fn generate_aes256_key() -> Result<ZVec, Error> {
50 // Safety: key has the same length as the requested number of random bytes.
51 let mut key = ZVec::new(AES_256_KEY_LENGTH)?;
Joel Galenson05914582021-01-08 09:30:41 -080052 if unsafe { randomBytes(key.as_mut_ptr(), AES_256_KEY_LENGTH) } {
Janis Danisevskis9d90b812020-11-25 21:02:11 -080053 Ok(key)
54 } else {
55 Err(Error::RandomNumberGenerationFailed)
56 }
57}
58
59/// Generate a salt.
60pub fn generate_salt() -> Result<Vec<u8>, Error> {
David Drysdale0e45a612021-02-25 17:24:36 +000061 generate_random_data(SALT_LENGTH)
62}
63
64/// Generate random data of the given size.
65pub fn generate_random_data(size: usize) -> Result<Vec<u8>, Error> {
66 // Safety: data has the same length as the requested number of random bytes.
67 let mut data = vec![0; size];
68 if unsafe { randomBytes(data.as_mut_ptr(), size) } {
69 Ok(data)
Janis Danisevskis9d90b812020-11-25 21:02:11 -080070 } else {
71 Err(Error::RandomNumberGenerationFailed)
72 }
73}
74
75/// Uses AES GCM to decipher a message given an initialization vector, aead tag, and key.
76/// This function accepts 128 and 256-bit keys and uses AES128 and AES256 respectively based
77/// on the key length.
78/// This function returns the plaintext message in a ZVec because it is assumed that
79/// it contains sensitive information that should be zeroed from memory before its buffer is
80/// freed. Input key is taken as a slice for flexibility, but it is recommended that it is held
81/// in a ZVec as well.
82pub fn aes_gcm_decrypt(data: &[u8], iv: &[u8], tag: &[u8], key: &[u8]) -> Result<ZVec, Error> {
83 if iv.len() != IV_LENGTH {
84 return Err(Error::InvalidIvLength);
85 }
86
87 if tag.len() != TAG_LENGTH {
88 return Err(Error::InvalidAeadTagLength);
89 }
90
91 match key.len() {
92 AES_128_KEY_LENGTH | AES_256_KEY_LENGTH => {}
93 _ => return Err(Error::InvalidKeyLength),
94 }
95
96 let mut result = ZVec::new(data.len())?;
97
98 // Safety: The first two arguments must point to buffers with a size given by the third
99 // argument. The key must have a size of 16 or 32 bytes which we check above.
100 // The iv and tag arguments must be 16 bytes, which we also check above.
101 match unsafe {
102 AES_gcm_decrypt(
103 data.as_ptr(),
104 result.as_mut_ptr(),
Joel Galenson05914582021-01-08 09:30:41 -0800105 data.len(),
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800106 key.as_ptr(),
Joel Galenson05914582021-01-08 09:30:41 -0800107 key.len(),
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800108 iv.as_ptr(),
109 tag.as_ptr(),
110 )
111 } {
112 true => Ok(result),
113 false => Err(Error::DecryptionFailed),
114 }
115}
116
117/// Uses AES GCM to encrypt a message given a key.
118/// This function accepts 128 and 256-bit keys and uses AES128 and AES256 respectively based on
119/// the key length. The function generates an initialization vector. The return value is a tuple
120/// of `(ciphertext, iv, tag)`.
121pub fn aes_gcm_encrypt(data: &[u8], key: &[u8]) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>), Error> {
122 let mut iv = vec![0; IV_LENGTH];
123 // Safety: iv is longer than GCM_IV_LENGTH, which is 12 while IV_LENGTH is 16.
124 // The iv needs to be 16 bytes long, but the last 4 bytes remain zeroed.
Joel Galenson05914582021-01-08 09:30:41 -0800125 if !unsafe { randomBytes(iv.as_mut_ptr(), GCM_IV_LENGTH) } {
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800126 return Err(Error::RandomNumberGenerationFailed);
127 }
128
129 match key.len() {
130 AES_128_KEY_LENGTH | AES_256_KEY_LENGTH => {}
131 _ => return Err(Error::InvalidKeyLength),
132 }
133
134 let mut result: Vec<u8> = vec![0; data.len()];
135 let mut tag: Vec<u8> = vec![0; TAG_LENGTH];
136 match unsafe {
137 AES_gcm_encrypt(
138 data.as_ptr(),
139 result.as_mut_ptr(),
Joel Galenson05914582021-01-08 09:30:41 -0800140 data.len(),
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800141 key.as_ptr(),
Joel Galenson05914582021-01-08 09:30:41 -0800142 key.len(),
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800143 iv.as_ptr(),
144 tag.as_mut_ptr(),
145 )
146 } {
147 true => Ok((result, iv, tag)),
148 false => Err(Error::EncryptionFailed),
149 }
150}
151
Paul Crowleyf61fee72021-03-17 14:38:44 -0700152/// Represents a "password" that can be used to key the PBKDF2 algorithm.
153pub enum Password<'a> {
154 /// Borrow an existing byte array
155 Ref(&'a [u8]),
156 /// Use an owned ZVec to store the key
157 Owned(ZVec),
158}
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800159
Paul Crowleyf61fee72021-03-17 14:38:44 -0700160impl<'a> From<&'a [u8]> for Password<'a> {
161 fn from(pw: &'a [u8]) -> Self {
162 Self::Ref(pw)
163 }
164}
165
166impl<'a> Password<'a> {
167 fn get_key(&'a self) -> &'a [u8] {
168 match self {
169 Self::Ref(b) => b,
170 Self::Owned(z) => &*z,
171 }
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800172 }
173
Paul Crowleyf61fee72021-03-17 14:38:44 -0700174 /// Generate a key from the given password and salt.
175 /// The salt must be exactly 16 bytes long.
176 /// Two key sizes are accepted: 16 and 32 bytes.
177 pub fn derive_key(&self, salt: Option<&[u8]>, key_length: usize) -> Result<ZVec, Error> {
178 let pw = self.get_key();
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800179
Paul Crowleyf61fee72021-03-17 14:38:44 -0700180 let salt: *const u8 = match salt {
181 Some(s) => {
182 if s.len() != SALT_LENGTH {
183 return Err(Error::InvalidSaltLength);
184 }
185 s.as_ptr()
186 }
187 None => std::ptr::null(),
188 };
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800189
Paul Crowleyf61fee72021-03-17 14:38:44 -0700190 match key_length {
191 AES_128_KEY_LENGTH | AES_256_KEY_LENGTH => {}
192 _ => return Err(Error::InvalidKeyLength),
193 }
194
195 let mut result = ZVec::new(key_length)?;
196
197 unsafe {
198 generateKeyFromPassword(
199 result.as_mut_ptr(),
200 result.len(),
201 pw.as_ptr() as *const std::os::raw::c_char,
202 pw.len(),
203 salt,
204 )
205 };
206
207 Ok(result)
208 }
209
210 /// Try to make another Password object with the same data.
211 pub fn try_clone(&self) -> Result<Password<'static>, Error> {
212 Ok(Password::Owned(ZVec::try_from(self.get_key())?))
213 }
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800214}
Joel Galenson46d6fd02020-11-19 17:58:33 -0800215
Joel Galenson05914582021-01-08 09:30:41 -0800216/// Calls the boringssl HKDF_extract function.
217pub fn hkdf_extract(secret: &[u8], salt: &[u8]) -> Result<ZVec, Error> {
218 let max_size: usize = EVP_MAX_MD_SIZE.try_into().unwrap();
219 let mut buf = ZVec::new(max_size)?;
220 let mut out_len = 0;
221 // Safety: HKDF_extract writes at most EVP_MAX_MD_SIZE bytes.
222 // Secret and salt point to valid buffers.
223 let result = unsafe {
224 HKDFExtract(
225 buf.as_mut_ptr(),
226 &mut out_len,
227 secret.as_ptr(),
228 secret.len(),
229 salt.as_ptr(),
230 salt.len(),
231 )
232 };
233 if !result {
234 return Err(Error::HKDFExtractFailed);
235 }
236 // According to the boringssl API, this should never happen.
237 if out_len > max_size {
238 return Err(Error::HKDFExtractFailed);
239 }
240 // HKDF_extract may write fewer than the maximum number of bytes, so we
241 // truncate the buffer.
242 buf.reduce_len(out_len);
243 Ok(buf)
244}
245
246/// Calls the boringssl HKDF_expand function.
247pub fn hkdf_expand(out_len: usize, prk: &[u8], info: &[u8]) -> Result<ZVec, Error> {
248 let mut buf = ZVec::new(out_len)?;
249 // Safety: HKDF_expand writes out_len bytes to the buffer.
250 // prk and info are valid buffers.
251 let result = unsafe {
252 HKDFExpand(buf.as_mut_ptr(), out_len, prk.as_ptr(), prk.len(), info.as_ptr(), info.len())
253 };
254 if !result {
255 return Err(Error::HKDFExpandFailed);
256 }
257 Ok(buf)
258}
259
260/// A wrapper around the boringssl EC_KEY type that frees it on drop.
261pub struct ECKey(*mut EC_KEY);
262
263impl Drop for ECKey {
264 fn drop(&mut self) {
265 // Safety: We only create ECKey objects for valid EC_KEYs
266 // and they are the sole owners of those keys.
267 unsafe { EC_KEY_free(self.0) };
268 }
269}
270
271// Wrappers around the boringssl EC_POINT type.
272// The EC_POINT can either be owned (and therefore mutable) or a pointer to an
273// EC_POINT owned by someone else (and thus immutable). The former are freed
274// on drop.
275
276/// An owned EC_POINT object.
277pub struct OwnedECPoint(*mut EC_POINT);
278
279/// A pointer to an EC_POINT object.
280pub struct BorrowedECPoint<'a> {
281 data: *const EC_POINT,
282 phantom: PhantomData<&'a EC_POINT>,
283}
284
285impl OwnedECPoint {
286 /// Get the wrapped EC_POINT object.
287 pub fn get_point(&self) -> &EC_POINT {
288 // Safety: We only create OwnedECPoint objects for valid EC_POINTs.
289 unsafe { self.0.as_ref().unwrap() }
290 }
291}
292
293impl<'a> BorrowedECPoint<'a> {
294 /// Get the wrapped EC_POINT object.
295 pub fn get_point(&self) -> &EC_POINT {
296 // Safety: We only create BorrowedECPoint objects for valid EC_POINTs.
297 unsafe { self.data.as_ref().unwrap() }
298 }
299}
300
301impl Drop for OwnedECPoint {
302 fn drop(&mut self) {
303 // Safety: We only create OwnedECPoint objects for valid
304 // EC_POINTs and they are the sole owners of those points.
305 unsafe { EC_POINT_free(self.0) };
306 }
307}
308
309/// Calls the boringssl ECDH_compute_key function.
310pub fn ecdh_compute_key(pub_key: &EC_POINT, priv_key: &ECKey) -> Result<ZVec, Error> {
311 let mut buf = ZVec::new(EC_MAX_BYTES)?;
312 // Safety: Our ECDHComputeKey wrapper passes EC_MAX_BYES to ECDH_compute_key, which
313 // writes at most that many bytes to the output.
314 // The two keys are valid objects.
315 let result =
316 unsafe { ECDHComputeKey(buf.as_mut_ptr() as *mut std::ffi::c_void, pub_key, priv_key.0) };
317 if result == -1 {
318 return Err(Error::ECDHComputeKeyFailed);
319 }
320 let out_len = result.try_into().unwrap();
321 // According to the boringssl API, this should never happen.
322 if out_len > buf.len() {
323 return Err(Error::ECDHComputeKeyFailed);
324 }
325 // ECDH_compute_key may write fewer than the maximum number of bytes, so we
326 // truncate the buffer.
327 buf.reduce_len(out_len);
328 Ok(buf)
329}
330
331/// Calls the boringssl EC_KEY_generate_key function.
332pub fn ec_key_generate_key() -> Result<ECKey, Error> {
333 // Safety: Creates a new key on its own.
334 let key = unsafe { ECKEYGenerateKey() };
335 if key.is_null() {
336 return Err(Error::ECKEYGenerateKeyFailed);
337 }
338 Ok(ECKey(key))
339}
340
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700341/// Calls the boringssl EC_KEY_marshal_private_key function.
342pub fn ec_key_marshal_private_key(key: &ECKey) -> Result<ZVec, Error> {
343 let len = 39; // Empirically observed length of private key
344 let mut buf = ZVec::new(len)?;
345 // Safety: the key is valid.
346 // This will not write past the specified length of the buffer; if the
347 // len above is too short, it returns 0.
348 let written_len =
349 unsafe { ECKEYMarshalPrivateKey(key.0, buf.as_mut_ptr(), buf.len()) } as usize;
350 if written_len == len {
351 Ok(buf)
352 } else {
353 Err(Error::ECKEYMarshalPrivateKeyFailed)
Joel Galenson05914582021-01-08 09:30:41 -0800354 }
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700355}
356
357/// Calls the boringssl EC_KEY_parse_private_key function.
358pub fn ec_key_parse_private_key(buf: &[u8]) -> Result<ECKey, Error> {
359 // Safety: this will not read past the specified length of the buffer.
360 // It fails if less than the whole buffer is consumed.
361 let key = unsafe { ECKEYParsePrivateKey(buf.as_ptr(), buf.len()) };
362 if key.is_null() {
363 Err(Error::ECKEYParsePrivateKeyFailed)
364 } else {
365 Ok(ECKey(key))
366 }
Joel Galenson05914582021-01-08 09:30:41 -0800367}
368
369/// Calls the boringssl EC_KEY_get0_public_key function.
370pub fn ec_key_get0_public_key(key: &ECKey) -> BorrowedECPoint {
371 // Safety: The key is valid.
372 // This returns a pointer to a key, so we create an immutable variant.
373 BorrowedECPoint { data: unsafe { EC_KEY_get0_public_key(key.0) }, phantom: PhantomData }
374}
375
376/// Calls the boringssl EC_POINT_point2oct.
377pub fn ec_point_point_to_oct(point: &EC_POINT) -> Result<Vec<u8>, Error> {
378 // We fix the length to 65 (1 + 2 * field_elem_size), as we get an error if it's too small.
379 let len = 65;
380 let mut buf = vec![0; len];
381 // Safety: EC_POINT_point2oct writes at most len bytes. The point is valid.
382 let result = unsafe { ECPOINTPoint2Oct(point, buf.as_mut_ptr(), len) };
383 if result == 0 {
384 return Err(Error::ECPoint2OctFailed);
385 }
386 // According to the boringssl API, this should never happen.
387 if result > len {
388 return Err(Error::ECPoint2OctFailed);
389 }
390 buf.resize(result, 0);
391 Ok(buf)
392}
393
394/// Calls the boringssl EC_POINT_oct2point function.
395pub fn ec_point_oct_to_point(buf: &[u8]) -> Result<OwnedECPoint, Error> {
396 // Safety: The buffer is valid.
397 let result = unsafe { ECPOINTOct2Point(buf.as_ptr(), buf.len()) };
398 if result.is_null() {
399 return Err(Error::ECPoint2OctFailed);
400 }
401 // Our C wrapper creates a new EC_POINT, so we mark this mutable and free
402 // it on drop.
403 Ok(OwnedECPoint(result))
404}
405
Shawn Willden34120872021-02-24 21:56:30 -0700406/// Uses BoringSSL to extract the DER-encoded subject from a DER-encoded X.509 certificate.
407pub fn parse_subject_from_certificate(cert_buf: &[u8]) -> Result<Vec<u8>, Error> {
Shawn Willden8fde4c22021-02-14 13:58:22 -0700408 // Try with a 200-byte output buffer, should be enough in all but bizarre cases.
409 let mut retval = vec![0; 200];
Shawn Willden34120872021-02-24 21:56:30 -0700410
411 // Safety: extractSubjectFromCertificate reads at most cert_buf.len() bytes from cert_buf and
412 // writes at most retval.len() bytes to retval.
Shawn Willden8fde4c22021-02-14 13:58:22 -0700413 let mut size = unsafe {
414 extractSubjectFromCertificate(
415 cert_buf.as_ptr(),
416 cert_buf.len(),
417 retval.as_mut_ptr(),
418 retval.len(),
419 )
420 };
421
422 if size == 0 {
423 return Err(Error::ExtractSubjectFailed);
424 }
425
426 if size < 0 {
427 // Our buffer wasn't big enough. Make one that is just the right size and try again.
Shawn Willden34120872021-02-24 21:56:30 -0700428 let negated_size = usize::try_from(-size).map_err(|_e| Error::ExtractSubjectFailed)?;
429 retval = vec![0; negated_size];
Shawn Willden8fde4c22021-02-14 13:58:22 -0700430
Shawn Willden34120872021-02-24 21:56:30 -0700431 // Safety: extractSubjectFromCertificate reads at most cert_buf.len() bytes from cert_buf
432 // and writes at most retval.len() bytes to retval.
Shawn Willden8fde4c22021-02-14 13:58:22 -0700433 size = unsafe {
434 extractSubjectFromCertificate(
435 cert_buf.as_ptr(),
436 cert_buf.len(),
437 retval.as_mut_ptr(),
438 retval.len(),
439 )
440 };
441
442 if size <= 0 {
443 return Err(Error::ExtractSubjectFailed);
444 }
445 }
446
447 // Reduce buffer size to the amount written.
Shawn Willden34120872021-02-24 21:56:30 -0700448 let safe_size = usize::try_from(size).map_err(|_e| Error::ExtractSubjectFailed)?;
449 retval.truncate(safe_size);
Shawn Willden8fde4c22021-02-14 13:58:22 -0700450
451 Ok(retval)
452}
453
Joel Galensonca0efb12020-10-01 14:32:30 -0700454#[cfg(test)]
455mod tests {
456
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800457 use super::*;
Joel Galensonca0efb12020-10-01 14:32:30 -0700458 use keystore2_crypto_bindgen::{
459 generateKeyFromPassword, AES_gcm_decrypt, AES_gcm_encrypt, CreateKeyId,
460 };
461
462 #[test]
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800463 fn test_wrapper_roundtrip() {
464 let key = generate_aes256_key().unwrap();
465 let message = b"totally awesome message";
466 let (cipher_text, iv, tag) = aes_gcm_encrypt(message, &key).unwrap();
467 let message2 = aes_gcm_decrypt(&cipher_text, &iv, &tag, &key).unwrap();
468 assert_eq!(message[..], message2[..])
469 }
470
471 #[test]
Joel Galensonca0efb12020-10-01 14:32:30 -0700472 fn test_encrypt_decrypt() {
473 let input = vec![0; 16];
474 let mut out = vec![0; 16];
475 let mut out2 = vec![0; 16];
476 let key = vec![0; 16];
477 let iv = vec![0; 12];
478 let mut tag = vec![0; 16];
479 unsafe {
480 let res = AES_gcm_encrypt(
481 input.as_ptr(),
482 out.as_mut_ptr(),
483 16,
484 key.as_ptr(),
485 16,
486 iv.as_ptr(),
487 tag.as_mut_ptr(),
488 );
489 assert!(res);
490 assert_ne!(out, input);
491 assert_ne!(tag, input);
492 let res = AES_gcm_decrypt(
493 out.as_ptr(),
494 out2.as_mut_ptr(),
495 16,
496 key.as_ptr(),
497 16,
498 iv.as_ptr(),
499 tag.as_ptr(),
500 );
501 assert!(res);
502 assert_eq!(out2, input);
503 }
504 }
505
506 #[test]
507 fn test_create_key_id() {
508 let blob = vec![0; 16];
509 let mut out: u64 = 0;
510 unsafe {
511 let res = CreateKeyId(blob.as_ptr(), 16, &mut out);
512 assert!(res);
513 assert_ne!(out, 0);
514 }
515 }
516
517 #[test]
518 fn test_generate_key_from_password() {
519 let mut key = vec![0; 16];
520 let pw = vec![0; 16];
521 let mut salt = vec![0; 16];
522 unsafe {
523 generateKeyFromPassword(key.as_mut_ptr(), 16, pw.as_ptr(), 16, salt.as_mut_ptr());
524 }
525 assert_ne!(key, vec![0; 16]);
526 }
Joel Galenson05914582021-01-08 09:30:41 -0800527
528 #[test]
529 fn test_hkdf() {
530 let result = hkdf_extract(&[0; 16], &[0; 16]);
531 assert!(result.is_ok());
532 for out_len in 4..=8 {
533 let result = hkdf_expand(out_len, &[0; 16], &[0; 16]);
534 assert!(result.is_ok());
535 assert_eq!(result.unwrap().len(), out_len);
536 }
537 }
538
539 #[test]
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700540 fn test_ec() -> Result<(), Error> {
541 let priv0 = ec_key_generate_key()?;
542 assert!(!priv0.0.is_null());
543 let pub0 = ec_key_get0_public_key(&priv0);
Joel Galenson05914582021-01-08 09:30:41 -0800544
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700545 let priv1 = ec_key_generate_key()?;
546 let pub1 = ec_key_get0_public_key(&priv1);
Joel Galenson05914582021-01-08 09:30:41 -0800547
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700548 let priv0s = ec_key_marshal_private_key(&priv0)?;
549 let pub0s = ec_point_point_to_oct(pub0.get_point())?;
550 let pub1s = ec_point_point_to_oct(pub1.get_point())?;
Joel Galenson05914582021-01-08 09:30:41 -0800551
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700552 let priv0 = ec_key_parse_private_key(&priv0s)?;
553 let pub0 = ec_point_oct_to_point(&pub0s)?;
554 let pub1 = ec_point_oct_to_point(&pub1s)?;
Joel Galenson05914582021-01-08 09:30:41 -0800555
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700556 let left_key = ecdh_compute_key(pub0.get_point(), &priv1)?;
557 let right_key = ecdh_compute_key(pub1.get_point(), &priv0)?;
Joel Galenson05914582021-01-08 09:30:41 -0800558
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700559 assert_eq!(left_key, right_key);
560 Ok(())
Joel Galenson05914582021-01-08 09:30:41 -0800561 }
Joel Galensonca0efb12020-10-01 14:32:30 -0700562}