#![cfg(feature = "rust")]
use std::fs;
use std::path::PathBuf;
use pg_core::api::Parameters;
use pg_core::artifacts::{UserSecretKey, VerifyingKey};
use pg_core::client::rust::UnsealerMemoryConfig;
use pg_core::client::Unsealer;
use pg_core::consts::{
PREAMBLE_SIZE, PRELUDE, PRELUDE_SIZE, VERSION_0, VERSION_1, VERSION_2, VERSION_SIZE,
};
use pg_core::kem::cgw_kv::CGWKV;
use serde::Deserialize;
fn testdata(name: &str) -> Vec<u8> {
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("testdata/wire-format-v3")
.join(name);
fs::read(&path).unwrap_or_else(|e| panic!("read {}: {e}", path.display()))
}
#[derive(Deserialize)]
struct Meta {
#[serde(rename = "recipientId")]
recipient_id: String,
#[serde(rename = "plaintextB64")]
plaintext_b64: String,
}
struct Fixture {
meta: Meta,
vk: VerifyingKey,
usk: UserSecretKey<CGWKV>,
want: Vec<u8>,
}
fn fixture() -> Fixture {
#[derive(Deserialize)]
struct UskResponse {
key: UserSecretKey<CGWKV>,
}
let meta: Meta = serde_json::from_slice(&testdata("meta.json")).expect("parse meta.json");
let vk: Parameters<VerifyingKey> =
serde_json::from_slice(&testdata("vk.json")).expect("parse vk.json");
let usk: UskResponse = serde_json::from_slice(&testdata("usk.json")).expect("parse usk.json");
let want = b64(&meta.plaintext_b64);
Fixture {
meta,
vk: vk.public_key,
usk: usk.key,
want,
}
}
#[test]
fn wire_constants_are_pinned() {
assert_eq!(PRELUDE, [0x14, 0x8A, 0x8E, 0xA7], "PRELUDE bytes changed");
assert_eq!(VERSION_0, 0, "VERSION_0 changed");
assert_eq!(VERSION_1, 1, "VERSION_1 changed");
assert_eq!(VERSION_2, 2, "VERSION_2 changed");
assert_eq!(PREAMBLE_SIZE, 10, "preamble layout changed");
}
#[test]
#[allow(deprecated)]
fn deprecated_aliases_match_their_replacements() {
use pg_core::consts::{VERSION_V1, VERSION_V2, VERSION_V3};
assert_eq!(VERSION_V1, VERSION_0, "VERSION_V1 is no longer version 0");
assert_eq!(VERSION_V2, VERSION_1, "VERSION_V2 is no longer version 1");
assert_eq!(VERSION_V3, VERSION_2, "VERSION_V3 is no longer version 2");
}
#[test]
fn golden_fixtures_carry_the_pinned_preamble() {
for name in ["stream.bin", "mem.bin"] {
let ct = testdata(name);
assert!(ct.len() > PREAMBLE_SIZE, "{name}: too short");
assert_eq!(&ct[..PRELUDE_SIZE], &PRELUDE, "{name}: prelude mismatch");
let version = u16::from_be_bytes(
ct[PRELUDE_SIZE..PRELUDE_SIZE + VERSION_SIZE]
.try_into()
.unwrap(),
);
assert_eq!(version, VERSION_2, "{name}: version mismatch");
}
}
#[test]
fn golden_mem_fixture_unseals() {
let f = fixture();
let unsealer = Unsealer::<Vec<u8>, UnsealerMemoryConfig>::new(testdata("mem.bin"), &f.vk)
.expect("parse the golden in-memory container");
let (plain, _verified) = unsealer
.unseal(&f.meta.recipient_id, &f.usk)
.expect("unseal the golden in-memory container");
assert_eq!(plain, f.want, "decrypted plaintext changed");
}
#[test]
#[cfg(feature = "stream")]
fn golden_stream_fixture_unseals() {
use pg_core::client::rust::stream::UnsealerStreamConfig;
let f = fixture();
let ct = testdata("stream.bin");
let mut plain = Vec::new();
futures::executor::block_on(async {
let mut reader = futures::io::Cursor::new(&ct);
let unsealer = Unsealer::<_, UnsealerStreamConfig>::new(&mut reader, &f.vk)
.await
.expect("parse the golden streaming container");
unsealer
.unseal(&f.meta.recipient_id, &f.usk, &mut plain)
.await
.expect("unseal the golden streaming container");
});
assert_eq!(plain, f.want, "decrypted plaintext changed");
}
fn b64(s: &str) -> Vec<u8> {
const ALPHABET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
let mut out = Vec::with_capacity(s.len() / 4 * 3);
let mut buf: u32 = 0;
let mut bits = 0;
for &c in s.as_bytes() {
if c == b'=' {
break;
}
let v = ALPHABET
.iter()
.position(|&a| a == c)
.unwrap_or_else(|| panic!("invalid base64 byte {c}")) as u32;
buf = (buf << 6) | v;
bits += 6;
if bits >= 8 {
bits -= 8;
out.push((buf >> bits) as u8);
}
}
out
}