use std::collections::VecDeque;
use crate::*;
use crate::constants::*;
use crate::core::cipher_key::CipherKey;
pub struct MagmaStream {
pub core: Magma,
pub(crate) context: StreamContext,
}
#[derive(Clone)]
pub(crate) struct StreamContext {
pub(crate) mode: CipherMode,
pub(crate) operation: Option<CipherOperation>,
pub(crate) iv: Vec<u64>,
pub(crate) padded: bool,
pub(crate) feedback: Feedback,
}
impl StreamContext {
fn new(cipher_mode: CipherMode) -> Self {
StreamContext {
mode: cipher_mode,
operation: None,
iv: Vec::from(IV_GOST_R3413_2015),
padded: false,
feedback: Feedback::new(),
}
}
}
#[derive(Clone)]
pub(crate) struct Feedback {
pub(crate) block: Option<u64>,
pub(crate) vector: Option<VecDeque<u64>>,
}
impl Feedback {
fn new() -> Self {
Feedback {
block: None,
vector: None,
}
}
}
impl MagmaStream {
pub fn new<T>(key: T, cipher_mode: CipherMode) -> Self
where
CipherKey: From<T>,
{
MagmaStream {
core: Magma::with_key(key),
context: StreamContext::new(cipher_mode),
}
}
pub fn set_key<T>(&mut self, key: T)
where
CipherKey: From<T>,
{
self.core.set_key(key);
self.reset_feedback();
}
pub fn set_mode(&mut self, cipher_mode: CipherMode) {
self.context.mode = cipher_mode;
self.reset_feedback();
}
pub fn set_substitution_box(&mut self, substitution_box: &[u8; 128]) {
self.core.set_substitution_box(substitution_box);
self.reset_feedback();
}
pub fn set_iv(&mut self, iv: &[u64]) {
self.context.iv = Vec::from(iv);
self.reset_feedback();
}
#[inline]
pub(crate) fn prepare_vector_ctr(&self) -> u64 {
self.ensure_iv_not_empty();
self.context.iv[0] & 0xffffffff_00000000
}
#[inline]
pub(crate) fn ensure_iv_not_empty(&self) {
if self.context.iv.is_empty() {
panic!("Initialization vector is empty!");
}
}
pub(crate) fn update_context(
&mut self,
cipher_operation: CipherOperation,
cipher_mode: CipherMode,
) {
if self.context.operation.as_ref() != Some(&cipher_operation)
|| self.context.mode != cipher_mode
{
self.context.operation = Some(cipher_operation);
self.context.mode = cipher_mode;
self.reset_feedback();
}
}
pub fn reset_context(&mut self) {
let cipher_mode = self.context.mode.clone();
self.context = StreamContext::new(cipher_mode);
}
pub fn reset_feedback(&mut self) {
self.context.feedback = Feedback::new();
}
pub fn get_mode(&self) -> CipherMode {
return self.context.mode;
}
pub fn encrypt(&mut self, buf: &[u8]) -> Vec<u8> {
let cipher_mode = self.context.mode;
self.update_context(CipherOperation::Encrypt, cipher_mode);
match cipher_mode {
CipherMode::ECB => ecb::encrypt(self, buf),
CipherMode::CTR => ctr::encrypt(self, buf),
CipherMode::CTR_ACPKM => ctr_acpkm::encrypt(self, buf),
CipherMode::OFB => ofb::encrypt(self, buf),
CipherMode::CBC => cbc::encrypt(self, buf),
CipherMode::CFB => cfb::encrypt(self, buf),
CipherMode::MAC => {
panic!("CipherMode::MAC can not be used in encrypting operation!")
}
}
}
pub fn decrypt(&mut self, buf: &[u8]) -> Vec<u8> {
let cipher_mode = self.context.mode;
self.update_context(CipherOperation::Decrypt, cipher_mode);
match cipher_mode {
CipherMode::ECB => ecb::decrypt(self, buf),
CipherMode::CTR => ctr::decrypt(self, buf),
CipherMode::CTR_ACPKM => ctr_acpkm::decrypt(self, buf),
CipherMode::OFB => ofb::decrypt(self, buf),
CipherMode::CBC => cbc::decrypt(self, buf),
CipherMode::CFB => cfb::decrypt(self, buf),
CipherMode::MAC => {
panic!("CipherMode::MAC can not be used in decrypting operation!")
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_initialization() {
let magma = MagmaStream::new([0;8],CipherMode::ECB);
assert_eq!(magma.context.iv, IV_GOST_R3413_2015);
}
#[test]
fn set_initialization_vector() {
let mut magma = MagmaStream::new([0;8],CipherMode::ECB);
let initialization_vector = vec![0x11223344_u64];
magma.set_iv(&initialization_vector);
assert_eq!(magma.context.iv, initialization_vector);
}
#[test]
fn cipher_ecb_gost_r_34_13_2015() {
use crypto_vectors::gost::r3413_2015;
let mut source = Vec::<u8>::new();
source.extend_from_slice(&r3413_2015::PLAINTEXT1.to_be_bytes());
source.extend_from_slice(&r3413_2015::PLAINTEXT2.to_be_bytes());
source.extend_from_slice(&r3413_2015::PLAINTEXT3.to_be_bytes());
source.extend_from_slice(&r3413_2015::PLAINTEXT4.to_be_bytes());
let mut magma =
MagmaStream::new(r3413_2015::CIPHER_KEY.clone(), CipherMode::ECB);
let encrypted = magma.encrypt(&source);
assert!(!encrypted.is_empty());
let mut expected = Vec::<u8>::new();
expected.extend_from_slice(&r3413_2015::CIPHERTEXT1_ECB.to_be_bytes());
expected.extend_from_slice(&r3413_2015::CIPHERTEXT2_ECB.to_be_bytes());
expected.extend_from_slice(&r3413_2015::CIPHERTEXT3_ECB.to_be_bytes());
expected.extend_from_slice(&r3413_2015::CIPHERTEXT4_ECB.to_be_bytes());
assert_eq!(encrypted, expected);
let decrypted = magma.decrypt(&encrypted);
assert_eq!(decrypted, source);
}
#[test]
fn cipher_ctr_gost_r_34_13_2015() {
use crypto_vectors::gost::r3413_2015;
let mut source = Vec::<u8>::new();
source.extend_from_slice(&r3413_2015::PLAINTEXT1.to_be_bytes());
source.extend_from_slice(&r3413_2015::PLAINTEXT2.to_be_bytes());
source.extend_from_slice(&r3413_2015::PLAINTEXT3.to_be_bytes());
source.extend_from_slice(&r3413_2015::PLAINTEXT4.to_be_bytes());
let mut magma = MagmaStream::new(r3413_2015::CIPHER_KEY.clone(), CipherMode::CTR);
let encrypted = magma.encrypt(&source);
assert!(!encrypted.is_empty());
let mut expected = Vec::<u8>::new();
expected.extend_from_slice(&r3413_2015::CIPHERTEXT1_CTR.to_be_bytes());
expected.extend_from_slice(&r3413_2015::CIPHERTEXT2_CTR.to_be_bytes());
expected.extend_from_slice(&r3413_2015::CIPHERTEXT3_CTR.to_be_bytes());
expected.extend_from_slice(&r3413_2015::CIPHERTEXT4_CTR.to_be_bytes());
assert_eq!(encrypted, expected);
let decrypted = magma.decrypt(&encrypted);
assert_eq!(decrypted, source);
}
#[test]
fn cipher_ctr_acpkm_r_1323565_1_017_2018() {
use crypto_vectors::gost::r1323565_1_017_2018::ctr_acpkm;
let mut magma = MagmaStream::new(ctr_acpkm::CIPHER_KEY.clone(), CipherMode::CTR_ACPKM);
let encrypted = magma.encrypt(&ctr_acpkm::PLAINTEXT);
assert!(!encrypted.is_empty());
assert_eq!(encrypted, ctr_acpkm::CIPHERTEXT);
let decrypted = magma.decrypt(&encrypted);
assert_eq!(decrypted, ctr_acpkm::PLAINTEXT);
}
#[test]
fn cipher_ofb_gost_r_34_13_2015() {
use crypto_vectors::gost::r3413_2015;
let mut source = Vec::<u8>::new();
source.extend_from_slice(&r3413_2015::PLAINTEXT1.to_be_bytes());
source.extend_from_slice(&r3413_2015::PLAINTEXT2.to_be_bytes());
source.extend_from_slice(&r3413_2015::PLAINTEXT3.to_be_bytes());
source.extend_from_slice(&r3413_2015::PLAINTEXT4.to_be_bytes());
let mut magma = MagmaStream::new(r3413_2015::CIPHER_KEY.clone(), CipherMode::OFB);
magma.set_iv(&IV_GOST_R3413_2015[..2]);
let encrypted = magma.encrypt(&source);
assert!(!encrypted.is_empty());
let mut expected = Vec::<u8>::new();
expected.extend_from_slice(&r3413_2015::CIPHERTEXT1_OFB.to_be_bytes());
expected.extend_from_slice(&r3413_2015::CIPHERTEXT2_OFB.to_be_bytes());
expected.extend_from_slice(&r3413_2015::CIPHERTEXT3_OFB.to_be_bytes());
expected.extend_from_slice(&r3413_2015::CIPHERTEXT4_OFB.to_be_bytes());
assert_eq!(encrypted, expected);
let decrypted = magma.decrypt(&encrypted);
assert_eq!(decrypted, source);
}
#[test]
fn cipher_cbc_gost_r_34_13_2015() {
use crypto_vectors::gost::r3413_2015;
let mut source = Vec::<u8>::new();
source.extend_from_slice(&r3413_2015::PLAINTEXT1.to_be_bytes());
source.extend_from_slice(&r3413_2015::PLAINTEXT2.to_be_bytes());
source.extend_from_slice(&r3413_2015::PLAINTEXT3.to_be_bytes());
source.extend_from_slice(&r3413_2015::PLAINTEXT4.to_be_bytes());
let mut magma = MagmaStream::new(r3413_2015::CIPHER_KEY.clone(), CipherMode::CBC);
let encrypted = magma.encrypt(&source);
assert!(!encrypted.is_empty());
let mut expected = Vec::<u8>::new();
expected.extend_from_slice(&r3413_2015::CIPHERTEXT1_CBC.to_be_bytes());
expected.extend_from_slice(&r3413_2015::CIPHERTEXT2_CBC.to_be_bytes());
expected.extend_from_slice(&r3413_2015::CIPHERTEXT3_CBC.to_be_bytes());
expected.extend_from_slice(&r3413_2015::CIPHERTEXT4_CBC.to_be_bytes());
assert_eq!(encrypted, expected);
let decrypted = magma.decrypt(&encrypted);
assert_eq!(decrypted, source);
}
#[test]
fn cipher_cfb_gost_r_34_13_2015() {
use crypto_vectors::gost::r3413_2015;
let mut source = Vec::<u8>::new();
source.extend_from_slice(&r3413_2015::PLAINTEXT1.to_be_bytes());
source.extend_from_slice(&r3413_2015::PLAINTEXT2.to_be_bytes());
source.extend_from_slice(&r3413_2015::PLAINTEXT3.to_be_bytes());
source.extend_from_slice(&r3413_2015::PLAINTEXT4.to_be_bytes());
let mut magma = MagmaStream::new(r3413_2015::CIPHER_KEY.clone(), CipherMode::CFB);
magma.set_iv(&IV_GOST_R3413_2015[..2]);
let encrypted = magma.encrypt(&source);
assert!(!encrypted.is_empty());
let mut expected = Vec::<u8>::new();
expected.extend_from_slice(&r3413_2015::CIPHERTEXT1_CFB.to_be_bytes());
expected.extend_from_slice(&r3413_2015::CIPHERTEXT2_CFB.to_be_bytes());
expected.extend_from_slice(&r3413_2015::CIPHERTEXT3_CFB.to_be_bytes());
expected.extend_from_slice(&r3413_2015::CIPHERTEXT4_CFB.to_be_bytes());
assert_eq!(encrypted, expected);
let decrypted = magma.decrypt(&encrypted);
assert_eq!(decrypted, source);
}
}