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
// This file is the part of `lea-rust`.
//
// Author: SitD <sitd0813@gmail.com>
//
// This file is licensed under the Unlicense.
// See LICENSE.txt for more information or you can obtain a copy at <http://unlicense.org/>.

//! LEA-128/192/256-CTR implementation
//!
//! * Examples
//!
//! Encryption
//! ```
//! use lea::ctr::Lea256Ctr;
//! use lea::stream_cipher::{NewStreamCipher, StreamCipher};
//! use lea::generic_array::arr;
//! use lea::generic_array::arr_impl;
//!
//! let key = arr![u8; 0x0F, 0x1E, 0x2D, 0x3C, 0x4B, 0x5A, 0x69, 0x78, 0x87, 0x96, 0xA5, 0xB4, 0xC3, 0xD2, 0xE1, 0xF0,
//!                    0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87, 0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F];
//! let counter = arr![u8; 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10];
//! let mut lea256ctr = Lea256Ctr::new(&key, &counter);
//!
//! let mut data = arr![u8; 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 
//!                         0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
//!                         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F];
//!
//! lea256ctr.encrypt(&mut data);
//!
//! let cipher = arr![u8; 0x15, 0x39, 0xF7, 0xA2, 0x1C, 0x0F, 0x16, 0x07, 0x6D, 0x90, 0xFB, 0xEB, 0x03, 0x97, 0xD4, 0x40,
//!                       0x2D, 0xFD, 0x4E, 0xB0, 0x44, 0x0B, 0x28, 0x3D, 0xE7, 0xE3, 0x0C, 0x36, 0x0D, 0x71, 0xF1, 0x47,
//!                       0x0E, 0x8B, 0xAF, 0xD2, 0x88, 0x3B, 0xA8, 0x08, 0x8D, 0x0C, 0x5D, 0xA7, 0xA9, 0x14, 0xAE, 0x90];
//!
//! assert_eq!(data, cipher);
//! ```
//!
//! Decryption
//! ```
//! use lea::ctr::Lea256Ctr;
//! use lea::stream_cipher::{NewStreamCipher, StreamCipher};
//! use lea::generic_array::arr;
//! use lea::generic_array::arr_impl;
//!
//! let key = arr![u8; 0x0F, 0x1E, 0x2D, 0x3C, 0x4B, 0x5A, 0x69, 0x78, 0x87, 0x96, 0xA5, 0xB4, 0xC3, 0xD2, 0xE1, 0xF0,
//!                    0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87, 0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F];
//! let counter = arr![u8; 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10];
//! let mut lea256ctr = Lea256Ctr::new(&key, &counter);
//!
//! let mut data = arr![u8; 0x15, 0x39, 0xF7, 0xA2, 0x1C, 0x0F, 0x16, 0x07, 0x6D, 0x90, 0xFB, 0xEB, 0x03, 0x97, 0xD4, 0x40,
//!                         0x2D, 0xFD, 0x4E, 0xB0, 0x44, 0x0B, 0x28, 0x3D, 0xE7, 0xE3, 0x0C, 0x36, 0x0D, 0x71, 0xF1, 0x47,
//!                         0x0E, 0x8B, 0xAF, 0xD2, 0x88, 0x3B, 0xA8, 0x08, 0x8D, 0x0C, 0x5D, 0xA7, 0xA9, 0x14, 0xAE, 0x90];
//!
//! lea256ctr.decrypt(&mut data);
//!
//! let plain = arr![u8; 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 
//!                      0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
//!                      0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F];
//!
//! assert_eq!(data, plain);
//! ```

use cfg_if::cfg_if;

use crate::{Lea128, Lea192, Lea256};
use crate::block_cipher_trait::BlockCipher;
use crate::generic_array::ArrayLength;
use crate::generic_array::GenericArray;
use crate::generic_array::typenum::{U16, U24, U32};
use crate::stream_cipher::{NewStreamCipher, StreamCipher};

macro_rules! generate_lea_ctr {
    ($name:ident, $cipher:ident, $key_size:ty) => {
        pub struct $name {
            cipher: $cipher,
            nonce: GenericArray<u8, U16>,
        }

        impl NewStreamCipher for $name {
            type KeySize = $key_size;
            type NonceSize = U16;
        
            fn new(key: &GenericArray<u8, Self::KeySize>, nonce: &GenericArray<u8, Self::NonceSize>) -> Self {
                let cipher = $cipher::new(&key);
                let nonce = *nonce;
        
                Self { cipher, nonce }
            }
        }
        
        impl StreamCipher for $name {
            fn encrypt(&mut self, data: &mut [u8]) {
                encrypt(&self.cipher, &self.nonce, data);
            }
        
            fn decrypt(&mut self, data: &mut [u8]) {
                encrypt(&self.cipher, &self.nonce, data);
            }
        }
    };
}

generate_lea_ctr!(Lea128Ctr, Lea128, U16);
generate_lea_ctr!(Lea192Ctr, Lea192, U24);
generate_lea_ctr!(Lea256Ctr, Lea256, U32);

fn encrypt<C: BlockCipher>(cipher: &C, nonce: &GenericArray<u8, C::BlockSize>, data: &mut [u8]) {
    let mut counter = nonce.clone();

    for data in data.chunks_mut(16) {
        let mut block = counter.clone();
        cipher.encrypt_block(&mut block);

        for i in 0..(data.len()) {
            data[i] ^= block[i];
        }

        increment_counter(&mut counter);
    }
}

fn increment_counter<L: ArrayLength<u8>>(counter: &mut GenericArray<u8, L>) {
    cfg_if! {
        if #[cfg(target_endian = "big")] {
            for n in counter.iter_mut() {
                *n += 1;
                if *n != 0 {
                    break;
                }
            }
        } else if #[cfg(target_endian = "little")] {
            #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
            unsafe { *(counter.as_mut_ptr() as *mut u128) += 1 };
        }
    }
}