Add files via upload
This commit is contained in:
parent
211d50b36c
commit
32e3d100fe
|
|
@ -1,9 +1,10 @@
|
|||
[package]
|
||||
name = "encrypted_images"
|
||||
version = "1.2.0"
|
||||
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"] }
|
||||
|
|
@ -15,3 +16,4 @@ sha2 = "0.10.7"
|
|||
hex-literal = "0.4.1"
|
||||
encoding = "0.2"
|
||||
subtle = "2.4"
|
||||
rand = "0.8.5"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
Support this developers open source efforts:
|
||||
|
||||
bitcoin: bc1pf0s98gva7la6r9srepywwr4llqea8t0r4fj8qkdqqac0f9y5624sxpsmqq
|
||||
ethereum: 0x78046716a783B94240ff6b4Ba6580F6D5690423A
|
||||
cardano: addr1q8dxlqu824ghzn3extm8zjqzmr2u5fy4p0jpaqs6w8jpt4wkpgtm6wkc0me3gmgfgdadnpzdcj24yz3znme5w7kvm8vs0thea2
|
||||
solana: HG1fpdqHkxSUyT85V6LGu8dbC3BK4JixiivjYLHVsazQ
|
||||
tezos: tz2TL7ke3xyxWi4JbS6egscmpEP9Z9XrV86y
|
||||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
|
@ -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."),
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -3,6 +3,11 @@
|
|||
/// 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.
|
||||
|
|
@ -25,15 +30,17 @@
|
|||
/// ```
|
||||
use subtle::ConstantTimeEq;
|
||||
use openssl::symm::{decrypt, Cipher};
|
||||
use base64::decode;
|
||||
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 = decode(encoded_result).ok()?;
|
||||
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..];
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,9 +1,25 @@
|
|||
/// Encrypts the input text with an optional encryption key.
|
||||
/// 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:
|
||||
|
|
@ -12,8 +28,8 @@
|
|||
/// use encrypted_images::encryption::text::encrypts;
|
||||
///
|
||||
/// let input = "ThisIsJustaTestString";
|
||||
/// let key = Some("your_secret_key");
|
||||
/// let encrypted = encrypts(input, key);
|
||||
/// let key = "your_secret_key";
|
||||
/// let encrypted = encrypts(input, Some(key), None);
|
||||
///
|
||||
/// assert!(encrypted.as_ref().unwrap().len() > 0);
|
||||
/// ```
|
||||
|
|
@ -24,42 +40,63 @@
|
|||
/// use encrypted_images::encryption::text::encrypts;
|
||||
///
|
||||
/// let input = "ThisIsJustaTestString";
|
||||
/// let encrypted = encrypts(input, None);
|
||||
/// 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 base64::encode;
|
||||
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>) -> Option<String> {
|
||||
|
||||
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 = base64::encode(iv_bytes);
|
||||
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();
|
||||
|
||||
// Calculate HMAC
|
||||
let hmac = calculate_hmac(&ciphertext, &padded_key);
|
||||
|
||||
// Constant-time compare HMAC to protect against timing attacks
|
||||
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 = encode(&result);
|
||||
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;
|
||||
|
|
@ -71,3 +108,10 @@
|
|||
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
|
||||
}
|
||||
|
||||
|
|
|
|||
25
src/lib.rs
25
src/lib.rs
|
|
@ -2,6 +2,7 @@
|
|||
pub mod encryption;
|
||||
pub mod decryption;
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::char_mappings::maps::mappings::{get_color, numbers_to_letter};
|
||||
|
|
@ -14,7 +15,7 @@
|
|||
#[test]
|
||||
fn test_char_conversion() {
|
||||
// Define valid characters for testing
|
||||
let valid_characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/";
|
||||
let valid_characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=";
|
||||
for character in valid_characters.chars() {
|
||||
// Get the color for the character
|
||||
let color_result = get_color(character);
|
||||
|
|
@ -42,7 +43,7 @@
|
|||
// 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());
|
||||
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
|
||||
|
|
@ -54,7 +55,7 @@
|
|||
// Input data to encrypt
|
||||
let input = "ThisIsJustsTestString";
|
||||
// Encrypt the input without a key
|
||||
let encrypted = encrypts(input, None);
|
||||
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
|
||||
|
|
@ -69,7 +70,7 @@
|
|||
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());
|
||||
let encrypted = encrypts(&"A".repeat(length), key.clone(), None);
|
||||
let decrypted = decrypts(encrypted.as_ref().unwrap(), key.clone());
|
||||
|
||||
if decrypted.is_none() {
|
||||
|
|
@ -100,7 +101,7 @@
|
|||
// Your encryption key
|
||||
let key = Some("your_secret_key");
|
||||
// Encrypt the input
|
||||
let encrypted = encrypts(input, key.clone());
|
||||
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
|
||||
|
|
@ -111,10 +112,20 @@
|
|||
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, watermark);
|
||||
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()));
|
||||
}
|
||||
|
|
@ -126,7 +137,7 @@
|
|||
// 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());
|
||||
let encrypted = encrypts(input, key.clone(), None);
|
||||
// Print the encrypted string for testing
|
||||
println!("Encrypted: {}", encrypted.as_ref().unwrap());
|
||||
// Decrypt the encrypted data
|
||||
|
|
|
|||
Loading…
Reference in New Issue