ck_meow/meow.rs
1use core::fmt;
2
3// See: https://strobe.sourceforge.io/specs for the specification for STROBE.
4use crate::kitten::{AlignedKittenState, STATE_SIZE_U8};
5use subtle::{Choice, ConstantTimeEq};
6use zeroize::{Zeroize, ZeroizeOnDrop};
7
8/// We use a hard coded security parameter of 128 bits.
9const SECURITY_PARAM: usize = 128;
10/// This is the rate of our sponge, given our security parameter.
11const MEOW_R: u8 = (STATE_SIZE_U8 - (2 * SECURITY_PARAM) / 8 - 2) as u8;
12/// The context string we use when initializing our construction.
13const MEOW_CONTEXT: &[u8] = b"Meow v0.1.0";
14
15// 6.2: Operations and flags.
16type Flags = u8;
17
18// Inbound flag. This is set when receiving data.
19const FLAG_I: Flags = 0b00000001;
20// Application flag. If set, data is moving to or from the application.
21const FLAG_A: Flags = 0b00000010;
22// Cipher flag. If set, the output depends on the cipher state.
23const FLAG_C: Flags = 0b00000100;
24// Transport flag. If set, the operation sends or receives dat on the transport.
25const FLAG_T: Flags = 0b00001000;
26// Meta flag. If set, indicates that the operation is handling metadata.
27const FLAG_M: Flags = 0b00010000;
28// Keytree flag. It's a mystery.
29const FLAG_K: Flags = 0b00100000;
30
31/// Represents the role of a participant.
32///
33/// This allows one state sending data and another state receiving data to come
34/// to the same result. Each of them modifies their role to be either the initiator
35/// or the responder, and this allows their state to be synchronized, since
36/// both parties agree on their respective roles.
37#[derive(Clone, Copy, Debug, PartialEq, Zeroize)]
38#[repr(u8)]
39enum Role {
40 /// We don't know which role we play yet.
41 Undecided = 2,
42 // We're the first person to send a message.
43 Initiator = 0,
44 // We're the first person to receive a message.
45 Responder = 1,
46}
47
48// We also need to be able to convert roles to flags, to include in our state updates.
49impl Role {
50 fn to_flag(self) -> Flags {
51 match self {
52 Role::Undecided => panic!("Undecided role was converted to flag."),
53 Role::Initiator => 0,
54 Role::Responder => 1,
55 }
56 }
57}
58
59impl From<u8> for Role {
60 fn from(x: u8) -> Self {
61 match x {
62 0 => Role::Initiator,
63 1 => Role::Responder,
64 _ => Role::Undecided,
65 }
66 }
67}
68
69/// A generic error to signal that MAC verification failed.
70#[derive(Clone, Copy, Debug)]
71pub struct MacError;
72
73impl fmt::Display for MacError {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 write!(f, "MAC failed to verify.")
76 }
77}
78
79fn check_zero(data: &[u8]) -> Result<(), MacError> {
80 let mut ok = Choice::from(1);
81 for b in data {
82 ok &= b.ct_eq(&0u8);
83 }
84 if !bool::from(ok) {
85 Err(MacError)
86 } else {
87 Ok(())
88 }
89}
90
91/// Represents the state of a Meow instance.
92///
93/// This is the main object you interact with when using Meow, and all of
94/// the functionalities of the framework are derived from methods on this
95/// object.
96///
97/// The basic idea is that each party creates their own local instance
98/// of Meow, and then performs various operations in sync, allowing them
99/// to hash data, encrypt it, verify its integrity, etc.
100///
101/// This crate contains examples of composite operations like that in its
102/// main documentation.
103///
104/// This object is cloneable, and that's very useful in certain situations,
105/// but one should be careful that the states are identical, and so some operations
106/// may not be secure because of common randomness between the states.
107///
108/// For example, the PRF output from both states will be the same right
109/// after forking them.
110///
111/// Many operations are divided into `send` and `recv` pairs. The idea is that
112/// one party performs `send`, sends some data, and then the other party uses
113/// `recv` with this data.
114///
115/// Many operations have a `meta` variant. These variants basically do the
116/// same thing as their normal variants, but have a bit of domain separation
117/// so that their result is separate.
118///
119/// Many operations also have a `more` argument. This can be used to split up
120/// an operation over multiple calls. For example, you might want to encrypt
121/// 1 GB of data as a single logical operation, but without having to store
122/// this entire piece of data in memory. Using `more` allows you to do this chunk
123/// by chunk, as if it were a single large operation. Each call after the first
124/// would set `more = true`, in order to indicate that it's a continuation
125/// of the previous call.
126#[cfg_attr(test, derive(Debug))]
127#[derive(Clone, ZeroizeOnDrop)]
128pub struct Meow {
129 state: AlignedKittenState,
130 pos: u8,
131 pos_begin: u8,
132 role: Role,
133 cur_flags: Flags,
134}
135
136impl Meow {
137 /// Create a new Meow instance.
138 ///
139 /// This function takes in a protocol string, which gets hashed into the state.
140 /// The intention is to use this for domain separation of different protocols based on Meow.
141 pub fn new(protocol: &[u8]) -> Self {
142 let mut state = AlignedKittenState([0u8; STATE_SIZE_U8]);
143 // "5.1:
144 // The initial state of the object is as follows:
145 // st = F([0x01, R+2, 0x01, 0x00, 0x01, 0x60] + ascii("STROBEvX.Y.Z"))
146 // pos = posbegin = 0
147 // I0 = None"
148 //
149 // Instead, we use a different context string.
150 state[0..6].copy_from_slice(&[0x01, (MEOW_R as u8) + 2, 0x01, 0x00, 0x01, 0x60]);
151 state[6..6 + MEOW_CONTEXT.len()].copy_from_slice(MEOW_CONTEXT);
152 state.permute();
153
154 let mut out = Self {
155 state,
156 pos: 0,
157 pos_begin: 0,
158 role: Role::Undecided,
159 cur_flags: 0,
160 };
161
162 out.meta_ad(protocol, false);
163
164 out
165 }
166
167 /// Absorb additional data into this state.
168 ///
169 /// This can be used as a way to hash in additional data, such as when
170 /// implementing an AEAD, or just a simple hash function.
171 ///
172 /// The semantics of this are also that each party already knows the data,
173 /// and doesn't have to send it to the other person.
174 pub fn ad(&mut self, data: &[u8], more: bool) {
175 self.begin_op(FLAG_A, more);
176 self.absorb(data);
177 }
178
179 /// Absorb additional metadata into this state.
180 ///
181 /// This is intended to be used to describe additional data, or for
182 /// framing: describing the operations being done.
183 pub fn meta_ad(&mut self, data: &[u8], more: bool) {
184 self.begin_op(FLAG_M | FLAG_A, more);
185 self.absorb(data);
186 }
187
188 /// Include a secret key into the state.
189 ///
190 /// This makes further operations dependent on knowing this secret key.
191 ///
192 /// For forward secrecy, the state is also ratcheted.
193 pub fn key(&mut self, data: &[u8], more: bool) {
194 self.begin_op(FLAG_A | FLAG_C, more);
195 self.overwrite(data);
196 }
197
198 /// Send some plaintext data to the other party.
199 ///
200 /// This is similar to `ad`, except the semantics are that the other person
201 /// will not already know this information, and so we additionally have
202 /// to send it to them.
203 pub fn send_clr(&mut self, data: &[u8], more: bool) {
204 self.begin_op(FLAG_A | FLAG_T, more);
205 self.absorb(data);
206 }
207
208 /// Send some plaintext metadata to the other party.
209 ///
210 /// Similarly to `send_clr`, the semantics are that the other party doesn't
211 /// know this information, and we need to send it to them.
212 pub fn meta_send_clr(&mut self, data: &[u8], more: bool) {
213 self.begin_op(FLAG_M | FLAG_A | FLAG_T, more);
214 self.absorb(data);
215 }
216
217 /// Receive plaintext data.
218 ///
219 /// This is the counterpart to `send_clr`.
220 pub fn recv_clr(&mut self, data: &[u8], more: bool) {
221 self.begin_op(FLAG_I | FLAG_A | FLAG_T, more);
222 self.absorb(data);
223 }
224
225 /// Receive plaintext metadata.
226 ///
227 /// This is the counterpart to `meta_recv_clr`.
228 pub fn meta_recv_clr(&mut self, data: &[u8], more: bool) {
229 self.begin_op(FLAG_M | FLAG_I | FLAG_A | FLAG_T, more);
230 self.absorb(data);
231 }
232
233 /// Send encrypted data.
234 ///
235 /// This function takes in the plaintext data to encrypt, and modifies
236 /// it in place to contain the encrypted data. This should then be sent
237 /// to the other party.
238 pub fn send_enc(&mut self, data: &mut [u8], more: bool) {
239 self.begin_op(FLAG_A | FLAG_C | FLAG_T, more);
240 self.absorb_and_set(data);
241 }
242
243 /// Send encrypted metadata.
244 ///
245 /// The intention of this operation is to send encrypted framing data,
246 /// which might be useful for some situations.
247 pub fn meta_send_enc(&mut self, data: &mut [u8], more: bool) {
248 self.begin_op(FLAG_M | FLAG_A | FLAG_C | FLAG_T, more);
249 self.absorb_and_set(data);
250 }
251
252 /// Receive encrypted data.
253 ///
254 /// This is the counterpart to `send_enc`.
255 ///
256 /// We start with a buffer of encrypted data, and then modify it to contain
257 /// the plaintext.
258 pub fn recv_enc(&mut self, data: &mut [u8], more: bool) {
259 self.begin_op(FLAG_I | FLAG_A | FLAG_C | FLAG_T, more);
260 self.exchange(data);
261 }
262
263 /// Received encrypted metadata.
264 pub fn meta_recv_enc(&mut self, data: &mut [u8], more: bool) {
265 self.begin_op(FLAG_M | FLAG_I | FLAG_A | FLAG_C | FLAG_T, more);
266 self.exchange(data);
267 }
268
269 /// Send a MAC to the other party.
270 ///
271 /// The buffer will be filled with a MAC, which verifies the integrity
272 /// of the operations done so far. This MAC is then intended to be sent
273 /// to the other party.
274 ///
275 /// This operation intentionally does not allow `more` to be used. This
276 /// is to match `recv_mac`.
277 pub fn send_mac(&mut self, data: &mut [u8]) {
278 self.begin_op(FLAG_C | FLAG_T, false);
279 self.copy(data);
280 }
281
282 /// Send a MAC of metadata to the other party.
283 ///
284 /// This is very similar to `send_mac`.
285 pub fn meta_send_mac(&mut self, data: &mut [u8]) {
286 self.begin_op(FLAG_M | FLAG_C | FLAG_T, false);
287 self.copy(data);
288 }
289
290 /// Receive and verify a MAC.
291 ///
292 /// The buffer contains the MAC to verify, and we need to mutate it
293 /// to be able to more conveniently check its correctness.
294 ///
295 /// This operation intentionally does not allow `more` to be used. This
296 /// is because a MAC should always be verified all at once, rather than in chunks.
297 pub fn recv_mac(&mut self, data: &mut [u8]) -> Result<(), MacError> {
298 self.begin_op(FLAG_I | FLAG_C | FLAG_T, false);
299 self.exchange(data);
300 check_zero(data)
301 }
302
303 /// Receive and verify a MAC of metadata.
304 ///
305 /// This is very similar to `recv_mac`.
306 pub fn meta_recv_mac(&mut self, data: &mut [u8]) -> Result<(), MacError> {
307 self.begin_op(FLAG_M | FLAG_I | FLAG_C | FLAG_T, false);
308 self.exchange(data);
309 check_zero(data)
310 }
311
312 /// Generate random bytes from the state.
313 pub fn prf(&mut self, data: &mut [u8], more: bool) {
314 self.begin_op(FLAG_I | FLAG_A | FLAG_C, more);
315 self.squeeze(data);
316 }
317
318 /// Ratchet the state forward.
319 ///
320 /// Because the state is modified with a permutation, we can use new states
321 /// to derive information about old states. Ratcheting prevents this flow
322 /// of information backwards.
323 pub fn ratchet(&mut self) {
324 self.ratchet_many(SECURITY_PARAM / 8, false)
325 }
326
327 /// Ratchet the state forward many times.
328 ///
329 /// The difference with `ratchet` is that you can specify how far to ratchet
330 /// the state. For `S` bits of security, you want to ratchet at least `S / 8`
331 /// bytes. Ratcheting more can function as a kind of "difficulty", like
332 /// you might want for password hashing.
333 ///
334 /// That said, you probably want a function dedicated for hashing passwords,
335 /// which have other security features, like being memory hard, and things like
336 /// that.
337 pub fn ratchet_many(&mut self, len: usize, more: bool) {
338 self.begin_op(FLAG_C, more);
339 self.zero_out(len);
340 }
341}
342
343impl Meow {
344 /// See: 7.1, running F
345 fn run_f(&mut self) {
346 self.state[self.pos as usize] &= self.pos_begin;
347 self.state[self.pos as usize + 1] &= 0x04;
348 self.state[MEOW_R as usize + 1] ^= 0x80;
349 self.state.permute();
350 self.pos = 0;
351 self.pos_begin = 0;
352 }
353
354 /// Move our writing position forward, possibly running the permutation
355 /// if we run out of space.
356 #[inline(always)]
357 fn advance_pos(&mut self) {
358 self.pos += 1;
359 if self.pos == MEOW_R {
360 self.run_f();
361 }
362 }
363
364 /// Absorb some data into this sponge.
365 fn absorb(&mut self, data: &[u8]) {
366 for b in data {
367 self.state[self.pos as usize] ^= b;
368 self.advance_pos();
369 }
370 }
371
372 /// Absorb data into the sponge, and the set the data to the resulting output.
373 fn absorb_and_set(&mut self, data: &mut [u8]) {
374 for b in data {
375 self.state[self.pos as usize] ^= *b;
376 *b = self.state[self.pos as usize];
377 self.advance_pos();
378 }
379 }
380
381 /// Overwrite bytes of the state with this data.
382 fn overwrite(&mut self, data: &[u8]) {
383 for &b in data {
384 self.state[self.pos as usize] = b;
385 self.advance_pos();
386 }
387 }
388
389 /// Zero out bytes of the state.
390 ///
391 /// A special case of `overwrite`.
392 fn zero_out(&mut self, len: usize) {
393 for _ in 0..len {
394 self.state[self.pos as usize] = 0;
395 self.advance_pos();
396 }
397 }
398
399 /// Exchange data with the state.
400 ///
401 /// Basically, the data gets xored with the state, and then the state
402 /// gets set to the initial value of the data.
403 ///
404 /// This is mainly useful when decrypting. There, you want to xor the
405 /// state to turn the ciphertext into the plaintext, but you then want
406 /// to commit to the ciphertext inside of the state, like the sender did.
407 ///
408 /// You can accomplish this by setting the state to the initial value of the data,
409 /// which was the ciphertext.
410 fn exchange(&mut self, data: &mut [u8]) {
411 for b in data {
412 let pos = self.pos as usize;
413 *b ^= self.state[pos];
414 self.state[pos] ^= *b;
415 self.advance_pos();
416 }
417 }
418
419 /// Copy bytes from the state.
420 fn copy(&mut self, data: &mut [u8]) {
421 for b in data {
422 let pos = self.pos as usize;
423 *b = self.state[pos];
424 self.advance_pos();
425 }
426 }
427
428 /// Squeeze bytes from the state.
429 ///
430 /// The difference with `copy` is that the operation is "destructive",
431 /// overwriting data with 0. This can provide some forward secrecy,
432 /// which is why we prefer this operation for extracting randomness
433 /// from the state.
434 fn squeeze(&mut self, data: &mut [u8]) {
435 for b in data {
436 let pos = self.pos as usize;
437 *b = self.state[pos];
438 self.state[pos] = 0;
439 self.advance_pos();
440 }
441 }
442
443 /// See: 7.3. Beginning an Operation.
444 fn begin_op(&mut self, flags: Flags, more: bool) {
445 if more {
446 assert_eq!(
447 self.cur_flags, flags,
448 "Cannot continue {:#b} with {:#b}.",
449 self.cur_flags, flags
450 );
451 return;
452 }
453 self.cur_flags = flags;
454
455 let flags = if flags & FLAG_T != 0 {
456 if let Role::Undecided = self.role {
457 self.role = Role::from(flags & FLAG_I);
458 }
459 flags ^ self.role.to_flag()
460 } else {
461 flags
462 };
463
464 let old_begin = self.pos_begin;
465 self.pos_begin = self.pos + 1;
466
467 self.absorb(&[old_begin, flags]);
468
469 let force_f = (flags & (FLAG_C | FLAG_K)) != 0;
470 if force_f && self.pos != 0 {
471 self.run_f();
472 }
473 }
474}
475
476#[cfg(test)]
477mod test {
478 use super::*;
479
480 #[test]
481 fn test_basic_encryption() {
482 let key = [0xAA; 32];
483 let message0 = [0xFF; MEOW_R as usize];
484
485 let mut encrypted = message0;
486 {
487 let mut meow = Meow::new(b"test protocol");
488 meow.key(&key, false);
489 meow.send_enc(&mut encrypted, false);
490 }
491
492 assert_ne!(message0, encrypted);
493
494 let mut message1 = encrypted;
495 {
496 let mut meow = Meow::new(b"test protocol");
497 meow.key(&key, false);
498 meow.recv_enc(&mut message1, false);
499 }
500
501 assert_eq!(message0, message1);
502 }
503
504 #[test]
505 fn test_encryption_with_nonce() {
506 let key = [0xAA; 32];
507 let nonce = [0xBB; 32];
508 let message0 = [0xFF; MEOW_R as usize];
509
510 let mut encrypted = message0.to_owned();
511 {
512 let mut meow = Meow::new(b"test protocol");
513 meow.key(&key, false);
514 meow.send_clr(&nonce, false);
515 meow.send_enc(&mut encrypted, false);
516 }
517
518 assert_ne!(message0, encrypted);
519
520 let mut message1 = encrypted.to_owned();
521 {
522 let mut meow = Meow::new(b"test protocol");
523 meow.key(&key, false);
524 meow.recv_clr(&nonce, false);
525 meow.recv_enc(&mut message1, false);
526 }
527
528 assert_eq!(message0, message1);
529 }
530
531 #[test]
532 fn test_authenticated_encryption() {
533 let key = [0xAA; 32];
534 let nonce = [0xBB; 32];
535 let message0 = [0xFF; MEOW_R as usize];
536
537 let mut mac = [0u8; 32];
538
539 let mut encrypted = message0.to_owned();
540 {
541 let mut meow = Meow::new(b"test protocol");
542 meow.key(&key, false);
543 meow.send_clr(&nonce, false);
544 meow.send_enc(&mut encrypted, false);
545 meow.send_mac(&mut mac);
546 }
547
548 assert_ne!(message0, encrypted);
549
550 let mut bad_mac = mac;
551 bad_mac[0] ^= 0xFF;
552
553 let mut message1 = encrypted.to_owned();
554 {
555 let mut meow = Meow::new(b"test protocol");
556 meow.key(&key, false);
557 meow.recv_clr(&nonce, false);
558 meow.recv_enc(&mut message1, false);
559 assert!(meow.clone().recv_mac(&mut mac).is_ok());
560 assert!(meow.clone().recv_mac(&mut bad_mac).is_err());
561 }
562
563 assert_eq!(message0, message1);
564 }
565
566 #[test]
567 fn test_prf() {
568 let mut hash0 = [0u8; 32];
569 {
570 let mut meow = Meow::new(b"test protocol");
571 meow.ad(b"hello A", false);
572 meow.prf(&mut hash0, false);
573 }
574
575 let mut hash1 = [0u8; 32];
576 {
577 let mut meow = Meow::new(b"test protocol");
578 meow.ad(b"hello B", false);
579 meow.prf(&mut hash1, false);
580 }
581
582 assert_ne!(hash0, hash1);
583 }
584
585 #[test]
586 fn test_streaming() {
587 let mut hash0 = [0u8; 32];
588 {
589 let mut meow = Meow::new(b"test protocol");
590 meow.ad(b"hello world!", false);
591 meow.prf(&mut hash0, false);
592 }
593
594 let mut hash1 = [0u8; 32];
595 {
596 let mut meow = Meow::new(b"test protocol");
597 meow.ad(b"hello", false);
598 meow.ad(b" world!", true);
599 meow.prf(&mut hash1, false);
600 }
601
602 assert_eq!(hash0, hash1);
603 }
604}