├── .github ├── dependabot.yml └── workflows │ ├── ci-version.yml │ └── ci.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── rustfmt.toml ├── src ├── ciphers │ ├── aes128.rs │ ├── aes192.rs │ ├── aes256.rs │ ├── des64.rs │ └── mod.rs ├── errors.rs ├── functions.rs ├── lib.rs ├── macros.rs ├── secure_bit.rs └── traits.rs └── tests ├── basic.rs └── stream.rs /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" -------------------------------------------------------------------------------- /.github/workflows/ci-version.yml: -------------------------------------------------------------------------------- 1 | name: CI-version 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | env: 9 | CARGO_TERM_COLOR: always 10 | 11 | jobs: 12 | tests: 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | os: 17 | - ubuntu-latest 18 | - macos-latest 19 | - windows-latest 20 | toolchain: 21 | - stable 22 | - nightly 23 | features: 24 | - 25 | - --no-default-features 26 | name: Test ${{ matrix.toolchain }} on ${{ matrix.os }} (${{ matrix.features }}) 27 | runs-on: ${{ matrix.os }} 28 | steps: 29 | - uses: actions/checkout@v4 30 | - uses: actions-rust-lang/setup-rust-toolchain@v1 31 | with: 32 | toolchain: ${{ matrix.toolchain }} 33 | - run: cargo test --release ${{ matrix.features }} 34 | - run: cargo doc --release ${{ matrix.features }} 35 | 36 | MSRV: 37 | strategy: 38 | fail-fast: false 39 | matrix: 40 | os: 41 | - ubuntu-latest 42 | - macos-latest 43 | - windows-latest 44 | toolchain: 45 | - 1.65 46 | features: 47 | - 48 | - --no-default-features 49 | name: Test ${{ matrix.toolchain }} on ${{ matrix.os }} (${{ matrix.features }}) 50 | runs-on: ${{ matrix.os }} 51 | steps: 52 | - uses: actions/checkout@v4 53 | - uses: actions-rust-lang/setup-rust-toolchain@v1 54 | with: 55 | toolchain: ${{ matrix.toolchain }} 56 | - run: cargo test --release --lib --bins ${{ matrix.features }} -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [ push, pull_request ] 4 | 5 | env: 6 | CARGO_TERM_COLOR: always 7 | 8 | jobs: 9 | rustfmt: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - uses: actions-rust-lang/setup-rust-toolchain@v1 14 | with: 15 | toolchain: nightly 16 | components: rustfmt 17 | - uses: actions-rust-lang/rustfmt@v1 18 | 19 | clippy: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | - uses: actions-rust-lang/setup-rust-toolchain@v1 24 | with: 25 | components: clippy 26 | - run: cargo clippy --all-targets --all-features -- -D warnings 27 | 28 | tests: 29 | strategy: 30 | fail-fast: false 31 | matrix: 32 | os: 33 | - ubuntu-latest 34 | - macos-latest 35 | - windows-latest 36 | toolchain: 37 | - stable 38 | - nightly 39 | features: 40 | - 41 | - --no-default-features 42 | name: Test ${{ matrix.toolchain }} on ${{ matrix.os }} (${{ matrix.features }}) 43 | runs-on: ${{ matrix.os }} 44 | steps: 45 | - uses: actions/checkout@v4 46 | - uses: actions-rust-lang/setup-rust-toolchain@v1 47 | with: 48 | toolchain: ${{ matrix.toolchain }} 49 | - run: cargo test --lib --bins ${{ matrix.features }} 50 | 51 | MSRV: 52 | strategy: 53 | fail-fast: false 54 | matrix: 55 | os: 56 | - ubuntu-latest 57 | - macos-latest 58 | - windows-latest 59 | toolchain: 60 | - 1.65 61 | features: 62 | - 63 | - --no-default-features 64 | name: Test ${{ matrix.toolchain }} on ${{ matrix.os }} (${{ matrix.features }}) 65 | runs-on: ${{ matrix.os }} 66 | steps: 67 | - uses: actions/checkout@v4 68 | - uses: actions-rust-lang/setup-rust-toolchain@v1 69 | with: 70 | toolchain: ${{ matrix.toolchain }} 71 | - run: cargo test --lib --bins ${{ matrix.features }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Intellij+all ### 2 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 3 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 4 | 5 | # User-specific stuff 6 | .idea/**/workspace.xml 7 | .idea/**/tasks.xml 8 | .idea/**/usage.statistics.xml 9 | .idea/**/dictionaries 10 | .idea/**/shelf 11 | 12 | # AWS User-specific 13 | .idea/**/aws.xml 14 | 15 | # Generated files 16 | .idea/**/contentModel.xml 17 | 18 | # Sensitive or high-churn files 19 | .idea/**/dataSources/ 20 | .idea/**/dataSources.ids 21 | .idea/**/dataSources.local.xml 22 | .idea/**/sqlDataSources.xml 23 | .idea/**/dynamic.xml 24 | .idea/**/uiDesigner.xml 25 | .idea/**/dbnavigator.xml 26 | 27 | # Gradle 28 | .idea/**/gradle.xml 29 | .idea/**/libraries 30 | 31 | # Gradle and Maven with auto-import 32 | # When using Gradle or Maven with auto-import, you should exclude module files, 33 | # since they will be recreated, and may cause churn. Uncomment if using 34 | # auto-import. 35 | # .idea/artifacts 36 | # .idea/compiler.xml 37 | # .idea/jarRepositories.xml 38 | # .idea/modules.xml 39 | # .idea/*.iml 40 | # .idea/modules 41 | # *.iml 42 | # *.ipr 43 | 44 | # CMake 45 | cmake-build-*/ 46 | 47 | # Mongo Explorer plugin 48 | .idea/**/mongoSettings.xml 49 | 50 | # File-based project format 51 | *.iws 52 | 53 | # IntelliJ 54 | out/ 55 | 56 | # mpeltonen/sbt-idea plugin 57 | .idea_modules/ 58 | 59 | # JIRA plugin 60 | atlassian-ide-plugin.xml 61 | 62 | # Cursive Clojure plugin 63 | .idea/replstate.xml 64 | 65 | # SonarLint plugin 66 | .idea/sonarlint/ 67 | 68 | # Crashlytics plugin (for Android Studio and IntelliJ) 69 | com_crashlytics_export_strings.xml 70 | crashlytics.properties 71 | crashlytics-build.properties 72 | fabric.properties 73 | 74 | # Editor-based Rest Client 75 | .idea/httpRequests 76 | 77 | # Android studio 3.1+ serialized cache file 78 | .idea/caches/build_file_checksums.ser 79 | 80 | ### Intellij+all Patch ### 81 | # Ignore everything but code style settings and run configurations 82 | # that are supposed to be shared within teams. 83 | 84 | .idea/* 85 | 86 | !.idea/codeStyles 87 | !.idea/runConfigurations 88 | 89 | ### Rust ### 90 | # Generated by Cargo 91 | # will have compiled files and executables 92 | debug/ 93 | target/ 94 | 95 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 96 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 97 | Cargo.lock 98 | 99 | # These are backup files generated by rustfmt 100 | **/*.rs.bk 101 | 102 | # MSVC Windows builds of rustc generate these, which store debugging information 103 | *.pdb 104 | 105 | ### Vim ### 106 | # Swap 107 | [._]*.s[a-v][a-z] 108 | !*.svg # comment out if you don't need vector files 109 | [._]*.sw[a-p] 110 | [._]s[a-rt-v][a-z] 111 | [._]ss[a-gi-z] 112 | [._]sw[a-p] 113 | 114 | # Session 115 | Session.vim 116 | Sessionx.vim 117 | 118 | # Temporary 119 | .netrwhist 120 | *~ 121 | # Auto-generated tag files 122 | tags 123 | # Persistent undo 124 | [._]*.un~ 125 | 126 | ### VisualStudioCode ### 127 | .vscode/* 128 | !.vscode/settings.json 129 | !.vscode/tasks.json 130 | !.vscode/launch.json 131 | !.vscode/extensions.json 132 | !.vscode/*.code-snippets 133 | 134 | # Local History for Visual Studio Code 135 | .history/ 136 | 137 | # Built Visual Studio Code Extensions 138 | *.vsix 139 | 140 | ### VisualStudioCode Patch ### 141 | # Ignore all local history of files 142 | .history 143 | .ionide -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "magic-crypt" 3 | version = "4.0.1" 4 | authors = ["Magic Len "] 5 | edition = "2021" 6 | rust-version = "1.65" 7 | repository = "https://github.com/magiclen/rust-magiccrypt" 8 | homepage = "https://magiclen.org/aes" 9 | keywords = ["crypto", "aes", "des", "encrypt", "decrypt"] 10 | categories = ["no-std" ,"algorithms", "cryptography"] 11 | description = "MagicCrypt 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." 12 | license = "Apache-2.0" 13 | include = ["src/**/*", "Cargo.toml", "README.md", "LICENSE"] 14 | 15 | [dependencies] 16 | base64 = { version = "0.22", default-features = false, features = ["alloc"] } 17 | cbc = { version = "0.1", features = ["alloc"] } 18 | des = "0.8" 19 | aes = "0.8" 20 | md-5 = "0.10" 21 | tiger = "0.2" 22 | sha2 = "0.10" 23 | crc-any = "2.5" 24 | 25 | [features] 26 | default = ["std"] 27 | std = ["base64/std", "cbc/std"] 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015-2018 magiclen.org 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MagicCrypt 2 | ==================== 3 | 4 | [![CI](https://github.com/magiclen/rust-magiccrypt/actions/workflows/ci.yml/badge.svg)](https://github.com/magiclen/rust-magiccrypt/actions/workflows/ci.yml) 5 | 6 | MagicCrypt 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. 7 | 8 | ## For Rust 9 | 10 | ### Example 11 | 12 | ```rust 13 | use magic_crypt::{new_magic_crypt, MagicCryptTrait}; 14 | 15 | let mc = new_magic_crypt!("magickey", 256); 16 | 17 | let base64 = mc.encrypt_str_to_base64("http://magiclen.org"); 18 | 19 | assert_eq!("DS/2U8royDnJDiNY2ps3f6ZoTbpZo8ZtUGYLGEjwLDQ=", base64); 20 | 21 | assert_eq!("http://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap()); 22 | ``` 23 | 24 | ## Change the Buffer Size 25 | 26 | The 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. 27 | 28 | For example, to change the buffer size to 256 bytes, 29 | 30 | ```rust 31 | use std::io::Cursor; 32 | 33 | use base64::Engine; 34 | use magic_crypt::{new_magic_crypt, MagicCryptTrait}; 35 | use magic_crypt::generic_array::typenum::U256; 36 | 37 | let mc = new_magic_crypt!("magickey", 256); 38 | 39 | let mut reader = Cursor::new("http://magiclen.org"); 40 | let mut writer = Vec::new(); 41 | 42 | mc.encrypt_reader_to_writer2::(&mut reader, &mut writer).unwrap(); 43 | 44 | let base64 = base64::engine::general_purpose::STANDARD.encode(&writer); 45 | 46 | assert_eq!("DS/2U8royDnJDiNY2ps3f6ZoTbpZo8ZtUGYLGEjwLDQ=", base64); 47 | 48 | assert_eq!("http://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap()); 49 | ``` 50 | 51 | ## No Std 52 | 53 | Disable the default features to compile this crate without std. 54 | 55 | ```toml 56 | [dependencies.magic-crypt] 57 | version = "*" 58 | default-features = false 59 | ``` 60 | 61 | ### Crates.io 62 | 63 | https://crates.io/crates/magic-crypt 64 | 65 | ### Documentation 66 | 67 | https://docs.rs/magic-crypt 68 | 69 | ## For Java 70 | 71 | Refer to [https://github.com/magiclen/MagicCrypt](https://github.com/magiclen/MagicCrypt). 72 | 73 | ## For PHP 74 | 75 | Refer to [https://github.com/magiclen/MagicCrypt](https://github.com/magiclen/MagicCrypt). 76 | 77 | ## For NodeJS 78 | 79 | Refer to [https://github.com/magiclen/node-magiccrypt](https://github.com/magiclen/node-magiccrypt). 80 | 81 | ## License 82 | 83 | [Apache-2.0](LICENSE) 84 | 85 | ## What's More? 86 | 87 | Please check out our web page at 88 | 89 | https://magiclen.org/aes/ -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | # array_width = 60 2 | # attr_fn_like_width = 70 3 | binop_separator = "Front" 4 | blank_lines_lower_bound = 0 5 | blank_lines_upper_bound = 1 6 | brace_style = "PreferSameLine" 7 | # chain_width = 60 8 | color = "Auto" 9 | # comment_width = 100 10 | condense_wildcard_suffixes = true 11 | control_brace_style = "AlwaysSameLine" 12 | empty_item_single_line = true 13 | enum_discrim_align_threshold = 80 14 | error_on_line_overflow = false 15 | error_on_unformatted = false 16 | # fn_call_width = 60 17 | fn_params_layout = "Tall" 18 | fn_single_line = false 19 | force_explicit_abi = true 20 | force_multiline_blocks = false 21 | format_code_in_doc_comments = true 22 | doc_comment_code_block_width = 80 23 | format_generated_files = true 24 | format_macro_matchers = true 25 | format_macro_bodies = true 26 | skip_macro_invocations = [] 27 | format_strings = true 28 | hard_tabs = false 29 | hex_literal_case = "Upper" 30 | imports_indent = "Block" 31 | imports_layout = "Mixed" 32 | indent_style = "Block" 33 | inline_attribute_width = 0 34 | match_arm_blocks = true 35 | match_arm_leading_pipes = "Never" 36 | match_block_trailing_comma = true 37 | max_width = 100 38 | merge_derives = true 39 | imports_granularity = "Crate" 40 | newline_style = "Unix" 41 | normalize_comments = false 42 | normalize_doc_attributes = true 43 | overflow_delimited_expr = true 44 | remove_nested_parens = true 45 | reorder_impl_items = true 46 | reorder_imports = true 47 | group_imports = "StdExternalCrate" 48 | reorder_modules = true 49 | short_array_element_width_threshold = 10 50 | # single_line_if_else_max_width = 50 51 | space_after_colon = true 52 | space_before_colon = false 53 | spaces_around_ranges = false 54 | struct_field_align_threshold = 80 55 | struct_lit_single_line = false 56 | # struct_lit_width = 18 57 | # struct_variant_width = 35 58 | tab_spaces = 4 59 | trailing_comma = "Vertical" 60 | trailing_semicolon = true 61 | type_punctuation_density = "Wide" 62 | use_field_init_shorthand = true 63 | use_small_heuristics = "Max" 64 | use_try_shorthand = true 65 | where_single_line = false 66 | wrap_comments = false -------------------------------------------------------------------------------- /src/ciphers/aes128.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | #[cfg(feature = "std")] 3 | use std::intrinsics::copy; 4 | #[cfg(feature = "std")] 5 | use std::io::{ErrorKind, Read, Write}; 6 | #[cfg(feature = "std")] 7 | use std::ops::Add; 8 | 9 | #[cfg(feature = "std")] 10 | use aes::cipher::{ 11 | block_padding::RawPadding, 12 | generic_array::typenum::{IsGreaterOrEqual, PartialDiv, True, B1, U16}, 13 | ArrayLength, 14 | }; 15 | use aes::{ 16 | cipher::{ 17 | block_padding::Pkcs7, generic_array::GenericArray, BlockDecryptMut, BlockEncryptMut, Iv, 18 | Key, KeyIvInit, 19 | }, 20 | Aes128, 21 | }; 22 | use md5::{Digest, Md5}; 23 | 24 | #[cfg(feature = "std")] 25 | use crate::functions::to_blocks; 26 | use crate::{MagicCryptError, MagicCryptTrait}; 27 | 28 | type Aes128CbcEnc = cbc::Encryptor; 29 | type Aes128CbcDec = cbc::Decryptor; 30 | 31 | #[cfg(feature = "std")] 32 | const BLOCK_SIZE: usize = 16; 33 | 34 | /// This struct can help you encrypt or decrypt data via AES-128 in a quick way. 35 | #[derive(Debug, Clone)] 36 | pub struct MagicCrypt128 { 37 | key: Key, 38 | iv: Iv, 39 | } 40 | 41 | impl MagicCryptTrait for MagicCrypt128 { 42 | fn new, V: AsRef<[u8]>>(key: S, iv: Option) -> MagicCrypt128 { 43 | let iv = match iv { 44 | Some(s) => { 45 | let mut hasher = Md5::new(); 46 | hasher.update(s.as_ref()); 47 | 48 | hasher.finalize() 49 | }, 50 | None => GenericArray::default(), 51 | }; 52 | 53 | let key = { 54 | let mut hasher = Md5::new(); 55 | hasher.update(key.as_ref()); 56 | 57 | hasher.finalize() 58 | }; 59 | 60 | MagicCrypt128 { 61 | key, 62 | iv, 63 | } 64 | } 65 | 66 | #[inline] 67 | fn encrypt_to_bytes>(&self, data: &T) -> Vec { 68 | let data = data.as_ref(); 69 | 70 | let cipher = Aes128CbcEnc::new(&self.key, &self.iv); 71 | 72 | cipher.encrypt_padded_vec_mut::(data) 73 | } 74 | 75 | #[cfg(feature = "std")] 76 | fn encrypt_reader_to_bytes(&self, reader: &mut dyn Read) -> Result, MagicCryptError> { 77 | let mut final_result = Vec::new(); 78 | 79 | let data_length = reader.read_to_end(&mut final_result)?; 80 | 81 | let padding_length = BLOCK_SIZE - (data_length % BLOCK_SIZE); 82 | let final_length = data_length + padding_length; 83 | 84 | final_result.reserve_exact(padding_length); 85 | 86 | unsafe { 87 | final_result.set_len(final_length); 88 | } 89 | 90 | let cipher = Aes128CbcEnc::new(&self.key, &self.iv); 91 | 92 | cipher.encrypt_padded_mut::(&mut final_result, data_length).unwrap(); 93 | 94 | Ok(final_result) 95 | } 96 | 97 | #[cfg(feature = "std")] 98 | fn encrypt_reader_to_writer2< 99 | N: ArrayLength + PartialDiv + IsGreaterOrEqual, 100 | >( 101 | &self, 102 | reader: &mut dyn Read, 103 | writer: &mut dyn Write, 104 | ) -> Result<(), MagicCryptError> { 105 | let mut buffer: GenericArray = GenericArray::default(); 106 | 107 | let mut cipher = Aes128CbcEnc::new(&self.key, &self.iv); 108 | 109 | let mut l = 0; 110 | 111 | loop { 112 | match reader.read(&mut buffer[l..]) { 113 | Ok(c) => { 114 | if c == 0 { 115 | break; 116 | } 117 | 118 | l += c; 119 | 120 | if l < BLOCK_SIZE { 121 | continue; 122 | } 123 | 124 | let r = l % BLOCK_SIZE; 125 | let e = l - r; 126 | 127 | cipher.encrypt_blocks_mut(to_blocks(&mut buffer[..e])); 128 | 129 | writer.write_all(&buffer[..e])?; 130 | 131 | unsafe { 132 | copy(buffer.as_ptr().add(e), buffer.as_mut_ptr(), r); 133 | } 134 | 135 | l = r; 136 | }, 137 | Err(error) if error.kind() == ErrorKind::Interrupted => {}, 138 | Err(error) => return Err(MagicCryptError::IOError(error)), 139 | } 140 | } 141 | 142 | let raw_block = &mut buffer[..BLOCK_SIZE]; 143 | 144 | Pkcs7::raw_pad(raw_block, l); 145 | cipher.encrypt_blocks_mut(to_blocks(raw_block)); 146 | 147 | writer.write_all(raw_block)?; 148 | 149 | Ok(writer.flush()?) 150 | } 151 | 152 | #[inline] 153 | fn decrypt_bytes_to_bytes>( 154 | &self, 155 | bytes: &T, 156 | ) -> Result, MagicCryptError> { 157 | let bytes = bytes.as_ref(); 158 | 159 | let cipher = Aes128CbcDec::new(&self.key, &self.iv); 160 | 161 | let final_result = cipher.decrypt_padded_vec_mut::(bytes)?; 162 | 163 | Ok(final_result) 164 | } 165 | 166 | #[cfg(feature = "std")] 167 | fn decrypt_reader_to_bytes(&self, reader: &mut dyn Read) -> Result, MagicCryptError> { 168 | let mut final_result = Vec::new(); 169 | 170 | reader.read_to_end(&mut final_result)?; 171 | 172 | let cipher = Aes128CbcDec::new(&self.key, &self.iv); 173 | 174 | let data_length = cipher.decrypt_padded_mut::(&mut final_result)?.len(); 175 | 176 | final_result.truncate(data_length); 177 | 178 | Ok(final_result) 179 | } 180 | 181 | #[cfg(feature = "std")] 182 | #[allow(clippy::many_single_char_names)] 183 | fn decrypt_reader_to_writer2< 184 | N: ArrayLength + PartialDiv + IsGreaterOrEqual + Add, 185 | >( 186 | &self, 187 | reader: &mut dyn Read, 188 | writer: &mut dyn Write, 189 | ) -> Result<(), MagicCryptError> 190 | where 191 | >::Output: ArrayLength, { 192 | let mut buffer: GenericArray = GenericArray::default(); 193 | 194 | let mut cipher = Aes128CbcDec::new(&self.key, &self.iv); 195 | let mut l = 0; 196 | 197 | loop { 198 | match reader.read(&mut buffer[l..]) { 199 | Ok(c) => { 200 | if c == 0 { 201 | break; 202 | } 203 | 204 | l += c; 205 | 206 | if l < BLOCK_SIZE { 207 | continue; 208 | } 209 | 210 | let r = l % BLOCK_SIZE; 211 | let e = if r > 0 { l + BLOCK_SIZE - r } else { l }; 212 | 213 | // fill the last block 214 | reader.read_exact(&mut buffer[l..e])?; 215 | 216 | match reader.read_exact(&mut buffer[e..(e + 1)]) { 217 | Ok(()) => { 218 | cipher.decrypt_blocks_mut(to_blocks(&mut buffer[..e])); 219 | 220 | writer.write_all(&buffer[..e])?; 221 | 222 | buffer[0] = buffer[e]; 223 | 224 | l = 1; 225 | }, 226 | Err(error) if error.kind() == ErrorKind::UnexpectedEof => { 227 | cipher.decrypt_blocks_mut(to_blocks(&mut buffer[..e])); 228 | 229 | writer.write_all(Pkcs7::raw_unpad(&buffer[..e])?)?; 230 | 231 | break; 232 | }, 233 | Err(error) => return Err(MagicCryptError::IOError(error)), 234 | } 235 | }, 236 | Err(error) if error.kind() == ErrorKind::Interrupted => {}, 237 | Err(error) => return Err(MagicCryptError::IOError(error)), 238 | } 239 | } 240 | 241 | Ok(writer.flush()?) 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /src/ciphers/aes192.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | #[cfg(feature = "std")] 3 | use std::intrinsics::copy; 4 | #[cfg(feature = "std")] 5 | use std::io::{ErrorKind, Read, Write}; 6 | #[cfg(feature = "std")] 7 | use std::ops::Add; 8 | 9 | #[cfg(feature = "std")] 10 | use aes::cipher::{ 11 | block_padding::RawPadding, 12 | generic_array::typenum::{IsGreaterOrEqual, PartialDiv, True, B1, U16}, 13 | ArrayLength, 14 | }; 15 | use aes::{ 16 | cipher::{ 17 | block_padding::Pkcs7, generic_array::GenericArray, BlockDecryptMut, BlockEncryptMut, Iv, 18 | Key, KeyIvInit, 19 | }, 20 | Aes192, 21 | }; 22 | use md5::{Digest, Md5}; 23 | use tiger::Tiger; 24 | 25 | #[cfg(feature = "std")] 26 | use crate::functions::to_blocks; 27 | use crate::{MagicCryptError, MagicCryptTrait}; 28 | 29 | type Aes192CbcEnc = cbc::Encryptor; 30 | type Aes192CbcDec = cbc::Decryptor; 31 | 32 | #[cfg(feature = "std")] 33 | const BLOCK_SIZE: usize = 16; 34 | 35 | /// This struct can help you encrypt or decrypt data via AES-192 in a quick way. 36 | #[derive(Debug, Clone)] 37 | pub struct MagicCrypt192 { 38 | key: Key, 39 | iv: Iv, 40 | } 41 | 42 | impl MagicCryptTrait for MagicCrypt192 { 43 | fn new, V: AsRef<[u8]>>(key: S, iv: Option) -> MagicCrypt192 { 44 | let iv = match iv { 45 | Some(s) => { 46 | let mut hasher = Md5::new(); 47 | hasher.update(s.as_ref()); 48 | 49 | hasher.finalize() 50 | }, 51 | None => GenericArray::default(), 52 | }; 53 | 54 | let key = { 55 | let mut hasher = Tiger::default(); 56 | hasher.update(key.as_ref()); 57 | 58 | hasher.finalize() 59 | }; 60 | 61 | MagicCrypt192 { 62 | key, 63 | iv, 64 | } 65 | } 66 | 67 | #[inline] 68 | fn encrypt_to_bytes>(&self, data: &T) -> Vec { 69 | let data = data.as_ref(); 70 | 71 | let cipher = Aes192CbcEnc::new(&self.key, &self.iv); 72 | 73 | cipher.encrypt_padded_vec_mut::(data) 74 | } 75 | 76 | #[cfg(feature = "std")] 77 | fn encrypt_reader_to_bytes(&self, reader: &mut dyn Read) -> Result, MagicCryptError> { 78 | let mut final_result = Vec::new(); 79 | 80 | let data_length = reader.read_to_end(&mut final_result)?; 81 | 82 | let padding_length = BLOCK_SIZE - (data_length % BLOCK_SIZE); 83 | let final_length = data_length + padding_length; 84 | 85 | final_result.reserve_exact(padding_length); 86 | 87 | unsafe { 88 | final_result.set_len(final_length); 89 | } 90 | 91 | let cipher = Aes192CbcEnc::new(&self.key, &self.iv); 92 | 93 | cipher.encrypt_padded_mut::(&mut final_result, data_length).unwrap(); 94 | 95 | Ok(final_result) 96 | } 97 | 98 | #[cfg(feature = "std")] 99 | fn encrypt_reader_to_writer2< 100 | N: ArrayLength + PartialDiv + IsGreaterOrEqual, 101 | >( 102 | &self, 103 | reader: &mut dyn Read, 104 | writer: &mut dyn Write, 105 | ) -> Result<(), MagicCryptError> { 106 | let mut buffer: GenericArray = GenericArray::default(); 107 | 108 | let mut cipher = Aes192CbcEnc::new(&self.key, &self.iv); 109 | 110 | let mut l = 0; 111 | 112 | loop { 113 | match reader.read(&mut buffer[l..]) { 114 | Ok(c) => { 115 | if c == 0 { 116 | break; 117 | } 118 | 119 | l += c; 120 | 121 | if l < BLOCK_SIZE { 122 | continue; 123 | } 124 | 125 | let r = l % BLOCK_SIZE; 126 | let e = l - r; 127 | 128 | cipher.encrypt_blocks_mut(to_blocks(&mut buffer[..e])); 129 | 130 | writer.write_all(&buffer[..e])?; 131 | 132 | unsafe { 133 | copy(buffer.as_ptr().add(e), buffer.as_mut_ptr(), r); 134 | } 135 | 136 | l = r; 137 | }, 138 | Err(error) if error.kind() == ErrorKind::Interrupted => {}, 139 | Err(error) => return Err(MagicCryptError::IOError(error)), 140 | } 141 | } 142 | 143 | let raw_block = &mut buffer[..BLOCK_SIZE]; 144 | 145 | Pkcs7::raw_pad(raw_block, l); 146 | cipher.encrypt_blocks_mut(to_blocks(raw_block)); 147 | 148 | writer.write_all(raw_block)?; 149 | 150 | Ok(writer.flush()?) 151 | } 152 | 153 | #[inline] 154 | fn decrypt_bytes_to_bytes>( 155 | &self, 156 | bytes: &T, 157 | ) -> Result, MagicCryptError> { 158 | let bytes = bytes.as_ref(); 159 | 160 | let cipher = Aes192CbcDec::new(&self.key, &self.iv); 161 | 162 | let final_result = cipher.decrypt_padded_vec_mut::(bytes)?; 163 | 164 | Ok(final_result) 165 | } 166 | 167 | #[cfg(feature = "std")] 168 | fn decrypt_reader_to_bytes(&self, reader: &mut dyn Read) -> Result, MagicCryptError> { 169 | let mut final_result = Vec::new(); 170 | 171 | reader.read_to_end(&mut final_result)?; 172 | 173 | let cipher = Aes192CbcDec::new(&self.key, &self.iv); 174 | 175 | let data_length = cipher.decrypt_padded_mut::(&mut final_result)?.len(); 176 | 177 | final_result.truncate(data_length); 178 | 179 | Ok(final_result) 180 | } 181 | 182 | #[cfg(feature = "std")] 183 | #[allow(clippy::many_single_char_names)] 184 | fn decrypt_reader_to_writer2< 185 | N: ArrayLength + PartialDiv + IsGreaterOrEqual + Add, 186 | >( 187 | &self, 188 | reader: &mut dyn Read, 189 | writer: &mut dyn Write, 190 | ) -> Result<(), MagicCryptError> 191 | where 192 | >::Output: ArrayLength, { 193 | let mut buffer: GenericArray = GenericArray::default(); 194 | 195 | let mut cipher = Aes192CbcDec::new(&self.key, &self.iv); 196 | let mut l = 0; 197 | 198 | loop { 199 | match reader.read(&mut buffer[l..]) { 200 | Ok(c) => { 201 | if c == 0 { 202 | break; 203 | } 204 | 205 | l += c; 206 | 207 | if l < BLOCK_SIZE { 208 | continue; 209 | } 210 | 211 | let r = l % BLOCK_SIZE; 212 | let e = if r > 0 { l + BLOCK_SIZE - r } else { l }; 213 | 214 | // fill the last block 215 | reader.read_exact(&mut buffer[l..e])?; 216 | 217 | match reader.read_exact(&mut buffer[e..(e + 1)]) { 218 | Ok(()) => { 219 | cipher.decrypt_blocks_mut(to_blocks(&mut buffer[..e])); 220 | 221 | writer.write_all(&buffer[..e])?; 222 | 223 | buffer[0] = buffer[e]; 224 | 225 | l = 1; 226 | }, 227 | Err(error) if error.kind() == ErrorKind::UnexpectedEof => { 228 | cipher.decrypt_blocks_mut(to_blocks(&mut buffer[..e])); 229 | 230 | writer.write_all(Pkcs7::raw_unpad(&buffer[..e])?)?; 231 | 232 | break; 233 | }, 234 | Err(error) => return Err(MagicCryptError::IOError(error)), 235 | } 236 | }, 237 | Err(error) if error.kind() == ErrorKind::Interrupted => {}, 238 | Err(error) => return Err(MagicCryptError::IOError(error)), 239 | } 240 | } 241 | 242 | Ok(writer.flush()?) 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/ciphers/aes256.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | #[cfg(feature = "std")] 3 | use std::intrinsics::copy; 4 | #[cfg(feature = "std")] 5 | use std::io::{ErrorKind, Read, Write}; 6 | #[cfg(feature = "std")] 7 | use std::ops::Add; 8 | 9 | #[cfg(feature = "std")] 10 | use aes::cipher::{ 11 | block_padding::RawPadding, 12 | generic_array::typenum::{IsGreaterOrEqual, PartialDiv, True, B1, U16}, 13 | ArrayLength, 14 | }; 15 | use aes::{ 16 | cipher::{ 17 | block_padding::Pkcs7, generic_array::GenericArray, BlockDecryptMut, BlockEncryptMut, Iv, 18 | Key, KeyIvInit, 19 | }, 20 | Aes256, 21 | }; 22 | use md5::{Digest, Md5}; 23 | use sha2::Sha256; 24 | 25 | #[cfg(feature = "std")] 26 | use crate::functions::to_blocks; 27 | use crate::{MagicCryptError, MagicCryptTrait}; 28 | 29 | type Aes256CbcEnc = cbc::Encryptor; 30 | type Aes256CbcDec = cbc::Decryptor; 31 | 32 | #[cfg(feature = "std")] 33 | const BLOCK_SIZE: usize = 16; 34 | 35 | /// This struct can help you encrypt or decrypt data via AES-256 in a quick way. 36 | #[derive(Debug, Clone)] 37 | pub struct MagicCrypt256 { 38 | key: Key, 39 | iv: Iv, 40 | } 41 | 42 | impl MagicCryptTrait for MagicCrypt256 { 43 | fn new, V: AsRef<[u8]>>(key: S, iv: Option) -> MagicCrypt256 { 44 | let iv = match iv { 45 | Some(s) => { 46 | let mut hasher = Md5::new(); 47 | hasher.update(s.as_ref()); 48 | 49 | hasher.finalize() 50 | }, 51 | None => GenericArray::default(), 52 | }; 53 | 54 | let key = { 55 | let mut hasher = Sha256::new(); 56 | hasher.update(key.as_ref()); 57 | 58 | hasher.finalize() 59 | }; 60 | 61 | MagicCrypt256 { 62 | key, 63 | iv, 64 | } 65 | } 66 | 67 | #[inline] 68 | fn encrypt_to_bytes>(&self, data: &T) -> Vec { 69 | let data = data.as_ref(); 70 | 71 | let cipher = Aes256CbcEnc::new(&self.key, &self.iv); 72 | 73 | cipher.encrypt_padded_vec_mut::(data) 74 | } 75 | 76 | #[cfg(feature = "std")] 77 | fn encrypt_reader_to_bytes(&self, reader: &mut dyn Read) -> Result, MagicCryptError> { 78 | let mut final_result = Vec::new(); 79 | 80 | let data_length = reader.read_to_end(&mut final_result)?; 81 | 82 | let padding_length = BLOCK_SIZE - (data_length % BLOCK_SIZE); 83 | let final_length = data_length + padding_length; 84 | 85 | final_result.reserve_exact(padding_length); 86 | 87 | unsafe { 88 | final_result.set_len(final_length); 89 | } 90 | 91 | let cipher = Aes256CbcEnc::new(&self.key, &self.iv); 92 | 93 | cipher.encrypt_padded_mut::(&mut final_result, data_length).unwrap(); 94 | 95 | Ok(final_result) 96 | } 97 | 98 | #[cfg(feature = "std")] 99 | fn encrypt_reader_to_writer2< 100 | N: ArrayLength + PartialDiv + IsGreaterOrEqual, 101 | >( 102 | &self, 103 | reader: &mut dyn Read, 104 | writer: &mut dyn Write, 105 | ) -> Result<(), MagicCryptError> { 106 | let mut buffer: GenericArray = GenericArray::default(); 107 | 108 | let mut cipher = Aes256CbcEnc::new(&self.key, &self.iv); 109 | 110 | let mut l = 0; 111 | 112 | loop { 113 | match reader.read(&mut buffer[l..]) { 114 | Ok(c) => { 115 | if c == 0 { 116 | break; 117 | } 118 | 119 | l += c; 120 | 121 | if l < BLOCK_SIZE { 122 | continue; 123 | } 124 | 125 | let r = l % BLOCK_SIZE; 126 | let e = l - r; 127 | 128 | cipher.encrypt_blocks_mut(to_blocks(&mut buffer[..e])); 129 | 130 | writer.write_all(&buffer[..e])?; 131 | 132 | unsafe { 133 | copy(buffer.as_ptr().add(e), buffer.as_mut_ptr(), r); 134 | } 135 | 136 | l = r; 137 | }, 138 | Err(error) if error.kind() == ErrorKind::Interrupted => {}, 139 | Err(error) => return Err(MagicCryptError::IOError(error)), 140 | } 141 | } 142 | 143 | let raw_block = &mut buffer[..BLOCK_SIZE]; 144 | 145 | Pkcs7::raw_pad(raw_block, l); 146 | cipher.encrypt_blocks_mut(to_blocks(raw_block)); 147 | 148 | writer.write_all(raw_block)?; 149 | 150 | Ok(writer.flush()?) 151 | } 152 | 153 | #[inline] 154 | fn decrypt_bytes_to_bytes>( 155 | &self, 156 | bytes: &T, 157 | ) -> Result, MagicCryptError> { 158 | let bytes = bytes.as_ref(); 159 | 160 | let cipher = Aes256CbcDec::new(&self.key, &self.iv); 161 | 162 | let final_result = cipher.decrypt_padded_vec_mut::(bytes)?; 163 | 164 | Ok(final_result) 165 | } 166 | 167 | #[cfg(feature = "std")] 168 | fn decrypt_reader_to_bytes(&self, reader: &mut dyn Read) -> Result, MagicCryptError> { 169 | let mut final_result = Vec::new(); 170 | 171 | reader.read_to_end(&mut final_result)?; 172 | 173 | let cipher = Aes256CbcDec::new(&self.key, &self.iv); 174 | 175 | let data_length = cipher.decrypt_padded_mut::(&mut final_result)?.len(); 176 | 177 | final_result.truncate(data_length); 178 | 179 | Ok(final_result) 180 | } 181 | 182 | #[cfg(feature = "std")] 183 | #[allow(clippy::many_single_char_names)] 184 | fn decrypt_reader_to_writer2< 185 | N: ArrayLength + PartialDiv + IsGreaterOrEqual + Add, 186 | >( 187 | &self, 188 | reader: &mut dyn Read, 189 | writer: &mut dyn Write, 190 | ) -> Result<(), MagicCryptError> 191 | where 192 | >::Output: ArrayLength, { 193 | let mut buffer: GenericArray = GenericArray::default(); 194 | 195 | let mut cipher = Aes256CbcDec::new(&self.key, &self.iv); 196 | let mut l = 0; 197 | 198 | loop { 199 | match reader.read(&mut buffer[l..]) { 200 | Ok(c) => { 201 | if c == 0 { 202 | break; 203 | } 204 | 205 | l += c; 206 | 207 | if l < BLOCK_SIZE { 208 | continue; 209 | } 210 | 211 | let r = l % BLOCK_SIZE; 212 | let e = if r > 0 { l + BLOCK_SIZE - r } else { l }; 213 | 214 | // fill the last block 215 | reader.read_exact(&mut buffer[l..e])?; 216 | 217 | match reader.read_exact(&mut buffer[e..(e + 1)]) { 218 | Ok(()) => { 219 | cipher.decrypt_blocks_mut(to_blocks(&mut buffer[..e])); 220 | 221 | writer.write_all(&buffer[..e])?; 222 | 223 | buffer[0] = buffer[e]; 224 | 225 | l = 1; 226 | }, 227 | Err(error) if error.kind() == ErrorKind::UnexpectedEof => { 228 | cipher.decrypt_blocks_mut(to_blocks(&mut buffer[..e])); 229 | 230 | writer.write_all(Pkcs7::raw_unpad(&buffer[..e])?)?; 231 | 232 | break; 233 | }, 234 | Err(error) => return Err(MagicCryptError::IOError(error)), 235 | } 236 | }, 237 | Err(error) if error.kind() == ErrorKind::Interrupted => {}, 238 | Err(error) => return Err(MagicCryptError::IOError(error)), 239 | } 240 | } 241 | 242 | Ok(writer.flush()?) 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/ciphers/des64.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | #[cfg(feature = "std")] 3 | use std::intrinsics::copy; 4 | #[cfg(feature = "std")] 5 | use std::io::{ErrorKind, Read, Write}; 6 | #[cfg(feature = "std")] 7 | use std::ops::Add; 8 | 9 | #[cfg(feature = "std")] 10 | use aes::cipher::{ 11 | block_padding::RawPadding, 12 | generic_array::typenum::{IsGreaterOrEqual, PartialDiv, True, B1, U16}, 13 | ArrayLength, 14 | }; 15 | use crc_any::CRCu64; 16 | use des::{ 17 | cipher::{ 18 | block_padding::Pkcs7, generic_array::GenericArray, BlockDecryptMut, BlockEncryptMut, Iv, 19 | Key, KeyIvInit, 20 | }, 21 | Des, 22 | }; 23 | 24 | #[cfg(feature = "std")] 25 | use crate::functions::to_blocks; 26 | use crate::{MagicCryptError, MagicCryptTrait}; 27 | 28 | type Des64CbcEnc = cbc::Encryptor; 29 | type Des64CbcDec = cbc::Decryptor; 30 | 31 | #[cfg(feature = "std")] 32 | const BLOCK_SIZE: usize = 8; 33 | 34 | /// This struct can help you encrypt or decrypt data via AES-64 in a quick way. 35 | #[derive(Debug, Clone)] 36 | pub struct MagicCrypt64 { 37 | key: Key, 38 | iv: Iv, 39 | } 40 | 41 | impl MagicCryptTrait for MagicCrypt64 { 42 | fn new, V: AsRef<[u8]>>(key: S, iv: Option) -> MagicCrypt64 { 43 | let iv = match iv { 44 | Some(s) => { 45 | let mut hasher = CRCu64::crc64we(); 46 | hasher.digest(s.as_ref()); 47 | 48 | GenericArray::clone_from_slice(&hasher.get_crc_vec_be()) 49 | }, 50 | None => GenericArray::default(), 51 | }; 52 | 53 | let key = { 54 | let mut hasher = CRCu64::crc64we(); 55 | hasher.digest(key.as_ref()); 56 | 57 | GenericArray::clone_from_slice(&hasher.get_crc_vec_be()) 58 | }; 59 | 60 | MagicCrypt64 { 61 | key, 62 | iv, 63 | } 64 | } 65 | 66 | #[inline] 67 | fn encrypt_to_bytes>(&self, data: &T) -> Vec { 68 | let data = data.as_ref(); 69 | 70 | let cipher = Des64CbcEnc::new(&self.key, &self.iv); 71 | 72 | cipher.encrypt_padded_vec_mut::(data) 73 | } 74 | 75 | #[cfg(feature = "std")] 76 | fn encrypt_reader_to_bytes(&self, reader: &mut dyn Read) -> Result, MagicCryptError> { 77 | let mut final_result = Vec::new(); 78 | 79 | let data_length = reader.read_to_end(&mut final_result)?; 80 | 81 | let padding_length = BLOCK_SIZE - (data_length % BLOCK_SIZE); 82 | let final_length = data_length + padding_length; 83 | 84 | final_result.reserve_exact(padding_length); 85 | 86 | unsafe { 87 | final_result.set_len(final_length); 88 | } 89 | 90 | let cipher = Des64CbcEnc::new(&self.key, &self.iv); 91 | 92 | cipher.encrypt_padded_mut::(&mut final_result, data_length).unwrap(); 93 | 94 | Ok(final_result) 95 | } 96 | 97 | #[cfg(feature = "std")] 98 | fn encrypt_reader_to_writer2< 99 | N: ArrayLength + PartialDiv + IsGreaterOrEqual, 100 | >( 101 | &self, 102 | reader: &mut dyn Read, 103 | writer: &mut dyn Write, 104 | ) -> Result<(), MagicCryptError> { 105 | let mut buffer: GenericArray = GenericArray::default(); 106 | 107 | let mut cipher = Des64CbcEnc::new(&self.key, &self.iv); 108 | 109 | let mut l = 0; 110 | 111 | loop { 112 | match reader.read(&mut buffer[l..]) { 113 | Ok(c) => { 114 | if c == 0 { 115 | break; 116 | } 117 | 118 | l += c; 119 | 120 | if l < BLOCK_SIZE { 121 | continue; 122 | } 123 | 124 | let r = l % BLOCK_SIZE; 125 | let e = l - r; 126 | 127 | cipher.encrypt_blocks_mut(to_blocks(&mut buffer[..e])); 128 | 129 | writer.write_all(&buffer[..e])?; 130 | 131 | unsafe { 132 | copy(buffer.as_ptr().add(e), buffer.as_mut_ptr(), r); 133 | } 134 | 135 | l = r; 136 | }, 137 | Err(error) if error.kind() == ErrorKind::Interrupted => {}, 138 | Err(error) => return Err(MagicCryptError::IOError(error)), 139 | } 140 | } 141 | 142 | let raw_block = &mut buffer[..BLOCK_SIZE]; 143 | 144 | Pkcs7::raw_pad(raw_block, l); 145 | cipher.encrypt_blocks_mut(to_blocks(raw_block)); 146 | 147 | writer.write_all(raw_block)?; 148 | 149 | Ok(writer.flush()?) 150 | } 151 | 152 | #[inline] 153 | fn decrypt_bytes_to_bytes>( 154 | &self, 155 | bytes: &T, 156 | ) -> Result, MagicCryptError> { 157 | let bytes = bytes.as_ref(); 158 | 159 | let cipher = Des64CbcDec::new(&self.key, &self.iv); 160 | 161 | let final_result = cipher.decrypt_padded_vec_mut::(bytes)?; 162 | 163 | Ok(final_result) 164 | } 165 | 166 | #[cfg(feature = "std")] 167 | fn decrypt_reader_to_bytes(&self, reader: &mut dyn Read) -> Result, MagicCryptError> { 168 | let mut final_result = Vec::new(); 169 | 170 | reader.read_to_end(&mut final_result)?; 171 | 172 | let cipher = Des64CbcDec::new(&self.key, &self.iv); 173 | 174 | let data_length = cipher.decrypt_padded_mut::(&mut final_result)?.len(); 175 | 176 | final_result.truncate(data_length); 177 | 178 | Ok(final_result) 179 | } 180 | 181 | #[cfg(feature = "std")] 182 | #[allow(clippy::many_single_char_names)] 183 | fn decrypt_reader_to_writer2< 184 | N: ArrayLength + PartialDiv + IsGreaterOrEqual + Add, 185 | >( 186 | &self, 187 | reader: &mut dyn Read, 188 | writer: &mut dyn Write, 189 | ) -> Result<(), MagicCryptError> 190 | where 191 | >::Output: ArrayLength, { 192 | let mut buffer: GenericArray = GenericArray::default(); 193 | 194 | let mut cipher = Des64CbcDec::new(&self.key, &self.iv); 195 | let mut l = 0; 196 | 197 | loop { 198 | match reader.read(&mut buffer[l..]) { 199 | Ok(c) => { 200 | if c == 0 { 201 | break; 202 | } 203 | 204 | l += c; 205 | 206 | if l < BLOCK_SIZE { 207 | continue; 208 | } 209 | 210 | let r = l % BLOCK_SIZE; 211 | let e = if r > 0 { l + BLOCK_SIZE - r } else { l }; 212 | 213 | // fill the last block 214 | reader.read_exact(&mut buffer[l..e])?; 215 | 216 | match reader.read_exact(&mut buffer[e..(e + 1)]) { 217 | Ok(()) => { 218 | cipher.decrypt_blocks_mut(to_blocks(&mut buffer[..e])); 219 | 220 | writer.write_all(&buffer[..e])?; 221 | 222 | buffer[0] = buffer[e]; 223 | 224 | l = 1; 225 | }, 226 | Err(error) if error.kind() == ErrorKind::UnexpectedEof => { 227 | cipher.decrypt_blocks_mut(to_blocks(&mut buffer[..e])); 228 | 229 | writer.write_all(Pkcs7::raw_unpad(&buffer[..e])?)?; 230 | 231 | break; 232 | }, 233 | Err(error) => return Err(MagicCryptError::IOError(error)), 234 | } 235 | }, 236 | Err(error) if error.kind() == ErrorKind::Interrupted => {}, 237 | Err(error) => return Err(MagicCryptError::IOError(error)), 238 | } 239 | } 240 | 241 | Ok(writer.flush()?) 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /src/ciphers/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod aes128; 2 | pub mod aes192; 3 | pub mod aes256; 4 | pub mod des64; 5 | -------------------------------------------------------------------------------- /src/errors.rs: -------------------------------------------------------------------------------- 1 | use alloc::string::FromUtf8Error; 2 | use core::fmt::{self, Display, Formatter}; 3 | #[cfg(feature = "std")] 4 | use std::error::Error; 5 | #[cfg(feature = "std")] 6 | use std::io::Error as IOError; 7 | 8 | use base64::DecodeError; 9 | use cbc::cipher::block_padding::UnpadError; 10 | 11 | /// Errors for MagicCrypt. 12 | #[derive(Debug)] 13 | pub enum MagicCryptError { 14 | #[cfg(feature = "std")] 15 | IOError(IOError), 16 | Base64Error(DecodeError), 17 | StringError(FromUtf8Error), 18 | DecryptError(UnpadError), 19 | } 20 | 21 | #[cfg(feature = "std")] 22 | impl From for MagicCryptError { 23 | #[inline] 24 | fn from(error: IOError) -> MagicCryptError { 25 | MagicCryptError::IOError(error) 26 | } 27 | } 28 | 29 | impl From for MagicCryptError { 30 | #[inline] 31 | fn from(error: DecodeError) -> MagicCryptError { 32 | MagicCryptError::Base64Error(error) 33 | } 34 | } 35 | 36 | impl From for MagicCryptError { 37 | #[inline] 38 | fn from(error: FromUtf8Error) -> MagicCryptError { 39 | MagicCryptError::StringError(error) 40 | } 41 | } 42 | 43 | impl From for MagicCryptError { 44 | #[inline] 45 | fn from(error: UnpadError) -> MagicCryptError { 46 | MagicCryptError::DecryptError(error) 47 | } 48 | } 49 | 50 | impl Display for MagicCryptError { 51 | #[inline] 52 | fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { 53 | match self { 54 | #[cfg(feature = "std")] 55 | MagicCryptError::IOError(err) => Display::fmt(err, f), 56 | MagicCryptError::Base64Error(err) => Display::fmt(err, f), 57 | MagicCryptError::StringError(err) => Display::fmt(err, f), 58 | MagicCryptError::DecryptError(err) => Display::fmt(err, f), 59 | } 60 | } 61 | } 62 | 63 | #[cfg(feature = "std")] 64 | impl Error for MagicCryptError {} 65 | -------------------------------------------------------------------------------- /src/functions.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "std")] 2 | use cbc::cipher::{generic_array::GenericArray, ArrayLength}; 3 | 4 | #[cfg(feature = "std")] 5 | #[inline] 6 | pub(crate) fn to_blocks(data: &mut [u8]) -> &mut [GenericArray] 7 | where 8 | N: ArrayLength, { 9 | let n = N::USIZE; 10 | 11 | unsafe { 12 | core::slice::from_raw_parts_mut(data.as_ptr() as *mut GenericArray, data.len() / n) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | # MagicCrypt 3 | 4 | MagicCrypt 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 | ## For Rust 7 | 8 | ### Example 9 | 10 | ```rust 11 | use magic_crypt::{new_magic_crypt, MagicCryptTrait}; 12 | 13 | let mc = new_magic_crypt!("magickey", 256); 14 | 15 | let base64 = mc.encrypt_str_to_base64("http://magiclen.org"); 16 | 17 | assert_eq!("DS/2U8royDnJDiNY2ps3f6ZoTbpZo8ZtUGYLGEjwLDQ=", base64); 18 | 19 | assert_eq!("http://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap()); 20 | ``` 21 | 22 | ## Change the Buffer Size 23 | 24 | The 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. 25 | 26 | For example, to change the buffer size to 256 bytes, 27 | 28 | ```rust 29 | use std::io::Cursor; 30 | 31 | use base64::Engine; 32 | use magic_crypt::{new_magic_crypt, MagicCryptTrait}; 33 | use magic_crypt::generic_array::typenum::U256; 34 | 35 | let mc = new_magic_crypt!("magickey", 256); 36 | 37 | # #[cfg(feature = "std")] { 38 | let mut reader = Cursor::new("http://magiclen.org"); 39 | let mut writer = Vec::new(); 40 | 41 | mc.encrypt_reader_to_writer2::(&mut reader, &mut writer).unwrap(); 42 | 43 | let base64 = base64::engine::general_purpose::STANDARD.encode(&writer); 44 | 45 | assert_eq!("DS/2U8royDnJDiNY2ps3f6ZoTbpZo8ZtUGYLGEjwLDQ=", base64); 46 | 47 | assert_eq!("http://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap()); 48 | # } 49 | ``` 50 | 51 | ## No Std 52 | 53 | Disable the default features to compile this crate without std. 54 | 55 | ```toml 56 | [dependencies.magic-crypt] 57 | version = "*" 58 | default-features = false 59 | ``` 60 | 61 | ## For Java 62 | 63 | Refer to https://github.com/magiclen/MagicCrypt. 64 | 65 | ## For PHP 66 | 67 | Refer to https://github.com/magiclen/MagicCrypt. 68 | 69 | ## For NodeJS 70 | 71 | Refer to https://github.com/magiclen/node-magiccrypt 72 | */ 73 | 74 | #![cfg_attr(not(feature = "std"), no_std)] 75 | 76 | extern crate alloc; 77 | 78 | mod ciphers; 79 | mod errors; 80 | mod functions; 81 | mod macros; 82 | mod secure_bit; 83 | mod traits; 84 | 85 | use alloc::vec::Vec; 86 | #[cfg(feature = "std")] 87 | use std::io::{Read, Write}; 88 | #[cfg(feature = "std")] 89 | use std::ops::Add; 90 | 91 | pub use cbc::cipher::generic_array; 92 | pub use ciphers::{ 93 | aes128::MagicCrypt128, aes192::MagicCrypt192, aes256::MagicCrypt256, des64::MagicCrypt64, 94 | }; 95 | pub use errors::MagicCryptError; 96 | #[cfg(feature = "std")] 97 | use generic_array::typenum::{IsGreaterOrEqual, PartialDiv, True, B1, U16}; 98 | #[cfg(feature = "std")] 99 | use generic_array::ArrayLength; 100 | pub use secure_bit::SecureBit; 101 | pub use traits::MagicCryptTrait; 102 | 103 | #[derive(Debug, Clone)] 104 | enum MagicCryptCipher { 105 | DES64(MagicCrypt64), 106 | AES128(MagicCrypt128), 107 | AES192(MagicCrypt192), 108 | AES256(MagicCrypt256), 109 | } 110 | 111 | /// This struct can help you encrypt or decrypt data in a quick way. 112 | #[derive(Debug, Clone)] 113 | pub struct MagicCrypt { 114 | cipher: MagicCryptCipher, 115 | } 116 | 117 | impl MagicCrypt { 118 | /// Create a new `MagicCrypt` instance. You may want to use the `new_magic_crypt!` macro. 119 | pub fn new, V: AsRef<[u8]>>( 120 | key: S, 121 | bit: SecureBit, 122 | iv: Option, 123 | ) -> MagicCrypt { 124 | let cipher = match bit { 125 | SecureBit::Bit64 => MagicCryptCipher::DES64(MagicCrypt64::new(key, iv)), 126 | SecureBit::Bit128 => MagicCryptCipher::AES128(MagicCrypt128::new(key, iv)), 127 | SecureBit::Bit192 => MagicCryptCipher::AES192(MagicCrypt192::new(key, iv)), 128 | SecureBit::Bit256 => MagicCryptCipher::AES256(MagicCrypt256::new(key, iv)), 129 | }; 130 | 131 | MagicCrypt { 132 | cipher, 133 | } 134 | } 135 | } 136 | 137 | impl MagicCryptTrait for MagicCrypt { 138 | #[inline] 139 | fn new, V: AsRef<[u8]>>(key: S, iv: Option) -> MagicCrypt { 140 | MagicCrypt::new(key, SecureBit::default(), iv) 141 | } 142 | 143 | #[inline] 144 | fn encrypt_to_bytes>(&self, data: &T) -> Vec { 145 | match &self.cipher { 146 | MagicCryptCipher::DES64(mc) => mc.encrypt_to_bytes(data), 147 | MagicCryptCipher::AES128(mc) => mc.encrypt_to_bytes(data), 148 | MagicCryptCipher::AES192(mc) => mc.encrypt_to_bytes(data), 149 | MagicCryptCipher::AES256(mc) => mc.encrypt_to_bytes(data), 150 | } 151 | } 152 | 153 | #[cfg(feature = "std")] 154 | #[inline] 155 | fn encrypt_reader_to_bytes(&self, reader: &mut dyn Read) -> Result, MagicCryptError> { 156 | match &self.cipher { 157 | MagicCryptCipher::DES64(mc) => mc.encrypt_reader_to_bytes(reader), 158 | MagicCryptCipher::AES128(mc) => mc.encrypt_reader_to_bytes(reader), 159 | MagicCryptCipher::AES192(mc) => mc.encrypt_reader_to_bytes(reader), 160 | MagicCryptCipher::AES256(mc) => mc.encrypt_reader_to_bytes(reader), 161 | } 162 | } 163 | 164 | #[cfg(feature = "std")] 165 | #[inline] 166 | fn encrypt_reader_to_writer2< 167 | N: ArrayLength + PartialDiv + IsGreaterOrEqual, 168 | >( 169 | &self, 170 | reader: &mut dyn Read, 171 | writer: &mut dyn Write, 172 | ) -> Result<(), MagicCryptError> { 173 | match &self.cipher { 174 | MagicCryptCipher::DES64(mc) => mc.encrypt_reader_to_writer2::(reader, writer), 175 | MagicCryptCipher::AES128(mc) => mc.encrypt_reader_to_writer2::(reader, writer), 176 | MagicCryptCipher::AES192(mc) => mc.encrypt_reader_to_writer2::(reader, writer), 177 | MagicCryptCipher::AES256(mc) => mc.encrypt_reader_to_writer2::(reader, writer), 178 | } 179 | } 180 | 181 | #[inline] 182 | fn decrypt_bytes_to_bytes>( 183 | &self, 184 | bytes: &T, 185 | ) -> Result, MagicCryptError> { 186 | match &self.cipher { 187 | MagicCryptCipher::DES64(mc) => mc.decrypt_bytes_to_bytes(bytes), 188 | MagicCryptCipher::AES128(mc) => mc.decrypt_bytes_to_bytes(bytes), 189 | MagicCryptCipher::AES192(mc) => mc.decrypt_bytes_to_bytes(bytes), 190 | MagicCryptCipher::AES256(mc) => mc.decrypt_bytes_to_bytes(bytes), 191 | } 192 | } 193 | 194 | #[cfg(feature = "std")] 195 | #[inline] 196 | fn decrypt_reader_to_bytes(&self, reader: &mut dyn Read) -> Result, MagicCryptError> { 197 | match &self.cipher { 198 | MagicCryptCipher::DES64(mc) => mc.decrypt_reader_to_bytes(reader), 199 | MagicCryptCipher::AES128(mc) => mc.decrypt_reader_to_bytes(reader), 200 | MagicCryptCipher::AES192(mc) => mc.decrypt_reader_to_bytes(reader), 201 | MagicCryptCipher::AES256(mc) => mc.decrypt_reader_to_bytes(reader), 202 | } 203 | } 204 | 205 | #[cfg(feature = "std")] 206 | #[inline] 207 | fn decrypt_reader_to_writer2< 208 | N: ArrayLength + PartialDiv + IsGreaterOrEqual + Add, 209 | >( 210 | &self, 211 | reader: &mut dyn Read, 212 | writer: &mut dyn Write, 213 | ) -> Result<(), MagicCryptError> 214 | where 215 | >::Output: ArrayLength, { 216 | match &self.cipher { 217 | MagicCryptCipher::DES64(mc) => mc.decrypt_reader_to_writer(reader, writer), 218 | MagicCryptCipher::AES128(mc) => mc.decrypt_reader_to_writer(reader, writer), 219 | MagicCryptCipher::AES192(mc) => mc.decrypt_reader_to_writer(reader, writer), 220 | MagicCryptCipher::AES256(mc) => mc.decrypt_reader_to_writer(reader, writer), 221 | } 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | /// This macro provides a convenient way to create a `MagicCrypt` instance or a `MagicCrypt` instance. 2 | #[macro_export] 3 | macro_rules! new_magic_crypt { 4 | (wrapper $key:expr) => { 5 | $crate::MagicCrypt::new($key, $crate::SecureBit::Bit128, None::) 6 | }; 7 | (wrapper $key:expr,64) => { 8 | $crate::MagicCrypt::new($key, $crate::SecureBit::Bit64, None::) 9 | }; 10 | (wrapper $key:expr,128) => { 11 | $crate::MagicCrypt::new($key, $crate::SecureBit::Bit128, None::) 12 | }; 13 | (wrapper $key:expr,192) => { 14 | $crate::MagicCrypt::new($key, $crate::SecureBit::Bit192, None::) 15 | }; 16 | (wrapper $key:expr,256) => { 17 | $crate::MagicCrypt::new($key, $crate::SecureBit::Bit256, None::) 18 | }; 19 | (wrapper $key:expr,64, $iv:expr) => { 20 | $crate::MagicCrypt::new($key, $crate::SecureBit::Bit64, Some($iv)) 21 | }; 22 | (wrapper $key:expr,128, $iv:expr) => { 23 | $crate::MagicCrypt::new($key, $crate::SecureBit::Bit128, Some($iv)) 24 | }; 25 | (wrapper $key:expr,192, $iv:expr) => { 26 | $crate::MagicCrypt::new($key, $crate::SecureBit::Bit192, Some($iv)) 27 | }; 28 | (wrapper $key:expr,256, $iv:expr) => { 29 | $crate::MagicCrypt::new($key, $crate::SecureBit::Bit256, Some($iv)) 30 | }; 31 | ($key:expr) => {{ 32 | use $crate::MagicCryptTrait; 33 | 34 | $crate::MagicCrypt128::new($key, None::) 35 | }}; 36 | ($key:expr,64) => {{ 37 | use $crate::MagicCryptTrait; 38 | 39 | $crate::MagicCrypt64::new($key, None::) 40 | }}; 41 | ($key:expr,128) => {{ 42 | use $crate::MagicCryptTrait; 43 | 44 | $crate::MagicCrypt128::new($key, None::) 45 | }}; 46 | ($key:expr,192) => {{ 47 | use $crate::MagicCryptTrait; 48 | 49 | $crate::MagicCrypt192::new($key, None::) 50 | }}; 51 | ($key:expr,256) => {{ 52 | use $crate::MagicCryptTrait; 53 | 54 | $crate::MagicCrypt256::new($key, None::) 55 | }}; 56 | ($key:expr,64, $iv:expr) => {{ 57 | use $crate::MagicCryptTrait; 58 | 59 | $crate::MagicCrypt64::new($key, Some($iv)) 60 | }}; 61 | ($key:expr,128, $iv:expr) => {{ 62 | use $crate::MagicCryptTrait; 63 | 64 | $crate::MagicCrypt128::new($key, Some($iv)) 65 | }}; 66 | ($key:expr,192, $iv:expr) => {{ 67 | use $crate::MagicCryptTrait; 68 | 69 | $crate::MagicCrypt192::new($key, Some($iv)) 70 | }}; 71 | ($key:expr,256, $iv:expr) => {{ 72 | use $crate::MagicCryptTrait; 73 | 74 | $crate::MagicCrypt256::new($key, Some($iv)) 75 | }}; 76 | } 77 | -------------------------------------------------------------------------------- /src/secure_bit.rs: -------------------------------------------------------------------------------- 1 | use core::convert::TryFrom; 2 | 3 | /// How secure does your encryption need to be? 4 | #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] 5 | pub enum SecureBit { 6 | Bit64, 7 | #[default] 8 | Bit128, 9 | Bit192, 10 | Bit256, 11 | } 12 | 13 | impl TryFrom for SecureBit { 14 | type Error = &'static str; 15 | 16 | #[inline] 17 | fn try_from(bit_number: u16) -> Result { 18 | Ok(match bit_number { 19 | 64 => SecureBit::Bit64, 20 | 128 => SecureBit::Bit128, 21 | 192 => SecureBit::Bit192, 22 | 256 => SecureBit::Bit256, 23 | _ => return Err("Unsupported number of bits."), 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/traits.rs: -------------------------------------------------------------------------------- 1 | use alloc::{string::String, vec::Vec}; 2 | #[cfg(feature = "std")] 3 | use std::io::{Read, Write}; 4 | #[cfg(feature = "std")] 5 | use std::ops::Add; 6 | 7 | use base64::Engine; 8 | 9 | #[cfg(feature = "std")] 10 | use crate::generic_array::typenum::{IsGreaterOrEqual, PartialDiv, True, B1, U16, U4096}; 11 | #[cfg(feature = "std")] 12 | use crate::generic_array::ArrayLength; 13 | use crate::MagicCryptError; 14 | 15 | /// Methods for `MagicCrypt` and `MagicCrypt` structs. 16 | pub trait MagicCryptTrait { 17 | fn new, V: AsRef<[u8]>>(key: S, iv: Option) -> Self; 18 | 19 | #[inline] 20 | fn encrypt_str_to_base64>(&self, string: S) -> String { 21 | self.encrypt_to_base64(string.as_ref()) 22 | } 23 | 24 | #[inline] 25 | fn encrypt_str_to_bytes>(&self, string: S) -> Vec { 26 | self.encrypt_to_bytes(string.as_ref()) 27 | } 28 | 29 | #[inline] 30 | fn encrypt_bytes_to_base64>(&self, bytes: &T) -> String { 31 | self.encrypt_to_base64(bytes) 32 | } 33 | 34 | #[inline] 35 | fn encrypt_bytes_to_bytes>(&self, bytes: &T) -> Vec { 36 | self.encrypt_to_bytes(bytes) 37 | } 38 | 39 | #[inline] 40 | fn encrypt_to_base64>(&self, data: &T) -> String { 41 | base64::engine::general_purpose::STANDARD.encode(self.encrypt_to_bytes(data)) 42 | } 43 | 44 | fn encrypt_to_bytes>(&self, data: &T) -> Vec; 45 | 46 | #[cfg(feature = "std")] 47 | #[inline] 48 | fn encrypt_reader_to_base64(&self, reader: &mut dyn Read) -> Result { 49 | self.encrypt_reader_to_bytes(reader) 50 | .map(|bytes| base64::engine::general_purpose::STANDARD.encode(bytes)) 51 | } 52 | 53 | #[cfg(feature = "std")] 54 | fn encrypt_reader_to_bytes(&self, reader: &mut dyn Read) -> Result, MagicCryptError>; 55 | 56 | #[cfg(feature = "std")] 57 | fn encrypt_reader_to_writer( 58 | &self, 59 | reader: &mut dyn Read, 60 | writer: &mut dyn Write, 61 | ) -> Result<(), MagicCryptError> { 62 | self.encrypt_reader_to_writer2::(reader, writer) 63 | } 64 | 65 | #[cfg(feature = "std")] 66 | fn encrypt_reader_to_writer2< 67 | N: ArrayLength + PartialDiv + IsGreaterOrEqual, 68 | >( 69 | &self, 70 | reader: &mut dyn Read, 71 | writer: &mut dyn Write, 72 | ) -> Result<(), MagicCryptError>; 73 | 74 | #[inline] 75 | fn decrypt_base64_to_string>( 76 | &self, 77 | base64: S, 78 | ) -> Result { 79 | Ok(String::from_utf8(self.decrypt_base64_to_bytes(base64)?)?) 80 | } 81 | 82 | #[inline] 83 | fn decrypt_base64_to_bytes>( 84 | &self, 85 | base64: S, 86 | ) -> Result, MagicCryptError> { 87 | self.decrypt_bytes_to_bytes( 88 | &base64::engine::general_purpose::STANDARD.decode(base64.as_ref())?, 89 | ) 90 | } 91 | 92 | fn decrypt_bytes_to_bytes>( 93 | &self, 94 | bytes: &T, 95 | ) -> Result, MagicCryptError>; 96 | 97 | #[cfg(feature = "std")] 98 | fn decrypt_reader_to_bytes(&self, reader: &mut dyn Read) -> Result, MagicCryptError>; 99 | 100 | #[cfg(feature = "std")] 101 | fn decrypt_reader_to_writer( 102 | &self, 103 | reader: &mut dyn Read, 104 | writer: &mut dyn Write, 105 | ) -> Result<(), MagicCryptError> { 106 | self.decrypt_reader_to_writer2::(reader, writer) 107 | } 108 | 109 | #[cfg(feature = "std")] 110 | fn decrypt_reader_to_writer2< 111 | N: ArrayLength + PartialDiv + IsGreaterOrEqual + Add, 112 | >( 113 | &self, 114 | reader: &mut dyn Read, 115 | writer: &mut dyn Write, 116 | ) -> Result<(), MagicCryptError> 117 | where 118 | >::Output: ArrayLength; 119 | } 120 | -------------------------------------------------------------------------------- /tests/basic.rs: -------------------------------------------------------------------------------- 1 | use magic_crypt::{new_magic_crypt, MagicCryptTrait}; 2 | 3 | #[test] 4 | fn crypt() { 5 | let mc = new_magic_crypt!("magickey"); 6 | 7 | let base64 = mc.encrypt_str_to_base64("https://magiclen.org"); 8 | 9 | assert_eq!("4tk0QoLU++c2TiZ/hke5YY9wHn2pluNIXaj8L3khj3s=", base64); 10 | 11 | let mc = new_magic_crypt!(wrapper "magickey"); 12 | 13 | assert_eq!("https://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap()); 14 | } 15 | 16 | #[test] 17 | fn crypt_64() { 18 | let mc = new_magic_crypt!("magickey", 64); 19 | 20 | let base64 = mc.encrypt_str_to_base64("https://magiclen.org"); 21 | 22 | assert_eq!("hnVcTXXaXO77Adc9jhnUV5AhIFq1SQNO", base64); 23 | 24 | let mc = new_magic_crypt!(wrapper "magickey", 64); 25 | 26 | assert_eq!("https://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap()); 27 | 28 | let mc = new_magic_crypt!("xxxxxxxx", 64); 29 | 30 | assert!(mc.decrypt_base64_to_string(&base64).is_err()); 31 | } 32 | 33 | #[test] 34 | fn crypt_128() { 35 | let mc = new_magic_crypt!("magickey", 128); 36 | 37 | let base64 = mc.encrypt_str_to_base64("https://magiclen.org"); 38 | 39 | assert_eq!("4tk0QoLU++c2TiZ/hke5YY9wHn2pluNIXaj8L3khj3s=", base64); 40 | 41 | let mc = new_magic_crypt!(wrapper "magickey", 128); 42 | 43 | assert_eq!("https://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap()); 44 | 45 | let mc = new_magic_crypt!("xxxxxxxx", 128); 46 | 47 | assert!(mc.decrypt_base64_to_string(&base64).is_err()); 48 | } 49 | 50 | #[test] 51 | fn crypt_192() { 52 | let mc = new_magic_crypt!("magickey", 192); 53 | 54 | let base64 = mc.encrypt_str_to_base64("https://magiclen.org"); 55 | 56 | assert_eq!("IccS4yndkkxev4eoy6FNlZxkz9YbxsEp5AzWiqzBDBQ=", base64); 57 | 58 | let mc = new_magic_crypt!(wrapper "magickey", 192); 59 | 60 | assert_eq!("https://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap()); 61 | 62 | let mc = new_magic_crypt!("xxxxxxxx", 192); 63 | 64 | assert!(mc.decrypt_base64_to_string(&base64).is_err()); 65 | } 66 | 67 | #[test] 68 | fn crypt_256() { 69 | let mc = new_magic_crypt!("magickey", 256); 70 | 71 | let base64 = mc.encrypt_str_to_base64("https://magiclen.org"); 72 | 73 | assert_eq!("jWEPYLTECqGvWJbdlRGeZIupoLX8N9DYZIUKMRp/OQY=", base64); 74 | 75 | let mc = new_magic_crypt!(wrapper "magickey", 256); 76 | 77 | assert_eq!("https://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap()); 78 | 79 | let mc = new_magic_crypt!("xxxxxxxx", 256); 80 | 81 | assert!(mc.decrypt_base64_to_string(&base64).is_err()); 82 | } 83 | 84 | #[test] 85 | fn crypt_64_with_iv() { 86 | let mc = new_magic_crypt!("magickey", 64, "123456789"); 87 | 88 | let base64 = mc.encrypt_str_to_base64("https://magiclen.org"); 89 | 90 | assert_eq!("Wn9566qFK9g/SD0OPKHAZz3Q/2pAGVbz", base64); 91 | 92 | let mc = new_magic_crypt!(wrapper "magickey", 64, "123456789"); 93 | 94 | assert_eq!("https://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap()); 95 | 96 | let mc = new_magic_crypt!("xxxxxxxx", 64, "123456789"); 97 | 98 | assert!(mc.decrypt_base64_to_string(&base64).is_err()); 99 | } 100 | 101 | #[test] 102 | fn crypt_128_with_iv() { 103 | let mc = new_magic_crypt!("magickey", 128, "123456789"); 104 | 105 | let base64 = mc.encrypt_str_to_base64("https://magiclen.org"); 106 | 107 | assert_eq!("dQcxpt67DG7+kMiSj+HyjRjjDisy1iZpyvxVJRVKKZ4=", base64); 108 | 109 | let mc = new_magic_crypt!(wrapper "magickey", 128, "123456789"); 110 | 111 | assert_eq!("https://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap()); 112 | 113 | let mc = new_magic_crypt!("xxxxxxxx", 128, "123456789"); 114 | 115 | assert!(mc.decrypt_base64_to_string(&base64).is_err()); 116 | } 117 | 118 | #[test] 119 | fn crypt_192_with_iv() { 120 | let mc = new_magic_crypt!("magickey", 192, "123456789"); 121 | 122 | let base64 = mc.encrypt_str_to_base64("https://magiclen.org"); 123 | 124 | assert_eq!("uqTD7ZesaVEHnlT801hM+T8nqY8lTVWwYoNe1OsMA04=", base64); 125 | 126 | let mc = new_magic_crypt!(wrapper "magickey", 192, "123456789"); 127 | 128 | assert_eq!("https://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap()); 129 | 130 | let mc = new_magic_crypt!("xxxxxxxx", 192, "123456789"); 131 | 132 | assert!(mc.decrypt_base64_to_string(&base64).is_err()); 133 | } 134 | 135 | #[test] 136 | fn crypt_256_with_iv() { 137 | let mc = new_magic_crypt!("magickey", 256, "123456789"); 138 | 139 | let base64 = mc.encrypt_str_to_base64("https://magiclen.org"); 140 | 141 | assert_eq!("ixCZtfFVt01DgOX+WmsqERcd1efq/yVpGLc5SfTVYXc=", base64); 142 | 143 | let mc = new_magic_crypt!(wrapper "magickey", 256, "123456789"); 144 | 145 | assert_eq!("https://magiclen.org", mc.decrypt_base64_to_string(&base64).unwrap()); 146 | 147 | let mc = new_magic_crypt!("xxxxxxxx", 256, "123456789"); 148 | 149 | assert!(mc.decrypt_base64_to_string(&base64).is_err()); 150 | } 151 | -------------------------------------------------------------------------------- /tests/stream.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "std")] 2 | 3 | use std::io::Cursor; 4 | 5 | use base64::Engine; 6 | use magic_crypt::{new_magic_crypt, MagicCryptError, MagicCryptTrait}; 7 | 8 | fn encrypt_reader_to_writer(mc: impl MagicCryptTrait) -> String { 9 | let mut output_buffer = Cursor::new([0; 32]); 10 | 11 | mc.encrypt_reader_to_writer(&mut Cursor::new("https://magiclen.org"), &mut output_buffer) 12 | .unwrap(); 13 | 14 | let c = output_buffer.position(); 15 | let output = output_buffer.into_inner(); 16 | 17 | base64::engine::general_purpose::STANDARD.encode(&output[..c as usize]) 18 | } 19 | 20 | fn decrypt_reader_to_writer( 21 | mc: impl MagicCryptTrait, 22 | base64: &str, 23 | ) -> Result { 24 | let encrypted_data = base64::engine::general_purpose::STANDARD.decode(base64).unwrap(); 25 | 26 | let mut output_buffer = Cursor::new(vec![0; 32]); 27 | 28 | mc.decrypt_reader_to_writer(&mut Cursor::new(encrypted_data), &mut output_buffer)?; 29 | 30 | let c = output_buffer.position(); 31 | let mut output = output_buffer.into_inner(); 32 | output.truncate(c as usize); 33 | 34 | Ok(String::from_utf8(output)?) 35 | } 36 | 37 | #[test] 38 | fn crypt_64_reader_writer() { 39 | let mc = new_magic_crypt!("magickey", 64); 40 | 41 | let base64 = encrypt_reader_to_writer(mc); 42 | 43 | assert_eq!("hnVcTXXaXO77Adc9jhnUV5AhIFq1SQNO", base64); 44 | 45 | let mc = new_magic_crypt!(wrapper "magickey", 64); 46 | 47 | assert_eq!("https://magiclen.org", decrypt_reader_to_writer(mc, &base64).unwrap()); 48 | 49 | let mc = new_magic_crypt!("xxxxxxxx", 64); 50 | 51 | assert!(decrypt_reader_to_writer(mc, &base64).is_err()); 52 | } 53 | 54 | #[test] 55 | fn crypt_128_reader_writer() { 56 | let mc = new_magic_crypt!("magickey", 128); 57 | 58 | let base64 = encrypt_reader_to_writer(mc); 59 | 60 | assert_eq!("4tk0QoLU++c2TiZ/hke5YY9wHn2pluNIXaj8L3khj3s=", base64); 61 | 62 | let mc = new_magic_crypt!(wrapper "magickey", 128); 63 | 64 | assert_eq!("https://magiclen.org", decrypt_reader_to_writer(mc, &base64).unwrap()); 65 | 66 | let mc = new_magic_crypt!("xxxxxxxx", 128); 67 | 68 | assert!(decrypt_reader_to_writer(mc, &base64).is_err()); 69 | } 70 | 71 | #[test] 72 | fn crypt_192_reader_writer() { 73 | let mc = new_magic_crypt!("magickey", 192); 74 | 75 | let base64 = encrypt_reader_to_writer(mc); 76 | 77 | assert_eq!("IccS4yndkkxev4eoy6FNlZxkz9YbxsEp5AzWiqzBDBQ=", base64); 78 | 79 | let mc = new_magic_crypt!(wrapper "magickey", 192); 80 | 81 | assert_eq!("https://magiclen.org", decrypt_reader_to_writer(mc, &base64).unwrap()); 82 | 83 | let mc = new_magic_crypt!("xxxxxxxx", 192); 84 | 85 | assert!(decrypt_reader_to_writer(mc, &base64).is_err()); 86 | } 87 | 88 | #[test] 89 | fn crypt_256_reader_writer() { 90 | let mc = new_magic_crypt!("magickey", 256); 91 | 92 | let base64 = encrypt_reader_to_writer(mc); 93 | 94 | assert_eq!("jWEPYLTECqGvWJbdlRGeZIupoLX8N9DYZIUKMRp/OQY=", base64); 95 | 96 | let mc = new_magic_crypt!(wrapper "magickey", 256); 97 | 98 | assert_eq!("https://magiclen.org", decrypt_reader_to_writer(mc, &base64).unwrap()); 99 | 100 | let mc = new_magic_crypt!("xxxxxxxx", 256); 101 | 102 | assert!(decrypt_reader_to_writer(mc, &base64).is_err()); 103 | } 104 | --------------------------------------------------------------------------------