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
#![no_std]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
)]
#![deny(unsafe_code)]
#![warn(rust_2018_idioms)]
pub use cipher::{self, BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher};
use cipher::{
consts::{U1, U32, U8},
generic_array::GenericArray,
};
use core::{convert::TryInto, marker::PhantomData};
mod sboxes;
pub use sboxes::Sbox;
#[derive(Clone, Copy)]
pub struct Gost89<S: Sbox> {
key: [u32; 8],
_p: PhantomData<S>,
}
impl<S: Sbox> NewBlockCipher for Gost89<S> {
type KeySize = U32;
fn new(key: &GenericArray<u8, U32>) -> Self {
let mut key_u32 = [0u32; 8];
key.chunks_exact(4)
.zip(key_u32.iter_mut())
.for_each(|(chunk, v)| *v = to_u32(chunk));
Self {
key: key_u32,
_p: Default::default(),
}
}
}
impl<S: Sbox> BlockCipher for Gost89<S> {
type BlockSize = U8;
type ParBlocks = U1;
}
impl<S: Sbox> BlockEncrypt for Gost89<S> {
#[inline]
fn encrypt_block(&self, block: &mut GenericArray<u8, U8>) {
let mut v = (to_u32(&block[0..4]), to_u32(&block[4..8]));
for _ in 0..3 {
for i in 0..8 {
v = (v.1, v.0 ^ S::g(v.1, self.key[i]));
}
}
for i in (0..8).rev() {
v = (v.1, v.0 ^ S::g(v.1, self.key[i]));
}
block[0..4].copy_from_slice(&v.1.to_be_bytes());
block[4..8].copy_from_slice(&v.0.to_be_bytes());
}
}
impl<S: Sbox> BlockDecrypt for Gost89<S> {
#[inline]
fn decrypt_block(&self, block: &mut GenericArray<u8, U8>) {
let mut v = (to_u32(&block[0..4]), to_u32(&block[4..8]));
for i in 0..8 {
v = (v.1, v.0 ^ S::g(v.1, self.key[i]));
}
for _ in 0..3 {
for i in (0..8).rev() {
v = (v.1, v.0 ^ S::g(v.1, self.key[i]));
}
}
block[0..4].copy_from_slice(&v.1.to_be_bytes());
block[4..8].copy_from_slice(&v.0.to_be_bytes());
}
}
pub type Magma = Gost89<sboxes::Tc26>;
pub type Gost89Test = Gost89<sboxes::TestSbox>;
pub type Gost89CryptoProA = Gost89<sboxes::CryptoProA>;
pub type Gost89CryptoProB = Gost89<sboxes::CryptoProB>;
pub type Gost89CryptoProC = Gost89<sboxes::CryptoProC>;
pub type Gost89CryptoProD = Gost89<sboxes::CryptoProD>;
fn to_u32(chunk: &[u8]) -> u32 {
u32::from_be_bytes(chunk.try_into().unwrap())
}