initial push
This commit is contained in:
commit
bb3877633a
19
Cargo.toml
Normal file
19
Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "encrypted_images"
|
||||||
|
version = "1.3.0"
|
||||||
|
edition = "2021"
|
||||||
|
description = "Encrypt Text to Images and decrypt text from images."
|
||||||
|
authors = ["Bruce Bates | https://encryptedimages.art"]
|
||||||
|
license = "MIT"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
openssl = { version = "0.10.57", features = ["vendored"] }
|
||||||
|
base64 = "0.21.4"
|
||||||
|
image = { version = "0.23", features = ["png"] }
|
||||||
|
native-dialog = "0.6.4"
|
||||||
|
hmac = "0.12.1"
|
||||||
|
sha2 = "0.10.7"
|
||||||
|
hex-literal = "0.4.1"
|
||||||
|
encoding = "0.2"
|
||||||
|
subtle = "2.4"
|
||||||
|
rand = "0.8.5"
|
7
SUPPORT
Normal file
7
SUPPORT
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
Support this developers open source efforts:
|
||||||
|
|
||||||
|
bitcoin: bc1pf0s98gva7la6r9srepywwr4llqea8t0r4fj8qkdqqac0f9y5624sxpsmqq
|
||||||
|
ethereum: 0x78046716a783B94240ff6b4Ba6580F6D5690423A
|
||||||
|
cardano: addr1q8dxlqu824ghzn3extm8zjqzmr2u5fy4p0jpaqs6w8jpt4wkpgtm6wkc0me3gmgfgdadnpzdcj24yz3znme5w7kvm8vs0thea2
|
||||||
|
solana: HG1fpdqHkxSUyT85V6LGu8dbC3BK4JixiivjYLHVsazQ
|
||||||
|
tezos: tz2TL7ke3xyxWi4JbS6egscmpEP9Z9XrV86y
|
15
examples/create_an_image.rs
Normal file
15
examples/create_an_image.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
use encrypted_images::encryption::images::create_img;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let ciphertext = "VkdocGN5QkpjeUJRYkE9PZNY2MOW01NWpSxCtFG6acHuAWun+CElPQ/IIwd0gy+D+IiBqB/5+qo8Jr9bMBOwoih3amCtjXlkAlRKHX5fhqI=";
|
||||||
|
let style = "h";
|
||||||
|
let watermark = "bitcoin";
|
||||||
|
let r = Some(100);
|
||||||
|
let g = Some(134);
|
||||||
|
let b = Some(137);
|
||||||
|
if let Some(encoded_image) = create_img(ciphertext, style, watermark, r, g, b, None, None, None) {
|
||||||
|
println!("Encoded image: {}", encoded_image);
|
||||||
|
} else {
|
||||||
|
println!("Image creation or encoding failed.");
|
||||||
|
}
|
||||||
|
}
|
15
examples/create_an_image_custom_gradient.rs
Normal file
15
examples/create_an_image_custom_gradient.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
use encrypted_images::encryption::images::create_img;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let ciphertext = "VkdocGN5QkpjeUJRYkE9PZNY2MOW01NWpSxCtFG6acHuAWun+CElPQ/IIwd0gy+D+IiBqB/5+qo8Jr9bMBOwoih3amCtjXlkAlRKHX5fhqI=";
|
||||||
|
let style = "h";
|
||||||
|
let watermark = "bitcoin";
|
||||||
|
let r = Some(46);
|
||||||
|
let g = Some(115);
|
||||||
|
let b = Some(82);
|
||||||
|
if let Some(encoded_image) = create_img(ciphertext, style, watermark, r, g, b, None, None, None) {
|
||||||
|
println!("Encoded image: {}", encoded_image);
|
||||||
|
} else {
|
||||||
|
println!("Image creation or encoding failed.");
|
||||||
|
}
|
||||||
|
}
|
18
examples/create_an_image_custom_watermark.rs
Normal file
18
examples/create_an_image_custom_watermark.rs
Normal file
File diff suppressed because one or more lines are too long
15
examples/create_an_image_upside_down.rs
Normal file
15
examples/create_an_image_upside_down.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
use encrypted_images::encryption::images::create_img;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let ciphertext = "VkdocGN5QkpjeUJRYkE9PZNY2MOW01NWpSxCtFG6acHuAWun+CElPQ/IIwd0gy+D+IiBqB/5+qo8Jr9bMBOwoih3amCtjXlkAlRKHX5fhqI=";
|
||||||
|
let style = "h2";
|
||||||
|
let watermark = "bitcoin";
|
||||||
|
let r = Some(100);
|
||||||
|
let g = Some(134);
|
||||||
|
let b = Some(137);
|
||||||
|
if let Some(encoded_image) = create_img(ciphertext, style, watermark, r, g, b, None, None, None) {
|
||||||
|
println!("Encoded image: {}", encoded_image);
|
||||||
|
} else {
|
||||||
|
println!("Image creation or encoding failed.");
|
||||||
|
}
|
||||||
|
}
|
11
examples/decode_image.rs
Normal file
11
examples/decode_image.rs
Normal file
File diff suppressed because one or more lines are too long
17
examples/decode_image_and_decrypt.rs
Normal file
17
examples/decode_image_and_decrypt.rs
Normal file
File diff suppressed because one or more lines are too long
10
examples/decrypt_novelty.rs
Normal file
10
examples/decrypt_novelty.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
use encrypted_images::decryption::text::decrypts;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let encrypted_text = "VkdocGN5QkpjeUJRYkE9PZNY2MOW01NWpSxCtFG6acHuAWun+CElPQ/IIwd0gy+D+IiBqB/5+qo8Jr9bMBOwoih3amCtjXlkAlRKHX5fhqI=";
|
||||||
|
if let Some(decrypted_text) = decrypts(encrypted_text, None) {
|
||||||
|
println!("Decrypted text: {}", decrypted_text);
|
||||||
|
} else {
|
||||||
|
println!("Decryption failed.");
|
||||||
|
}
|
||||||
|
}
|
11
examples/decrypt_secure.rs
Normal file
11
examples/decrypt_secure.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
use encrypted_images::decryption::text::decrypts;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let encrypted_text = "OWFNTGpvaGFMbWtTUkE9PcjB/klKI3ix+Z0uVuYbd3zRqaTjMgxotQu4hz1FRSfPWRQMOBhLSI6+KFPl8qldeCPoUYvezvVMOScWll9OzCA=";
|
||||||
|
let key = Some("16characterslong");
|
||||||
|
if let Some(decrypted_text) = decrypts(encrypted_text, key) {
|
||||||
|
println!("Decrypted text: {}", decrypted_text);
|
||||||
|
} else {
|
||||||
|
println!("Decryption failed.");
|
||||||
|
}
|
||||||
|
}
|
16
examples/encrypt_and_create_image.rs
Normal file
16
examples/encrypt_and_create_image.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
use encrypted_images::encryption::text::encrypts;
|
||||||
|
use encrypted_images::encryption::images::create_img;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let key = Some("your_secret_key");
|
||||||
|
let ciphertext = "This is a secret message.";
|
||||||
|
let style = "h";
|
||||||
|
let encrypted = encrypts(ciphertext, key.clone(), None).unwrap();
|
||||||
|
let watermark = "bitcoin";
|
||||||
|
let image_data = create_img(&encrypted, style, watermark, None, None, None, None, None, None);
|
||||||
|
|
||||||
|
match image_data {
|
||||||
|
Some(encoded_image) => println!("Encoded Image:\n{}", encoded_image),
|
||||||
|
None => println!("Failed to create the image."),
|
||||||
|
}
|
||||||
|
}
|
7
examples/encrypt_novelty.rs
Normal file
7
examples/encrypt_novelty.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use encrypted_images::encryption::text::encrypts;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let plaintext = "This Is Plain Text";
|
||||||
|
let encrypted_text = encrypts(plaintext, None, None).unwrap();
|
||||||
|
println!("Encrypted text: {}", encrypted_text);
|
||||||
|
}
|
9
examples/encrypt_secure.rs
Normal file
9
examples/encrypt_secure.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use encrypted_images::encryption::text::encrypts;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let plaintext = "This Is Plain Text";
|
||||||
|
let key = Some("16characterslong");
|
||||||
|
let strength = Some("advanced");
|
||||||
|
let encrypted_text = encrypts(plaintext, key, strength).unwrap();
|
||||||
|
println!("Encrypted text: {}", encrypted_text);
|
||||||
|
}
|
149
src/char_mappings/maps.rs
Normal file
149
src/char_mappings/maps.rs
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
pub mod mappings {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
pub(crate) fn get_color(char: char) -> Option<(u8, u8, u8)> {
|
||||||
|
match char {
|
||||||
|
'a' => Some((204, 180, 194)),
|
||||||
|
'A' => Some((255, 255, 255)),
|
||||||
|
'b' => Some((197, 186, 201)),
|
||||||
|
'B' => Some((221, 206, 212)),
|
||||||
|
'c' => Some((181, 185, 193)),
|
||||||
|
'C' => Some((184, 201, 223)),
|
||||||
|
'd' => Some((224, 218, 192)),
|
||||||
|
'D' => Some((185, 191, 195)),
|
||||||
|
'e' => Some((181, 197, 198)),
|
||||||
|
'E' => Some((193, 206, 255)),
|
||||||
|
'f' => Some((252, 193, 211)),
|
||||||
|
'F' => Some((183, 192, 229)),
|
||||||
|
'g' => Some((180, 191, 192)),
|
||||||
|
'G' => Some((187, 219, 189)),
|
||||||
|
'h' => Some((195, 187, 234)),
|
||||||
|
'H' => Some((182, 216, 189)),
|
||||||
|
'i' => Some((197, 183, 248)),
|
||||||
|
'I' => Some((200, 182, 204)),
|
||||||
|
'j' => Some((255, 235, 196)),
|
||||||
|
'J' => Some((194, 186, 228)),
|
||||||
|
'k' => Some((199, 238, 239)),
|
||||||
|
'K' => Some((208, 247, 234)),
|
||||||
|
'l' => Some((244, 214, 189)),
|
||||||
|
'L' => Some((187, 243, 239)),
|
||||||
|
'm' => Some((188, 231, 238)),
|
||||||
|
'M' => Some((187, 197, 227)),
|
||||||
|
'n' => Some((186, 240, 191)),
|
||||||
|
'N' => Some((187, 198, 206)),
|
||||||
|
'o' => Some((205, 193, 184)),
|
||||||
|
'O' => Some((191, 187, 197)),
|
||||||
|
'p' => Some((194, 200, 206)),
|
||||||
|
'P' => Some((195, 183, 229)),
|
||||||
|
'q' => Some((182, 219, 196)),
|
||||||
|
'Q' => Some((238, 216, 184)),
|
||||||
|
'r' => Some((199, 181, 208)),
|
||||||
|
'R' => Some((239, 231, 198)),
|
||||||
|
's' => Some((189, 188, 230)),
|
||||||
|
'S' => Some((242, 192, 230)),
|
||||||
|
't' => Some((199, 199, 199)),
|
||||||
|
'T' => Some((188, 190, 230)),
|
||||||
|
'u' => Some((230, 180, 253)),
|
||||||
|
'U' => Some((241, 247, 247)),
|
||||||
|
'v' => Some((242, 190, 199)),
|
||||||
|
'V' => Some((230, 247, 234)),
|
||||||
|
'w' => Some((197, 186, 249)),
|
||||||
|
'W' => Some((194, 247, 249)),
|
||||||
|
'x' => Some((242, 182, 246)),
|
||||||
|
'X' => Some((188, 222, 193)),
|
||||||
|
'y' => Some((188, 194, 183)),
|
||||||
|
'Y' => Some((197, 195, 197)),
|
||||||
|
'z' => Some((187, 249, 240)),
|
||||||
|
'Z' => Some((233, 231, 242)),
|
||||||
|
'0' => Some((195, 184, 218)),
|
||||||
|
'1' => Some((232, 180, 196)),
|
||||||
|
'2' => Some((191, 193, 196)),
|
||||||
|
'3' => Some((185, 186, 186)),
|
||||||
|
'4' => Some((191, 247, 180)),
|
||||||
|
'5' => Some((187, 199, 248)),
|
||||||
|
'6' => Some((248, 198, 184)),
|
||||||
|
'7' => Some((243, 195, 184)),
|
||||||
|
'8' => Some((232, 192, 208)),
|
||||||
|
'9' => Some((239, 197, 183)),
|
||||||
|
'/' => Some((199, 187, 241)),
|
||||||
|
'+' => Some((195, 216, 223)),
|
||||||
|
'=' => Some((193, 211, 184)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub(crate) fn numbers_to_letter(r: u8, g: u8, b: u8) -> Option<char> {
|
||||||
|
let color_map: HashMap<(u8, u8, u8), char> = [
|
||||||
|
((204, 180, 194), 'a'),
|
||||||
|
((255, 255, 255), 'A'),
|
||||||
|
((197, 186, 201), 'b'),
|
||||||
|
((221, 206, 212), 'B'),
|
||||||
|
((181, 185, 193), 'c'),
|
||||||
|
((184, 201, 223), 'C'),
|
||||||
|
((224, 218, 192), 'd'),
|
||||||
|
((185, 191, 195), 'D'),
|
||||||
|
((181, 197, 198), 'e'),
|
||||||
|
((193, 206, 255), 'E'),
|
||||||
|
((252, 193, 211), 'f'),
|
||||||
|
((183, 192, 229), 'F'),
|
||||||
|
((180, 191, 192), 'g'),
|
||||||
|
((187, 219, 189), 'G'),
|
||||||
|
((195, 187, 234), 'h'),
|
||||||
|
((182, 216, 189), 'H'),
|
||||||
|
((197, 183, 248), 'i'),
|
||||||
|
((200, 182, 204), 'I'),
|
||||||
|
((255, 235, 196), 'j'),
|
||||||
|
((194, 186, 228), 'J'),
|
||||||
|
((199, 238, 239), 'k'),
|
||||||
|
((208, 247, 234), 'K'),
|
||||||
|
((244, 214, 189), 'l'),
|
||||||
|
((187, 243, 239), 'L'),
|
||||||
|
((188, 231, 238), 'm'),
|
||||||
|
((187, 197, 227), 'M'),
|
||||||
|
((186, 240, 191), 'n'),
|
||||||
|
((187, 198, 206), 'N'),
|
||||||
|
((205, 193, 184), 'o'),
|
||||||
|
((191, 187, 197), 'O'),
|
||||||
|
((194, 200, 206), 'p'),
|
||||||
|
((195, 183, 229), 'P'),
|
||||||
|
((182, 219, 196), 'q'),
|
||||||
|
((238, 216, 184), 'Q'),
|
||||||
|
((199, 181, 208), 'r'),
|
||||||
|
((239, 231, 198), 'R'),
|
||||||
|
((189, 188, 230), 's'),
|
||||||
|
((242, 192, 230), 'S'),
|
||||||
|
((199, 199, 199), 't'),
|
||||||
|
((188, 190, 230), 'T'),
|
||||||
|
((230, 180, 253), 'u'),
|
||||||
|
((241, 247, 247), 'U'),
|
||||||
|
((242, 190, 199), 'v'),
|
||||||
|
((230, 247, 234), 'V'),
|
||||||
|
((197, 186, 249), 'w'),
|
||||||
|
((194, 247, 249), 'W'),
|
||||||
|
((242, 182, 246), 'x'),
|
||||||
|
((188, 222, 193), 'X'),
|
||||||
|
((188, 194, 183), 'y'),
|
||||||
|
((197, 195, 197), 'Y'),
|
||||||
|
((187, 249, 240), 'z'),
|
||||||
|
((233, 231, 242), 'Z'),
|
||||||
|
((195, 184, 218), '0'),
|
||||||
|
((232, 180, 196), '1'),
|
||||||
|
((191, 193, 196), '2'),
|
||||||
|
((185, 186, 186), '3'),
|
||||||
|
((191, 247, 180), '4'),
|
||||||
|
((187, 199, 248), '5'),
|
||||||
|
((248, 198, 184), '6'),
|
||||||
|
((243, 195, 184), '7'),
|
||||||
|
((232, 192, 208), '8'),
|
||||||
|
((239, 197, 183), '9'),
|
||||||
|
((199, 187, 241), '/'),
|
||||||
|
((195, 216, 223), '+'),
|
||||||
|
((193, 211, 184), '='),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
match color_map.get(&(r, g, b)) {
|
||||||
|
Some(&letter) => Some(letter),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
src/char_mappings/mod.rs
Normal file
1
src/char_mappings/mod.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub mod maps;
|
100
src/decryption/images.rs
Normal file
100
src/decryption/images.rs
Normal file
File diff suppressed because one or more lines are too long
122
src/decryption/images.rs_WORKING
Normal file
122
src/decryption/images.rs_WORKING
Normal file
File diff suppressed because one or more lines are too long
2
src/decryption/mod.rs
Normal file
2
src/decryption/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod text;
|
||||||
|
pub mod images;
|
56
src/decryption/text.rs
Normal file
56
src/decryption/text.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/// Decrypts an encoded result using an optional decryption key.
|
||||||
|
///
|
||||||
|
/// This function takes an encoded result and an optional decryption key, and attempts to decrypt
|
||||||
|
/// the result using AES-128 CBC decryption. It also verifies the integrity of the data using HMAC.
|
||||||
|
///
|
||||||
|
/// Timing Attack Protection:
|
||||||
|
/// The decryption process is designed to protect against timing attacks, ensuring secure
|
||||||
|
/// operation. It is suitable for standard encryption needs. Please see notes inside the encrypts
|
||||||
|
/// function to understand additional security. Default encryption settings are not maximum security.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `encoded_result` - The Base64-encoded result to be decrypted.
|
||||||
|
/// * `key` - An optional decryption key. If not provided, the default key "welovenfts" is used.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// An `Option<String>` containing the decrypted plaintext if successful, or `None` if decryption
|
||||||
|
/// fails or if the HMAC verification fails.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use encrypted_images::decryption::text::decrypts;
|
||||||
|
///
|
||||||
|
/// let encoded_result = "VkdocGMybHpiWGxqYnc9PbUWoPUFfy9Izm1wkCFZ8gSMWr6EUGW6UwYpnaounDkYmLNDjqWyvjcus2atCStKBOJSCnosjApRrcJrm44hatuaJHSYONbHNOmpk3Rja/xH";
|
||||||
|
/// let key = "welovenfts";
|
||||||
|
/// let decrypted_data = decrypts(encoded_result, Some(key));
|
||||||
|
/// assert!(decrypted_data.is_some());
|
||||||
|
/// ```
|
||||||
|
use subtle::ConstantTimeEq;
|
||||||
|
use openssl::symm::{decrypt, Cipher};
|
||||||
|
use crate::encryption::text::hmac::calculate_hmac;
|
||||||
|
use base64::{Engine as _, engine::{self, general_purpose}, alphabet};
|
||||||
|
const CUSTOM_ENGINE: engine::GeneralPurpose =
|
||||||
|
engine::GeneralPurpose::new(&alphabet::STANDARD, general_purpose::PAD);
|
||||||
|
pub fn decrypts(encoded_result: &str, key: Option<&str>) -> Option<String> {
|
||||||
|
let key = key.unwrap_or("welovenfts");
|
||||||
|
let mut padded_key = key.as_bytes().to_vec();
|
||||||
|
while padded_key.len() < 16 {
|
||||||
|
padded_key.push(b'\0');
|
||||||
|
}
|
||||||
|
let result_bytes = CUSTOM_ENGINE.decode(encoded_result).ok()?;
|
||||||
|
let iv = &result_bytes[..16];
|
||||||
|
let hmac = &result_bytes[16..48];
|
||||||
|
let ciphertext = &result_bytes[48..];
|
||||||
|
let hmac_calculated = calculate_hmac(ciphertext, &padded_key);
|
||||||
|
if hmac_calculated.ct_eq(hmac).unwrap_u8() == 1 {
|
||||||
|
let cipher = Cipher::aes_128_cbc();
|
||||||
|
let decrypted_data = decrypt(cipher, &padded_key, Some(iv), ciphertext).ok()?;
|
||||||
|
Some(String::from_utf8_lossy(&decrypted_data).to_string())
|
||||||
|
} else {
|
||||||
|
println!("Decryption Failed");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
345
src/encryption/images.rs
Normal file
345
src/encryption/images.rs
Normal file
File diff suppressed because one or more lines are too long
2
src/encryption/mod.rs
Normal file
2
src/encryption/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod text;
|
||||||
|
pub mod images;
|
117
src/encryption/text.rs
Normal file
117
src/encryption/text.rs
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/// Encrypts the input text with an optional encryption key with timing attack protections and
|
||||||
|
/// standard encryption security measures (which are optional).
|
||||||
|
///
|
||||||
|
/// The `input` parameter is the text to be encrypted.
|
||||||
|
///
|
||||||
|
/// The `key` parameter is an optional encryption key. If not provided, a default key is used.
|
||||||
|
///
|
||||||
|
/// The `strength` parameter is optional security level. Is set this value can be default or
|
||||||
|
/// advanced.
|
||||||
|
///
|
||||||
|
/// # Notes
|
||||||
|
///
|
||||||
|
/// - This function has been updated to include timing attack protections to enhance security.
|
||||||
|
/// - The function uses static IV (Initialization Vector) bytes by default to generate consistant
|
||||||
|
/// encrypted text output. While suitable for some situations ensure to use the advanced
|
||||||
|
/// strength for highly sensative data but note that everytime you encrypt with the advanced
|
||||||
|
/// method the output will look differnt.
|
||||||
|
/// - Again stressing that the default security option is not the ideal choice for scenarios requiring the
|
||||||
|
/// highest level of encryption security.
|
||||||
|
/// - Without advanced security there are potentials for comparison attacks that can occur this encryption.
|
||||||
|
/// - Only use standard settings for novelty usage.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Encrypt a text with a custom key:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use encrypted_images::encryption::text::encrypts;
|
||||||
|
///
|
||||||
|
/// let input = "ThisIsJustaTestString";
|
||||||
|
/// let key = "your_secret_key";
|
||||||
|
/// let encrypted = encrypts(input, Some(key), None);
|
||||||
|
///
|
||||||
|
/// assert!(encrypted.as_ref().unwrap().len() > 0);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Encrypt a text without providing a custom key:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use encrypted_images::encryption::text::encrypts;
|
||||||
|
///
|
||||||
|
/// let input = "ThisIsJustaTestString";
|
||||||
|
/// let encrypted = encrypts(input, None, None);
|
||||||
|
///
|
||||||
|
/// assert!(encrypted.as_ref().unwrap().len() > 0);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Encrypt a text with advanced security:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use encrypted_images::encryption::text::encrypts;
|
||||||
|
///
|
||||||
|
/// let input = "ThisIsJustaTestString";
|
||||||
|
/// let strength = "advanced";
|
||||||
|
/// let encrypted = encrypts(input, None, Some(strength));
|
||||||
|
///
|
||||||
|
/// assert!(encrypted.as_ref().unwrap().len() > 0);
|
||||||
|
/// ```
|
||||||
|
use rand::{Rng};
|
||||||
|
use rand::rngs::OsRng;
|
||||||
|
use openssl::symm::{encrypt, Cipher};
|
||||||
|
use crate::encryption::text::hmac::calculate_hmac;
|
||||||
|
use subtle::ConstantTimeEq;
|
||||||
|
use base64::{Engine as _, engine::{self, general_purpose}, alphabet};
|
||||||
|
const CUSTOM_ENGINE: engine::GeneralPurpose =
|
||||||
|
engine::GeneralPurpose::new(&alphabet::STANDARD, general_purpose::PAD);
|
||||||
|
|
||||||
|
|
||||||
|
pub fn encrypts(input: &str, key: Option<&str>, strength: Option<&str>) -> Option<String> {
|
||||||
|
let cipher = Cipher::aes_128_cbc();
|
||||||
|
let key = key.unwrap_or("welovenfts");
|
||||||
|
let strength = strength.unwrap_or("default");
|
||||||
|
let iv_bytes = &input.to_string()[..10];
|
||||||
|
let iv: String;
|
||||||
|
if strength == "default" {
|
||||||
|
iv = CUSTOM_ENGINE.encode(iv_bytes);
|
||||||
|
} else {
|
||||||
|
let num_bytes = 10; // Adjust this to the number of random bytes you need
|
||||||
|
let random_bytes = generate_random_bytes(num_bytes);
|
||||||
|
iv = CUSTOM_ENGINE.encode(random_bytes);
|
||||||
|
}
|
||||||
|
let mut padded_key = key.as_bytes().to_vec();
|
||||||
|
while padded_key.len() < 16 {
|
||||||
|
padded_key.push(b'\0');
|
||||||
|
}
|
||||||
|
padded_key.truncate(16);
|
||||||
|
let ciphertext = encrypt(cipher, &padded_key, Some(iv.as_bytes()), input.as_bytes()).unwrap();
|
||||||
|
let hmac = calculate_hmac(&ciphertext, &padded_key);
|
||||||
|
if hmac.ct_eq(&calculate_hmac(&ciphertext, &padded_key)).unwrap_u8() == 1 {
|
||||||
|
let mut result = iv.into_bytes();
|
||||||
|
result.extend_from_slice(&hmac);
|
||||||
|
result.extend_from_slice(&ciphertext);
|
||||||
|
let encoded_result = CUSTOM_ENGINE.encode(&result);
|
||||||
|
Some(encoded_result)
|
||||||
|
} else {
|
||||||
|
println!("Encryption HMAC validation failed");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub mod hmac {
|
||||||
|
pub(crate) fn calculate_hmac(data: &[u8], key: &[u8]) -> Vec<u8> {
|
||||||
|
use openssl::hash::MessageDigest;
|
||||||
|
use openssl::pkey::PKey;
|
||||||
|
use openssl::sign::Signer;
|
||||||
|
let pkey = PKey::hmac(key).unwrap();
|
||||||
|
let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap();
|
||||||
|
signer.update(data).unwrap();
|
||||||
|
signer.sign_to_vec().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn generate_random_bytes(num_bytes: usize) -> Vec<u8> {
|
||||||
|
let mut rng = OsRng;
|
||||||
|
let mut random_bytes = vec![0u8; num_bytes];
|
||||||
|
rng.fill(&mut random_bytes[..]);
|
||||||
|
random_bytes
|
||||||
|
}
|
||||||
|
|
148
src/lib.rs
Normal file
148
src/lib.rs
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
pub mod char_mappings;
|
||||||
|
pub mod encryption;
|
||||||
|
pub mod decryption;
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::char_mappings::maps::mappings::{get_color, numbers_to_letter};
|
||||||
|
use crate::encryption::text::encrypts;
|
||||||
|
use crate::decryption::text::decrypts;
|
||||||
|
use crate::encryption::images::create_img;
|
||||||
|
use crate::decryption::images::decode_image_and_extract_text;
|
||||||
|
use std::time::{Instant, Duration};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_char_conversion() {
|
||||||
|
// Define valid characters for testing
|
||||||
|
let valid_characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=";
|
||||||
|
for character in valid_characters.chars() {
|
||||||
|
// Get the color for the character
|
||||||
|
let color_result = get_color(character);
|
||||||
|
// Get the character back from the color
|
||||||
|
let character_result = numbers_to_letter(color_result.unwrap().0, color_result.unwrap().1, color_result.unwrap().2);
|
||||||
|
// Check if character_result matches the input character
|
||||||
|
assert_eq!(character_result.unwrap(), character);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test invalid characters
|
||||||
|
let invalid_characters = "!@#$%^&*()_";
|
||||||
|
for character in invalid_characters.chars() {
|
||||||
|
// Attempt to get a color for the invalid character
|
||||||
|
let color_result = get_color(character);
|
||||||
|
|
||||||
|
// Ensure the result is None for invalid characters
|
||||||
|
assert_eq!(color_result, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encrypts_decrypts_with_key() {
|
||||||
|
// Input data to encrypt
|
||||||
|
let input = "ThisIsJustaTestString";
|
||||||
|
// Your encryption key (replace with the actual key you use)
|
||||||
|
let key = Some("your_secret_key");
|
||||||
|
// Encrypt the input
|
||||||
|
let encrypted = encrypts(input, key.clone(), None);
|
||||||
|
// Decrypt the encrypted data
|
||||||
|
let decrypted = decrypts(encrypted.as_ref().unwrap(), key);
|
||||||
|
// Assert that decryption matches the original input
|
||||||
|
assert_eq!(decrypted, Some(input.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encrypts_decrypts_without_key() {
|
||||||
|
// Input data to encrypt
|
||||||
|
let input = "ThisIsJustsTestString";
|
||||||
|
// Encrypt the input without a key
|
||||||
|
let encrypted = encrypts(input, None, None);
|
||||||
|
// Decrypt the encrypted data without a key
|
||||||
|
let decrypted = decrypts(encrypted.as_ref().unwrap(), None);
|
||||||
|
// Assert that decryption matches the original input
|
||||||
|
assert_eq!(decrypted, Some(input.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_maximum_length() {
|
||||||
|
// Your encryption key
|
||||||
|
let key = Some("your_secret_key");
|
||||||
|
|
||||||
|
let mut length = 1844674406; // Start with an initial length
|
||||||
|
let max_length = 1844674407; // Set the maximum length
|
||||||
|
while length <= max_length {
|
||||||
|
let encrypted = encrypts(&"A".repeat(length), key.clone(), None);
|
||||||
|
let decrypted = decrypts(encrypted.as_ref().unwrap(), key.clone());
|
||||||
|
|
||||||
|
if decrypted.is_none() {
|
||||||
|
println!("Maximum size: {} characters", length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
length += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_decryption_timing() {
|
||||||
|
let encoded_result = "Your encrypted data"; // Replace with an actual encoded result
|
||||||
|
let key = Some("Your secret key"); // Replace with an actual key
|
||||||
|
// Measure the time for decryption
|
||||||
|
let start_time = Instant::now();
|
||||||
|
let _ = decrypts(encoded_result, key);
|
||||||
|
let end_time = Instant::now();
|
||||||
|
let decryption_time = end_time - start_time;
|
||||||
|
// Ensure that decryption time is within an acceptable range (e.g., less than 1 second)
|
||||||
|
assert!(decryption_time < Duration::from_secs(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_minimum_length() {
|
||||||
|
// minimum 10 characters required to encrypt
|
||||||
|
let input = "aaaaaaaaaa";
|
||||||
|
// Your encryption key
|
||||||
|
let key = Some("your_secret_key");
|
||||||
|
// Encrypt the input
|
||||||
|
let encrypted = encrypts(input, key.clone(), None);
|
||||||
|
// Decrypt the encrypted data
|
||||||
|
let decrypted = decrypts(encrypted.as_ref().unwrap(), key);
|
||||||
|
// Assert that decryption matches the original input
|
||||||
|
assert_eq!(decrypted, Some(input.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_create_img_and_decode() {
|
||||||
|
let ciphertext = "ThisIsJustaTestString";
|
||||||
|
let watermark = "Bitcoin"; // Text watermark
|
||||||
|
let style = "h";
|
||||||
|
|
||||||
|
// Create the image
|
||||||
|
let encoded_image = create_img(ciphertext, style, watermark, None, None, None, None, None, None);
|
||||||
|
|
||||||
|
// Print out the encoded image for debugging
|
||||||
|
println!("Encoded Image: {:?}", encoded_image);
|
||||||
|
|
||||||
|
// Decode the image and extract text
|
||||||
|
let extracted_text = decode_image_and_extract_text(&encoded_image.unwrap());
|
||||||
|
|
||||||
|
// Print out the extracted text for debugging
|
||||||
|
println!("Extracted Text: {:?}", extracted_text);
|
||||||
|
|
||||||
|
// Check if extracted text matches the original ciphertext
|
||||||
|
assert_eq!(extracted_text, Some(ciphertext.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encrypts_decrypts() {
|
||||||
|
// Input data to encrypt
|
||||||
|
let input = "ThisIsJustaTestString";
|
||||||
|
// Your encryption key (replace with the actual key you use)
|
||||||
|
let key = Some("your_secret_key");
|
||||||
|
// Encrypt the input
|
||||||
|
let encrypted = encrypts(input, key.clone(), None);
|
||||||
|
// Print the encrypted string for testing
|
||||||
|
println!("Encrypted: {}", encrypted.as_ref().unwrap());
|
||||||
|
// Decrypt the encrypted data
|
||||||
|
let decrypted = decrypts(encrypted.as_ref().unwrap(), key);
|
||||||
|
// Assert that decryption matches the original input
|
||||||
|
assert_eq!(decrypted, Some(input.to_string()));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user