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
use subtle::ConstantTimeEq;
use ::common::{ Tag, tags, with, pad, absorb };
use ::constant::{ U, S, BLOCK_LENGTH, KEY_LENGTH, TAG_LENGTH };
use ::{ permutation, Norx, Encrypt, Decrypt };


pub struct Process<Mode> {
    state: [U; S],
    started: bool,
    _mode: Mode
}

impl Norx {
    pub fn encrypt(self, aad: &[u8]) -> Process<Encrypt> {
        let Norx(mut state) = self;
        absorb::<tags::Header>(&mut state, aad);

        Process { state, started: false, _mode: Encrypt }
    }

    pub fn decrypt(self, aad: &[u8]) -> Process<Decrypt> {
        let Norx(mut state) = self;
        absorb::<tags::Header>(&mut state, aad);

        Process { state, started: false, _mode: Decrypt }
    }
}

impl Process<Encrypt> {
    pub fn process<'a, I>(&mut self, bufs: I)
        where I: Iterator<Item = (&'a [u8; BLOCK_LENGTH], &'a mut [u8; BLOCK_LENGTH])>
    {
        for (input, output) in bufs {
            self.started = true;

            self.state[15] ^= <tags::Payload as Tag>::TAG;
            permutation::norx(&mut self.state);

            with(&mut self.state, |state| {
                for i in 0..BLOCK_LENGTH {
                    state[i] ^= input[i];
                }
                output.copy_from_slice(&state[..BLOCK_LENGTH]);
            });
        }
    }

    pub fn finalize(mut self, key: &[u8; KEY_LENGTH], aad2: &[u8], input: &[u8], output: &mut [u8]) {
        assert!(input.len() < BLOCK_LENGTH);
        assert_eq!(input.len() + TAG_LENGTH, output.len());

        let (output, tag) = output.split_at_mut(input.len());
        let tag = array_mut_ref!(tag, 0, TAG_LENGTH);

        if self.started || !input.is_empty() {
            let input_pad = pad(input);

            self.state[15] ^= <tags::Payload as Tag>::TAG;
            permutation::norx(&mut self.state);

            with(&mut self.state, |state| {
                for i in 0..BLOCK_LENGTH {
                    state[i] ^= input_pad[i];
                }
                output.copy_from_slice(&state[..input.len()]);
            });
        }

        Norx(self.state).finalize(key, aad2, tag);
    }
}

impl Process<Decrypt> {
    pub fn process<'a, I>(&mut self, bufs: I)
        where I: Iterator<Item = (&'a [u8; BLOCK_LENGTH], &'a mut [u8; BLOCK_LENGTH])>
    {
        for (input, output) in bufs {
            self.started = true;

            self.state[15] ^= <tags::Payload as Tag>::TAG;
            permutation::norx(&mut self.state);

            with(&mut self.state, |state| {
                for i in 0..BLOCK_LENGTH {
                    output[i] = state[i] ^ input[i];
                }
                state[..BLOCK_LENGTH].copy_from_slice(input);
            });
        }
    }

    pub fn finalize(mut self, key: &[u8; KEY_LENGTH], aad2: &[u8], input: &[u8], output: &mut [u8]) -> bool {
        assert!(output.len() < BLOCK_LENGTH);
        assert_eq!(input.len(), output.len() + TAG_LENGTH);

        let (input, tag) = input.split_at(output.len());

        if self.started || !output.is_empty() {
            let mut lastblock = [0; BLOCK_LENGTH];

            self.state[15] ^= <tags::Payload as Tag>::TAG;
            permutation::norx(&mut self.state);

            with(&mut self.state, |state| {
                lastblock[..input.len()].copy_from_slice(input);
                lastblock[input.len()..].copy_from_slice(&state[..BLOCK_LENGTH][input.len()..]);
                lastblock[input.len()] ^= 0x01;
                lastblock[BLOCK_LENGTH - 1] ^= 0x80;

                for i in 0..input.len() {
                    output[i] = state[i] ^ lastblock[i];
                }
                state[..BLOCK_LENGTH].copy_from_slice(&lastblock);
            });
        }

        let mut tag2 = [0; TAG_LENGTH];
        Norx(self.state).finalize(key, aad2, &mut tag2);

        tag.ct_eq(&tag2).unwrap_u8() == 1
    }
}