1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use crate::{
aead::{Aead, AeadTag},
kdf::Kdf as KdfTrait,
kem::{EncappedKey, Kem as KemTrait},
kex::KeyExchange,
op_mode::{OpModeR, OpModeS},
setup::{setup_receiver, setup_sender},
HpkeError,
};
use rand::{CryptoRng, RngCore};
pub fn single_shot_seal<A, Kdf, Kem, R>(
mode: &OpModeS<Kem::Kex, Kdf>,
pk_recip: &<Kem::Kex as KeyExchange>::PublicKey,
info: &[u8],
plaintext: &mut [u8],
aad: &[u8],
csprng: &mut R,
) -> Result<(EncappedKey<Kem::Kex>, AeadTag<A>), HpkeError>
where
A: Aead,
Kdf: KdfTrait,
Kem: KemTrait,
R: CryptoRng + RngCore,
{
let (encapped_key, mut aead_ctx) =
setup_sender::<A, Kdf, Kem, R>(mode, pk_recip, info, csprng)?;
let tag = aead_ctx.seal(plaintext, aad)?;
Ok((encapped_key, tag))
}
pub fn single_shot_open<A, Kdf, Kem>(
mode: &OpModeR<Kem::Kex, Kdf>,
sk_recip: &<Kem::Kex as KeyExchange>::PrivateKey,
encapped_key: &EncappedKey<Kem::Kex>,
info: &[u8],
ciphertext: &mut [u8],
aad: &[u8],
tag: &AeadTag<A>,
) -> Result<(), HpkeError>
where
A: Aead,
Kdf: KdfTrait,
Kem: KemTrait,
{
let mut aead_ctx = setup_receiver::<A, Kdf, Kem>(mode, sk_recip, encapped_key, info)?;
aead_ctx.open(ciphertext, aad, tag)
}
#[cfg(test)]
mod test {
use super::{single_shot_open, single_shot_seal};
use crate::{
aead::ChaCha20Poly1305,
kdf::HkdfSha256,
kem::{Kem as KemTrait, X25519HkdfSha256},
kex::KeyExchange,
op_mode::{OpModeR, OpModeS},
test_util::gen_psk_bundle,
};
#[test]
fn test_single_shot_correctness() {
type A = ChaCha20Poly1305;
type Kd = HkdfSha256;
type Ke = X25519HkdfSha256;
type Kex = <Ke as KemTrait>::Kex;
let msg = b"Good night, a-ding ding ding ding ding";
let aad = b"Five four three two one";
let mut csprng = rand::thread_rng();
let info = b"why would you think in a million years that that would actually work";
let psk_bundle = gen_psk_bundle::<Kd>();
let (sk_sender_id, pk_sender_id) = Kex::gen_keypair(&mut csprng);
let (sk_recip, pk_recip) = Kex::gen_keypair(&mut csprng);
let sender_mode =
OpModeS::<Kex, _>::AuthPsk((sk_sender_id, pk_sender_id.clone()), psk_bundle.clone());
let receiver_mode = OpModeR::<Kex, _>::AuthPsk(pk_sender_id, psk_bundle);
let mut ciphertext = msg.clone();
let (encapped_key, tag) = single_shot_seal::<A, _, Ke, _>(
&sender_mode,
&pk_recip,
&info[..],
&mut ciphertext[..],
aad,
&mut csprng,
)
.expect("single_shot_seal() failed");
assert!(&ciphertext[..] != &msg[..]);
single_shot_open::<A, _, Ke>(
&receiver_mode,
&sk_recip,
&encapped_key,
info,
&mut ciphertext[..],
aad,
&tag,
)
.expect("single_shot_open() failed");
let decrypted = ciphertext;
assert_eq!(&decrypted[..], &msg[..]);
}
}