securedrop_protocol_minimal/
keys.rs1mod newsroom;
2
3use rand_core::{CryptoRng, RngCore};
4
5use crate::sign::{
6 DomainTag, FpfOnNewsroom, JournalistEphemeralKey, JournalistLongTermKey, Signature, SigningKey,
7 VerifyingKey,
8};
9
10use crate::message::{MessageKeyPair, MessagePublicKey};
11use crate::metadata::{MetadataKeyPair, MetadataPublicKey};
12use crate::primitives::dh_akem::DH_AKEM_PUBLIC_KEY_LEN;
13use crate::primitives::mlkem::MLKEM768_PUBLIC_KEY_LEN;
14use crate::primitives::x25519::{DH_PUBLIC_KEY_LEN, DHPrivateKey, DHPublicKey, DHSharedSecret};
15use crate::primitives::xwing::XWING_PUBLIC_KEY_LEN;
16use alloc::vec::Vec;
17
18pub struct KeyPair<SK, PK> {
20 pub(crate) sk: SK,
21 pub(crate) pk: PK,
22}
23
24pub type DhFetchKeyPair = KeyPair<DHPrivateKey, DHPublicKey>;
27pub type SigningKeyPair = KeyPair<SigningKey, VerifyingKey>;
28
29pub type SignedKeyBundlePublic = (KeyBundlePublic, Signature<JournalistEphemeralKey>);
32
33#[derive(Debug, Clone)]
35pub struct KeyBundlePublic {
36 pub apke_pk: MessagePublicKey,
38 pub metadata_pk: MetadataPublicKey,
40}
41
42impl KeyBundlePublic {
43 pub fn as_bytes(&self) -> Vec<u8> {
47 let mut out = Vec::new();
48 out.extend(self.apke_pk.as_bytes());
49 out.extend(self.metadata_pk.as_bytes());
50 out
51 }
52}
53
54pub(crate) struct MessageKeyBundle {
55 pub(crate) apke: MessageKeyPair,
56 pub(crate) metadata_kp: MetadataKeyPair,
57}
58
59impl MessageKeyBundle {
60 pub fn new(apke: MessageKeyPair, metadata_kp: MetadataKeyPair) -> Self {
61 Self { apke, metadata_kp }
62 }
63
64 pub(crate) fn public(&self) -> KeyBundlePublic {
65 KeyBundlePublic {
66 apke_pk: self.apke.public_key().clone(),
67 metadata_pk: self.metadata_kp.public_key().clone(),
68 }
69 }
70}
71
72pub(crate) struct SignedMessageKeyBundle {
73 pub(crate) bundle: MessageKeyBundle,
74 pub(crate) selfsig: Signature<JournalistEphemeralKey>,
75}
76
77#[derive(Debug, Clone)]
78pub struct SignedLongtermPubKeyBytes(
79 pub [u8; DH_AKEM_PUBLIC_KEY_LEN + MLKEM768_PUBLIC_KEY_LEN + DH_PUBLIC_KEY_LEN],
80);
81
82impl SignedLongtermPubKeyBytes {
83 pub(crate) fn from_keys(reply_apke: &MessagePublicKey, fetch_pk: &DHPublicKey) -> Self {
88 let apke_bytes = reply_apke.as_bytes();
89 let fetch_bytes = fetch_pk.into_bytes();
90
91 let mut pubkey_bytes =
92 [0u8; DH_AKEM_PUBLIC_KEY_LEN + MLKEM768_PUBLIC_KEY_LEN + DH_PUBLIC_KEY_LEN];
93 pubkey_bytes[..apke_bytes.len()].copy_from_slice(&apke_bytes);
94 pubkey_bytes[apke_bytes.len()..].copy_from_slice(&fetch_bytes);
95
96 Self(pubkey_bytes)
97 }
98
99 pub fn as_bytes(&self) -> &[u8] {
101 &self.0
102 }
103}
104
105#[derive(Clone, Debug)]
106pub struct Enrollment {
107 pub bundle: SignedLongtermPubKeyBytes,
108 pub selfsig: Signature<JournalistLongTermKey>,
109 pub keys: (VerifyingKey, DHPublicKey, MessagePublicKey),
110}
111
112pub struct SessionStorage {
114 pub fpf_key: Option<VerifyingKey>,
115 pub nr_key: Option<VerifyingKey>,
116 pub fpf_signature: Option<Signature<FpfOnNewsroom>>,
117}
118
119pub struct FPFKeyPair {
121 sk: SigningKey,
122 vk: VerifyingKey,
123}
124
125impl core::fmt::Debug for FPFKeyPair {
126 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
127 f.debug_struct("FPFKeyPair")
128 .field("vk", &self.vk)
129 .finish_non_exhaustive()
130 }
131}
132
133impl FPFKeyPair {
134 pub fn new<R: RngCore + CryptoRng>(mut rng: R) -> Result<Self, anyhow::Error> {
140 let sk = SigningKey::new(&mut rng)?;
141 let vk = sk.vk;
142 Ok(Self { sk, vk })
143 }
144
145 pub fn verifying_key(&self) -> VerifyingKey {
147 self.vk
148 }
149
150 pub fn sign<D: DomainTag>(&self, msg: &[u8]) -> Signature<D> {
152 self.sk.sign(msg)
153 }
154}
155
156pub use newsroom::NewsroomKeyPair;