Skip to main content

magic_crypt/
lib.rs

1/*!
2# MagicCrypt
3
4MagicCrypt is a Java/PHP/NodeJS/Rust library to encrypt/decrypt strings, files, or data, using Data Encryption Standard(DES) or Advanced Encryption Standard(AES) algorithms. It supports CBC block cipher mode, PKCS7 padding and 64, 128, 192 or 256-bits key length.
5
6## Security Notice
7
8MagicCrypt uses an older encryption design and is not recommended for new projects.
9
10For new applications, please use a modern library that supports authenticated encryption. Authenticated encryption can protect encrypted data from both reading and unauthorized changes.
11
12## For Rust
13
14### Migrating from 5.x to 6.0
15
16Version 6.0 requires Rust 1.89 or later.
17
18`MagicCryptError::Base64Error` and `From<base64::DecodeError>` now use `base64` 0.23.
19If your code uses `base64::DecodeError` with this library, update your direct `base64` dependency to `0.23.1`.
20Update matches from `DecodeError::InvalidLastSymbol(_, _)` to `DecodeError::InvalidLastSymbol { .. }`.
21
22### Example
23
24```rust
25use magic_crypt::{new_magic_crypt, MagicCryptTrait};
26
27let mc = new_magic_crypt!("magickey", 256);
28
29let base64 = mc.encrypt_str_to_base64("http://magiclen.org");
30
31assert_eq!("DS/2U8royDnJDiNY2ps3f6ZoTbpZo8ZtUGYLGEjwLDQ=", base64);
32
33assert_eq!("http://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap());
34```
35
36## Change the Buffer Size
37
38The default buffer size for the `encrypt_reader_to_writer` method and the `decrypt_reader_to_writer` method is 4096 bytes. If you want to change that, you can use the `encrypt_reader_to_writer2` method or the `decrypt_reader_to_writer2` method, and define a length explicitly.
39
40For example, to change the buffer size to 256 bytes,
41
42```rust
43use std::io::Cursor;
44
45use base64::Engine;
46use magic_crypt::{new_magic_crypt, MagicCryptTrait};
47use magic_crypt::array::typenum::U256;
48
49let mc = new_magic_crypt!("magickey", 256);
50
51# #[cfg(feature = "std")] {
52let mut reader = Cursor::new("http://magiclen.org");
53let mut writer = Vec::new();
54
55mc.encrypt_reader_to_writer2::<U256>(&mut reader, &mut writer).unwrap();
56
57let base64 = base64::engine::general_purpose::STANDARD.encode(&writer);
58
59assert_eq!("DS/2U8royDnJDiNY2ps3f6ZoTbpZo8ZtUGYLGEjwLDQ=", base64);
60
61assert_eq!("http://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap());
62# }
63```
64
65## No Std
66
67Disable the default features to compile this crate without std.
68
69```toml
70[dependencies.magic-crypt]
71version = "*"
72default-features = false
73```
74
75## For Java
76
77Refer to <https://github.com/magiclen/MagicCrypt>.
78
79## For PHP
80
81Refer to <https://github.com/magiclen/MagicCrypt>.
82
83## For NodeJS
84
85Refer to <https://github.com/magiclen/node-magiccrypt>.
86*/
87
88#![cfg_attr(not(feature = "std"), no_std)]
89
90extern crate alloc;
91
92mod ciphers;
93mod errors;
94mod functions;
95mod macros;
96mod secure_bit;
97mod traits;
98
99use alloc::vec::Vec;
100#[cfg(feature = "std")]
101use std::io::{Read, Write};
102
103#[cfg(feature = "std")]
104use array::ArraySize;
105#[cfg(feature = "std")]
106use array::typenum::{IsGreaterOrEqual, PartialDiv, True, U16};
107pub use cbc::cipher::array;
108pub use ciphers::{
109    aes128::MagicCrypt128, aes192::MagicCrypt192, aes256::MagicCrypt256, des64::MagicCrypt64,
110};
111pub use errors::MagicCryptError;
112pub use secure_bit::SecureBit;
113pub use traits::MagicCryptTrait;
114
115#[derive(Debug, Clone)]
116enum MagicCryptCipher {
117    DES64(MagicCrypt64),
118    AES128(MagicCrypt128),
119    AES192(MagicCrypt192),
120    AES256(MagicCrypt256),
121}
122
123/// This struct can help you encrypt or decrypt data in a quick way.
124#[derive(Debug, Clone)]
125pub struct MagicCrypt {
126    cipher: MagicCryptCipher,
127}
128
129impl MagicCrypt {
130    /// Create a new `MagicCrypt` instance. You may want to use the `new_magic_crypt!` macro.
131    pub fn new<S: AsRef<[u8]>, V: AsRef<[u8]>>(
132        key: S,
133        bit: SecureBit,
134        iv: Option<V>,
135    ) -> MagicCrypt {
136        let cipher = match bit {
137            SecureBit::Bit64 => MagicCryptCipher::DES64(MagicCrypt64::new(key, iv)),
138            SecureBit::Bit128 => MagicCryptCipher::AES128(MagicCrypt128::new(key, iv)),
139            SecureBit::Bit192 => MagicCryptCipher::AES192(MagicCrypt192::new(key, iv)),
140            SecureBit::Bit256 => MagicCryptCipher::AES256(MagicCrypt256::new(key, iv)),
141        };
142
143        MagicCrypt {
144            cipher,
145        }
146    }
147}
148
149impl MagicCryptTrait for MagicCrypt {
150    #[inline]
151    fn new<S: AsRef<[u8]>, V: AsRef<[u8]>>(key: S, iv: Option<V>) -> MagicCrypt {
152        MagicCrypt::new(key, SecureBit::default(), iv)
153    }
154
155    #[inline]
156    fn encrypt_to_bytes<T: ?Sized + AsRef<[u8]>>(&self, data: &T) -> Vec<u8> {
157        match &self.cipher {
158            MagicCryptCipher::DES64(mc) => mc.encrypt_to_bytes(data),
159            MagicCryptCipher::AES128(mc) => mc.encrypt_to_bytes(data),
160            MagicCryptCipher::AES192(mc) => mc.encrypt_to_bytes(data),
161            MagicCryptCipher::AES256(mc) => mc.encrypt_to_bytes(data),
162        }
163    }
164
165    #[cfg(feature = "std")]
166    #[inline]
167    fn encrypt_reader_to_bytes(&self, reader: &mut dyn Read) -> Result<Vec<u8>, MagicCryptError> {
168        match &self.cipher {
169            MagicCryptCipher::DES64(mc) => mc.encrypt_reader_to_bytes(reader),
170            MagicCryptCipher::AES128(mc) => mc.encrypt_reader_to_bytes(reader),
171            MagicCryptCipher::AES192(mc) => mc.encrypt_reader_to_bytes(reader),
172            MagicCryptCipher::AES256(mc) => mc.encrypt_reader_to_bytes(reader),
173        }
174    }
175
176    #[cfg(feature = "std")]
177    #[inline]
178    fn encrypt_reader_to_writer2<
179        N: ArraySize + PartialDiv<U16> + IsGreaterOrEqual<U16, Output = True>,
180    >(
181        &self,
182        reader: &mut dyn Read,
183        writer: &mut dyn Write,
184    ) -> Result<(), MagicCryptError> {
185        match &self.cipher {
186            MagicCryptCipher::DES64(mc) => mc.encrypt_reader_to_writer2::<N>(reader, writer),
187            MagicCryptCipher::AES128(mc) => mc.encrypt_reader_to_writer2::<N>(reader, writer),
188            MagicCryptCipher::AES192(mc) => mc.encrypt_reader_to_writer2::<N>(reader, writer),
189            MagicCryptCipher::AES256(mc) => mc.encrypt_reader_to_writer2::<N>(reader, writer),
190        }
191    }
192
193    #[inline]
194    fn decrypt_bytes_to_bytes<T: ?Sized + AsRef<[u8]>>(
195        &self,
196        bytes: &T,
197    ) -> Result<Vec<u8>, MagicCryptError> {
198        match &self.cipher {
199            MagicCryptCipher::DES64(mc) => mc.decrypt_bytes_to_bytes(bytes),
200            MagicCryptCipher::AES128(mc) => mc.decrypt_bytes_to_bytes(bytes),
201            MagicCryptCipher::AES192(mc) => mc.decrypt_bytes_to_bytes(bytes),
202            MagicCryptCipher::AES256(mc) => mc.decrypt_bytes_to_bytes(bytes),
203        }
204    }
205
206    #[cfg(feature = "std")]
207    #[inline]
208    fn decrypt_reader_to_bytes(&self, reader: &mut dyn Read) -> Result<Vec<u8>, MagicCryptError> {
209        match &self.cipher {
210            MagicCryptCipher::DES64(mc) => mc.decrypt_reader_to_bytes(reader),
211            MagicCryptCipher::AES128(mc) => mc.decrypt_reader_to_bytes(reader),
212            MagicCryptCipher::AES192(mc) => mc.decrypt_reader_to_bytes(reader),
213            MagicCryptCipher::AES256(mc) => mc.decrypt_reader_to_bytes(reader),
214        }
215    }
216
217    #[cfg(feature = "std")]
218    #[inline]
219    fn decrypt_reader_to_writer2<
220        N: ArraySize + PartialDiv<U16> + IsGreaterOrEqual<U16, Output = True>,
221    >(
222        &self,
223        reader: &mut dyn Read,
224        writer: &mut dyn Write,
225    ) -> Result<(), MagicCryptError> {
226        match &self.cipher {
227            MagicCryptCipher::DES64(mc) => mc.decrypt_reader_to_writer2::<N>(reader, writer),
228            MagicCryptCipher::AES128(mc) => mc.decrypt_reader_to_writer2::<N>(reader, writer),
229            MagicCryptCipher::AES192(mc) => mc.decrypt_reader_to_writer2::<N>(reader, writer),
230            MagicCryptCipher::AES256(mc) => mc.decrypt_reader_to_writer2::<N>(reader, writer),
231        }
232    }
233}