Skip to main content

opcua_crypto/aes/
aeskey.rs

1// OPCUA for Rust
2// SPDX-License-Identifier: MPL-2.0
3// Copyright (C) 2017-2024 Adam Lock
4
5//! Symmetric encryption / decryption wrapper.
6
7use std::result::Result;
8
9use aes::cipher::generic_array::GenericArray;
10use aes::cipher::{block_padding::NoPadding, BlockDecryptMut, BlockEncryptMut, KeyIvInit};
11
12use opcua_types::status_code::StatusCode;
13use opcua_types::Error;
14
15type Aes128CbcEnc = cbc::Encryptor<aes::Aes128>;
16type Aes128CbcDec = cbc::Decryptor<aes::Aes128>;
17type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>;
18type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;
19
20type AesArray128 = GenericArray<u8, <aes::Aes128 as aes::cipher::BlockSizeUser>::BlockSize>;
21type AesArray256 = GenericArray<u8, <aes::Aes256 as aes::cipher::KeySizeUser>::KeySize>;
22
23type EncryptResult = Result<usize, Error>;
24
25#[derive(Debug)]
26/// Wrapper around an AES key.
27pub struct AesKey {
28    value: Vec<u8>,
29}
30impl AesKey {
31    /// Create a new AES key with the given security policy and raw value.
32    pub fn new(value: Vec<u8>) -> AesKey {
33        AesKey { value }
34    }
35
36    /// Get the raw value of this AES key.
37    pub fn value(&self) -> &[u8] {
38        &self.value
39    }
40
41    pub(crate) fn encrypt_aes128_cbc(
42        &self,
43        src: &[u8],
44        iv: &[u8],
45        dst: &mut [u8],
46    ) -> EncryptResult {
47        Aes128CbcEnc::new(
48            AesArray128::from_slice(&self.value),
49            AesArray128::from_slice(iv),
50        )
51        .encrypt_padded_b2b_mut::<NoPadding>(src, dst)
52        .map_err(|e| Error::new(StatusCode::BadUnexpectedError, e.to_string()))?;
53        Ok(src.len())
54    }
55
56    pub(crate) fn encrypt_aes256_cbc(
57        &self,
58        src: &[u8],
59        iv: &[u8],
60        dst: &mut [u8],
61    ) -> EncryptResult {
62        Aes256CbcEnc::new(
63            AesArray256::from_slice(&self.value),
64            AesArray128::from_slice(iv),
65        )
66        .encrypt_padded_b2b_mut::<NoPadding>(src, dst)
67        .map_err(|e| Error::new(StatusCode::BadUnexpectedError, e.to_string()))?;
68        Ok(src.len())
69    }
70
71    pub(crate) fn decrypt_aes128_cbc(
72        &self,
73        src: &[u8],
74        iv: &[u8],
75        dst: &mut [u8],
76    ) -> EncryptResult {
77        Aes128CbcDec::new(
78            AesArray128::from_slice(&self.value),
79            AesArray128::from_slice(iv),
80        )
81        .decrypt_padded_b2b_mut::<NoPadding>(src, dst)
82        .map_err(|e| Error::new(StatusCode::BadUnexpectedError, e.to_string()))?;
83        Ok(src.len())
84    }
85
86    pub(crate) fn decrypt_aes256_cbc(
87        &self,
88        src: &[u8],
89        iv: &[u8],
90        dst: &mut [u8],
91    ) -> EncryptResult {
92        Aes256CbcDec::new(
93            AesArray256::from_slice(&self.value),
94            AesArray128::from_slice(iv),
95        )
96        .decrypt_padded_b2b_mut::<NoPadding>(src, dst)
97        .map_err(|e| Error::new(StatusCode::BadUnexpectedError, e.to_string()))?;
98        Ok(src.len())
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use std::thread;
105
106    use super::*;
107
108    #[test]
109    fn test_aeskey_cross_thread() {
110        let v: [u8; 5] = [1, 2, 3, 4, 5];
111        let k = AesKey::new(v.to_vec());
112        let child = thread::spawn(move || {
113            println!("k={k:?}");
114        });
115        let _ = child.join();
116    }
117}