/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use serde::Deserialize;
use std::ffi::c_void;
use std::fs::File;
use std::io::Cursor;
use thin_vec::ThinVec;
use dap_ffi::types::Report;
use prio::codec::{Decode, Encode};
#[no_mangle]
pub extern "C" fn dap_test_encoding() {
let r = Report::new_dummy();
let mut encoded = Vec::<u8>::new();
Report::encode(&r, &
mut encoded).expect(
"Report encoding failed!");
let decoded = Report::decode(&
mut Cursor::new(&encoded)).expect(
"Report decoding failed!");
if r != decoded {
println!(
"Report:");
println!(
"{:?}", r);
println!(
"Encoded Report:");
println!(
"{:?}", encoded);
println!(
"Decoded Report:");
println!(
"{:?}", decoded);
panic!(
"Report changed after encoding & decoding.");
}
}
extern "C" {
pub fn dapHpkeEncrypt(
aContext: *
mut c_void,
aAad: *
mut u8,
aAadLength: u32,
aPlaintext: *
mut u8,
aPlaintextLength: u32,
aOutputShare: &
mut ThinVec<u8>,
) -> bool;
pub fn dapSetupHpkeContextForTesting(
aKey: *
const u8,
aKeyLength: u32,
aInfo: *
mut u8,
aInfoLength: u32,
aPkEm: *
const u8,
aPkEmLength: u32,
aSkEm: *
const u8,
aSkEmLength: u32,
aOutputEncapsulatedKey: &
mut ThinVec<u8>,
) -> *
mut c_void;
pub fn dapDestroyHpkeContext(aContext: *
mut c_void);
}
struct HpkeContext(*
mut c_void);
impl Drop
for HpkeContext {
fn drop(&
mut self) {
unsafe {
dapDestroyHpkeContext(
self.
0);
}
}
}
type Testsuites = Vec<CiphersuiteTest>;
#[derive(Debug, Deserialize)]
pub struct HexString(
#[serde(with =
"hex")] Vec<u8>);
impl AsRef<[u8]>
for HexString {
fn as_ref(&
self) -> &[u8] {
&
self.
0
}
}
#[allow(dead_code)]
#[derive(Debug, Deserialize)]
struct CiphersuiteTest {
mode: i64,
kem_id: i64,
kdf_id: i64,
aead_id: i64,
info: HexString,
#[serde(rename =
"ikmR")]
ikm_r: HexString,
#[serde(rename =
"ikmE")]
ikm_e: HexString,
#[serde(rename =
"skRm")]
sk_r_m: HexString,
#[serde(rename =
"skEm")]
sk_e_m: HexString,
#[serde(rename =
"pkRm")]
pk_r_m: HexString,
#[serde(rename =
"pkEm")]
pk_e_m: HexString,
enc: HexString,
shared_secret: HexString,
key_schedule_context: HexString,
secret: HexString,
key: HexString,
base_nonce: HexString,
exporter_secret: HexString,
encryptions: Vec<Encryption>,
exports: Vec<Export>,
psk: Option<HexString>,
psk_id: Option<HexString>,
ikm_s: Option<HexString>,
sk_sm: Option<HexString>,
pk_sm: Option<HexString>,
}
#[derive(Debug, Deserialize)]
pub struct Encryption {
pub aad: HexString,
pub ciphertext: HexString,
pub nonce: HexString,
pub plaintext: HexString,
}
#[derive(Debug, Deserialize)]
pub struct Export {
pub exporter_context: HexString,
#[serde(rename =
"L")]
pub length: i64,
pub exported_value: HexString,
}
#[no_mangle]
pub extern "C" fn dap_test_hpke_encrypt() {
let file = File::open(
"hpke-vectors.json").unwrap();
let tests: Testsuites = serde_json::from_reader(file).unwrap();
let mut have_tested =
false;
for (test_idx, test)
in tests.into_iter().enumerate() {
// Mode must be "Base"
if test.mode !=
0
// KEM must be DHKEM(X25519, HKDF-SHA256)
|| test.kem_id !=
32
// KDF must be HKDF-SHA256
|| test.kdf_id !=
1
// AEAD must be AES-128-GCM
|| test.aead_id !=
1
{
continue;
}
have_tested =
true;
let mut pk_r_serialized = test.pk_r_m.
0;
let mut info = test.info.
0;
let mut pk_e_serialized = test.pk_e_m.
0;
let mut sk_e_serialized = test.sk_e_m.
0;
let mut encapsulated_key = ThinVec::<u8>::new();
let ctx = HpkeContext(
unsafe {
dapSetupHpkeContextForTesting(
pk_r_serialized.as_mut_ptr(),
pk_r_serialized.len().try_into().unwrap(),
info.as_mut_ptr(),
info.len().try_into().unwrap(),
pk_e_serialized.as_mut_ptr(),
pk_e_serialized.len().try_into().unwrap(),
sk_e_serialized.as_mut_ptr(),
sk_e_serialized.len().try_into().unwrap(),
&
mut encapsulated_key,
)
});
if ctx.
0.is_null() {
panic!(
"Failed to set up HPKE context.");
}
if encapsulated_key != test.enc.
0 {
panic!(
"Encapsulated key is wrong!");
}
for (encryption_idx, encryption)
in test.encryptions.into_iter().enumerate() {
let mut encrypted_share = ThinVec::<u8>::new();
let mut aad = encryption.aad.
0.clone();
let mut pt = encryption.plaintext.
0.clone();
unsafe {
dapHpkeEncrypt(
ctx.
0,
aad.as_mut_ptr(),
aad.len().try_into().unwrap(),
pt.as_mut_ptr(),
pt.len().try_into().unwrap(),
&
mut encrypted_share,
);
}
if encrypted_share != encryption.ciphertext.
0 {
println!(
"Test: {}, Encryption: {}", test_idx, encryption_idx);
println!(
"Expected:");
println!(
"{:?}", encryption.ciphertext.
0);
println!(
"Actual:");
println!(
"{:?}", encrypted_share);
panic!(
"Encryption outputs did not match!");
}
}
}
assert!(have_tested);
}