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}