#encryption-decryption #aes #encryption #decryption #key-derivation #cryptojs

cryptojs_rust

A Rust implementation of CryptoJS encryption/decryption functionality

5 releases

new 0.1.4 Jan 18, 2025
0.1.3 Jan 17, 2025
0.1.2 Jan 15, 2025
0.1.1 Jan 7, 2025
0.1.0 Jan 7, 2025

#1052 in Cryptography

Download history 175/week @ 2025-01-03 138/week @ 2025-01-10

313 downloads per month

MIT license

27KB
485 lines

cryptojs_rust

A Rust implementation of CryptoJS encryption/decryption functionality, focusing on AES encryption compatibility.

Features

  • AES-256 and AES-128 encryption/decryption compatible with CryptoJS
  • Password-based key derivation using PBKDF2-HMAC-SHA256
  • Support for CBC mode encryption (more modes coming soon)
  • CryptoJS-compatible key derivation with salt
  • Base64 encoding/decoding
  • Proper PKCS7 padding handling

Installation

Add this to your Cargo.toml:

[dependencies]
cryptojs_rust = "0.1.4"

Usage Examples

Decrypting data from CryptoJS (Simple example)

use cryptojs_rust::cryptojs;

fn main() {
    let encrypted_data = "U2FsdGVkX1...";
    let password = "xxxxxxx";

    let decrypted = cryptojs::decrypt(&encrypted_data, password.as_bytes());
    println!("Decrypted: {:?}", decrypted);
}

This is the most common and secure way to use the library, as it properly handles key derivation from passwords:

use cryptojs_rust::{Mode, AesEncryptor, AesDecryptor, CryptoOperation};

// Encryption
let password = b"my secret password";
let data = b"Hello, CryptoJS!";

// Create an encryptor with password
let mut encryptor = AesEncryptor::new_256_from_password(password, Mode::CBC).unwrap();
encryptor.update(data).unwrap();
let encrypted = encryptor.finalize().unwrap();

// The encrypted output contains: [16 bytes salt][16 bytes IV][ciphertext]
let salt = &encrypted[..16];
let iv = &encrypted[16..32];
let ciphertext = &encrypted[32..];

// Decryption
let mut decryptor = AesDecryptor::new_256_from_password(
    password,
    Mode::CBC,
    salt,
    Some(iv)
).unwrap();
decryptor.update(ciphertext).unwrap();
let decrypted = decryptor.finalize().unwrap();

assert_eq!(data, &decrypted[..]);

Raw Key Encryption

If you already have a proper-length key (32 bytes for AES-256, 16 bytes for AES-128):

use cryptojs_rust::{Mode, AesEncryptor, AesDecryptor, CryptoOperation};

// Use exact 32-byte key for AES-256
let key = b"12345678901234567890123456789012";
let data = b"Hello, CryptoJS!";

// Encrypt
let mut encryptor = AesEncryptor::new_256(key, Mode::CBC).unwrap();
encryptor.update(data).unwrap();
let encrypted = encryptor.finalize().unwrap();

// The encrypted output contains: [16 bytes IV][ciphertext]
let iv = &encrypted[..16];
let ciphertext = &encrypted[16..];

// Decrypt
let mut decryptor = AesDecryptor::new_256(key, Mode::CBC, Some(iv)).unwrap();
decryptor.update(ciphertext).unwrap();
let decrypted = decryptor.finalize().unwrap();

assert_eq!(data, &decrypted[..]);

Working with Base64

When exchanging encrypted data, it's common to use base64 encoding:

use base64::{Engine, engine::general_purpose::STANDARD};
use cryptojs_rust::{Mode, AesEncryptor, CryptoOperation};

// Encrypt and base64 encode
let mut encryptor = AesEncryptor::new_256_from_password(b"password", Mode::CBC).unwrap();
encryptor.update(b"secret data").unwrap();
let encrypted = encryptor.finalize().unwrap();
let base64_data = STANDARD.encode(&encrypted);

// Now base64_data can be safely transmitted or stored
println!("Encrypted (base64): {}", base64_data);

Compatibility with CryptoJS

The library is designed to be compatible with CryptoJS's AES encryption. When using password-based encryption:

  1. The key is derived using PBKDF2-HMAC-SHA256 with 10,000 iterations
  2. A random 16-byte salt is generated for each encryption
  3. A random 16-byte IV is used for CBC mode
  4. The output format is: [salt (16 bytes)][iv (16 bytes)][ciphertext]
  5. The final output is typically base64 encoded for storage or transmission

Security Considerations

  • Always use password-based encryption (new_256_from_password) unless you have a specific reason to use raw keys
  • The raw key methods (new_256, new_128) should only be used when you have proper key generation and management
  • The library uses secure defaults:
    • PBKDF2-HMAC-SHA256 with 10,000 iterations for key derivation
    • Random salt for each encryption
    • Random IV for each encryption
    • CBC mode with PKCS7 padding

Changelog

Version 0.1.4 (Latest)

  • Fixed Node.js compatibility for password-based encryption
  • Updated Node.js decryption example to properly handle salt and IV
  • Clarified the encrypted data format: [salt (16 bytes)][iv (16 bytes)][ciphertext]
  • Added detailed Node.js decryption example:
const CryptoJS = require('crypto-js');

function decryptFromRust(encryptedBase64, password) {
    // Decode base64
    const encryptedBytes = Buffer.from(encryptedBase64, 'base64');
    
    // Extract salt (first 16 bytes), IV (next 16 bytes) and ciphertext
    const salt = encryptedBytes.subarray(0, 16);
    const iv = encryptedBytes.subarray(16, 32);
    const ciphertext = encryptedBytes.subarray(32);
    
    // Convert to CryptoJS format
    const ciphertextWA = CryptoJS.lib.WordArray.create(ciphertext);
    const ivWA = CryptoJS.lib.WordArray.create(iv);
    const saltWA = CryptoJS.lib.WordArray.create(salt);
    
    // Create key using PBKDF2 (matching Rust parameters)
    const key = CryptoJS.PBKDF2(password, saltWA, {
        keySize: 256/32,
        iterations: 10000,
        hasher: CryptoJS.algo.SHA256
    });
    
    // Decrypt
    const decrypted = CryptoJS.AES.decrypt(
        { ciphertext: ciphertextWA },
        key,
        {
            iv: ivWA,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        }
    );
    
    return decrypted.toString(CryptoJS.enc.Utf8);
}

Version 0.1.3

  • Initial public release
  • AES-256 and AES-128 encryption/decryption
  • Password-based key derivation using PBKDF2
  • CBC mode support
  • Base64 encoding/decoding

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Security

This crate implements cryptographic functionality. While we strive for correctness and security, this implementation has not been audited. Use at your own risk in production environments.

Dependencies

~1.9–3MB
~61K SLoC