| Crates.io | ironcrypt |
| lib.rs | ironcrypt |
| version | 0.1.0 |
| created_at | 2025-08-16 21:10:02.35533+00 |
| updated_at | 2025-08-16 21:10:02.35533+00 |
| description | A Rust library for secure password hashing, RSA key generation, and managing the encryption and verification of passwords and binary files. |
| homepage | |
| repository | https://github.com/teamflp/ironcrypt |
| max_upload_size | |
| id | 1798904 |
| size | 1,614,093 |
IronCrypt is a Command-Line Interface (CLI) tool and Rust library dedicated to secure password and data encryption. By combining the Argon2 hashing algorithm, AES-256-GCM encryption, and RSA for key management, IronCrypt provides a robust solution to ensure your application’s data confidentiality and password security.
-v v1, -v v2) and the dedicated rotate-key command allow you to update your encryption keys over time. This automates the process of migrating to a new key without having to manually decrypt and re-encrypt all your data. IronCrypt can load both modern PKCS#8 keys and legacy PKCS#1 keys, ensuring broad compatibility.ironcrypt.toml file, environment variables, or the IronCryptConfig struct in code. This includes RSA key size and the computational "costs" of the Argon2 algorithm, allowing you to balance security and performance to fit your needs.
This process ensures maximum security by combining robust hashing with Argon2 and hybrid encryption (called "envelope encryption") with AES and RSA.
The goal here is not to encrypt the password itself, but to encrypt a unique fingerprint (a "hash") of that password. The plaintext password is never stored.
Password Hashing:
"MyPassword123") is first passed through the Argon2 hashing algorithm.Creating the Encryption Envelope:
Securing the AES Key (the "seal" of the envelope):
Storing the Secure Data:
The goal here is to verify if the password provided by the user matches the stored one, without ever having to see it in plaintext.
Data Retrieval:
"MyPassword123").Opening the Envelope:
Real-time Hashing and Comparison:
Verification Result:
This workflow ensures that even if your database were compromised, the users' passwords would remain unusable by an attacker, as the original password is never stored there.

This process also uses envelope encryption (AES + RSA) to ensure both performance and security.
my_document.enc)..enc file (the JSON) is read.
Encrypting an entire directory is based on the file encryption workflow, with an additional preparation step.
.tar.gz file)..tar.gz archive is then treated as a simple binary file..tar.gz archive..tar.gz archive is then decompressed, and its contents are extracted to the destination directory, thus recreating the original structure and files.There are three main ways to run the ironcrypt command-line tool.
cargo run (Recommended for development)This command compiles and runs the program in one step. Use -- to separate cargo's arguments from your program's arguments.
# Clone the repository
git clone https://github.com/teamflp/ironcrypt.git
cd ironcrypt
# Run the --help command
cargo run -- --help
You can build the executable and then run it from its path in the target directory.
# Build the optimized release executable
cargo build --release
# Run it from its path
./target/release/ironcrypt --help
This will install the ironcrypt command on your system, making it available from any directory. This is the best option for regular use.
# From the root of the project directory, run:
cargo install --path .
# Now you can use the command from anywhere
ironcrypt --help
Here is a summary table of all available commands:
| Command | Alias | Description | Key Options |
|---|---|---|---|
generate |
Generates a new RSA key pair. | -v, --version <VERSION> -d, --directory <DIR> -s, --key-size <SIZE> |
|
encrypt |
Hashes and encrypts a password. | -w, --password <PASSWORD> -d, --public-key-directory <DIR> -v, --key-version <VERSION> |
|
decrypt |
Verifies an encrypted password. | -w, --password <PASSWORD> -k, --private-key-directory <DIR> -v, --key-version <VERSION> -f, --file <FILE> |
|
encrypt-file |
encfile, efile, ef |
Encrypts a binary file. | -i, --input-file <INPUT> -o, --output-file <OUTPUT> -d, --public-key-directory <DIR> -v, --key-version <VERSION> [-w, --password <PASSWORD>] |
decrypt-file |
decfile, dfile, df |
Decrypts a binary file. | -i, --input-file <INPUT> -o, --output-file <OUTPUT> -k, --private-key-directory <DIR> -v, --key-version <VERSION> [-w, --password <PASSWORD>] |
encrypt-dir |
encdir |
Encrypts an entire directory. | -i, --input-dir <INPUT> -o, --output-file <OUTPUT> -d, --public-key-directory <DIR> -v, --key-version <VERSION> [-w, --password <PASSWORD>] |
decrypt-dir |
decdir |
Decrypts an entire directory. | -i, --input-file <INPUT> -o, --output-dir <OUTPUT> -k, --private-key-directory <DIR> -v, --key-version <VERSION> [-w, --password <PASSWORD>] |
rotate-key |
rk |
Rotates encryption keys for encrypted data. | --old-version <OLD_V> --new-version <NEW_V> -k, --key-directory <DIR> --file <FILE> or --directory <DIR> |
A full list of commands and their arguments can be viewed by running ironcrypt --help. To get help for a specific command, run ironcrypt <command> --help.
generateGenerates a new RSA key pair (private and public).
Usage:
ironcrypt generate --version <VERSION> [--directory <DIR>] [--key-size <SIZE>]
Example:
# Generate a new v2 key with a size of 4096 bits in the "my_keys" directory
ironcrypt generate -v v2 -d my_keys -s 4096
encryptHashes and encrypts a password.
Usage:
ironcrypt encrypt --password <PASSWORD> --public-key-directory <DIR> --key-version <VERSION>
Example:
# Encrypt a password using the v1 public key
ironcrypt encrypt -w "My$trongP@ssw0rd" -d keys -v v1
decryptDecrypts and verifies a password.
Usage:
ironcrypt decrypt --password <PASSWORD> --private-key-directory <DIR> --key-version <VERSION> --file <FILE>
Example:
# Verify a password using the v1 private key and the encrypted data from a file
ironcrypt decrypt -w "My$trongP@ssw0rd" -k keys -v v1 -f encrypted_data.json
encrypt-fileEncrypts a single file.
Usage:
ironcrypt encrypt-file -i <INPUT> -o <OUTPUT> -d <KEY_DIR> -v <VERSION> [-w <PASSWORD>]
Example:
# Encrypt a file with the v1 public key
ironcrypt encrypt-file -i my_document.pdf -o my_document.enc -d keys -v v1
# Encrypt a file with a password as well
ironcrypt encrypt-file -i my_secret.zip -o my_secret.enc -d keys -v v1 -w "ExtraL@yerOfS3curity"
decrypt-fileDecrypts a single file.
Usage:
ironcrypt decrypt-file -i <INPUT> -o <OUTPUT> -k <KEY_DIR> -v <VERSION> [-w <PASSWORD>]
Example:
# Decrypt a file with the v1 private key
ironcrypt decrypt-file -i my_document.enc -o my_document.pdf -k keys -v v1
# Decrypt a file that was also encrypted with a password
ironcrypt decrypt-file -i my_secret.enc -o my_secret.zip -k keys -v v1 -w "ExtraL@yerOfS3curity"
encrypt-dirEncrypts an entire directory by first archiving it into a .tar.gz.
Usage:
ironcrypt encrypt-dir -i <INPUT_DIR> -o <OUTPUT_FILE> -d <KEY_DIR> -v <VERSION> [-w <PASSWORD>]
Example:
# Encrypt the "my_project" directory
ironcrypt encrypt-dir -i ./my_project -o my_project.enc -d keys -v v1
decrypt-dirDecrypts and extracts a directory.
Usage:
ironcrypt decrypt-dir -i <INPUT_FILE> -o <OUTPUT_DIR> -k <KEY_DIR> -v <VERSION> [-w <PASSWORD>]
Example:
# Decrypt the "my_project.enc" file into the "decrypted_project" directory
ironcrypt decrypt-dir -i my_project.enc -o ./decrypted_project -k keys -v v1
rotate-keyRotates encryption keys for a file or a directory of files.
Usage:
ironcrypt rotate-key --old-version <OLD_V> --new-version <NEW_V> --key-directory <DIR> [--file <FILE> | --directory <DIR>]
Example:
# Rotate keys from v1 to v2 for a single file
ironcrypt rotate-key --old-version v1 --new-version v2 -k keys --file my_document.enc
# Rotate keys from v1 to v2 for all files in the "encrypted_files" directory
ironcrypt rotate-key --old-version v1 --new-version v2 -k keys -d ./encrypted_files
You can also use ironcrypt as a library in your Rust projects. Add it to your Cargo.toml:
[dependencies]
ironcrypt = "0.1.0" # Replace with the desired version from crates.io
use ironcrypt::{IronCrypt, IronCryptConfig, IronCryptError};
fn main() -> Result<(), IronCryptError> {
// Initialize IronCrypt
let config = IronCryptConfig::default();
let crypt = IronCrypt::new("keys", "v1", config)?;
// Encrypt a password
let password = "My$ecureP@ssw0rd!";
let encrypted_data = crypt.encrypt_password(password)?;
println!("Password encrypted!");
// Verify the password
let is_valid = crypt.verify_password(&encrypted_data, password)?;
assert!(is_valid);
println!("Password verification successful!");
// Clean up keys for this example
std::fs::remove_dir_all("keys")?;
Ok(())
}
use ironcrypt::{IronCrypt, IronCryptConfig, IronCryptError};
use std::fs;
fn main() -> Result<(), IronCryptError> {
// Initialize IronCrypt
let config = IronCryptConfig::default();
let crypt = IronCrypt::new("keys", "v1", config)?;
// Encrypt a file
let file_data = b"This is the content of my secret file.";
let encrypted_file = crypt.encrypt_binary_data(file_data, "file_password")?;
fs::write("secret.enc", encrypted_file).unwrap();
println!("File encrypted!");
// Decrypt the file
let encrypted_content = fs::read_to_string("secret.enc").unwrap();
let decrypted_data = crypt.decrypt_binary_data(&encrypted_content, "file_password")?;
assert_eq!(file_data, &decrypted_data[..]);
println!("File decrypted successfully!");
// Clean up
std::fs::remove_dir_all("keys")?;
std::fs::remove_file("secret.enc")?;
Ok(())
}
Here are some examples of how to use ironcrypt with popular web frameworks and a PostgreSQL database. These examples use the sqlx crate for database interaction.
This example shows how to create a simple web service with actix-web that can register and log in users.
Dependencies:
[dependencies]
ironcrypt = "0.1.0"
actix-web = "4"
sqlx = { version = "0.7", features = ["runtime-async-std-native-tls", "postgres"] }
serde = { version = "1.0", features = ["derive"] }
Code:
use actix_web::{web, App, HttpServer, Responder, HttpResponse};
use sqlx::postgres::PgPoolOptions;
use sqlx::PgPool;
use ironcrypt::{IronCrypt, IronCryptConfig};
use serde::Deserialize;
#[derive(Deserialize)]
struct User {
username: String,
password: String,
}
async fn register(user: web::Json<User>, pool: web::Data<PgPool>, crypt: web::Data<IronCrypt>) -> impl Responder {
let encrypted_password = match crypt.encrypt_password(&user.password) {
Ok(p) => p,
Err(_) => return HttpResponse::InternalServerError().finish(),
};
let result = sqlx::query("INSERT INTO users (username, password) VALUES ($1, $2)")
.bind(&user.username)
.bind(&encrypted_password)
.execute(pool.get_ref())
.await;
match result {
Ok(_) => HttpResponse::Ok().body("User created"),
Err(_) => HttpResponse::InternalServerError().finish(),
}
}
async fn login(user: web::Json<User>, pool: web::Data<PgPool>, crypt: web::Data<IronCrypt>) -> impl Responder {
let result: Result<(String,), sqlx::Error> = sqlx::query_as("SELECT password FROM users WHERE username = $1")
.bind(&user.username)
.fetch_one(pool.get_ref())
.await;
let stored_password = match result {
Ok((p,)) => p,
Err(_) => return HttpResponse::Unauthorized().finish(),
};
match crypt.verify_password(&stored_password, &user.password) {
Ok(true) => HttpResponse::Ok().body("Login successful"),
Ok(false) => HttpResponse::Unauthorized().finish(),
Err(_) => HttpResponse::InternalServerError().finish(),
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let database_url = "postgres://user:password@localhost/database";
let pool = PgPoolOptions::new()
.max_connections(5)
.connect(&database_url)
.await
.expect("Failed to create pool.");
let config = IronCryptConfig::default();
let crypt = IronCrypt::new("keys", "v1", config).expect("Failed to initialize IronCrypt");
sqlx::query(
"CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL
)"
)
.execute(&pool)
.await
.expect("Failed to create table.");
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(pool.clone()))
.app_data(web::Data::new(crypt.clone()))
.route("/register", web::post().to(register))
.route("/login", web::post().to(login))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
This example shows how to achieve the same functionality using the rocket framework.
Dependencies:
[dependencies]
ironcrypt = "0.1.0"
rocket = { version = "0.5.0-rc.2", features = ["json"] }
sqlx = { version = "0.7", features = ["runtime-tokio-native-tls", "postgres"] }
serde = { version = "1.0", features = ["derive"] }
Code:
#[macro_use] extern crate rocket;
use rocket::serde::json::Json;
use rocket::State;
use sqlx::postgres::PgPoolOptions;
use sqlx::PgPool;
use ironcrypt::{IronCrypt, IronCryptConfig};
use serde::Deserialize;
#[derive(Deserialize)]
struct User {
username: String,
password: String,
}
#[post("/register", data = "<user>")]
async fn register(user: Json<User>, pool: &State<PgPool>, crypt: &State<IronCrypt>) -> Result<String, rocket::response::status::Custom<String>> {
let encrypted_password = crypt.encrypt_password(&user.password).map_err(|e| rocket::response::status::Custom(rocket::http::Status::InternalServerError, e.to_string()))?;
sqlx::query("INSERT INTO users (username, password) VALUES ($1, $2)")
.bind(&user.username)
.bind(&encrypted_password)
.execute(&**pool)
.await
.map_err(|e| rocket::response::status::Custom(rocket::http::Status::InternalServerError, e.to_string()))?;
Ok("User created".to_string())
}
#[post("/login", data = "<user>")]
async fn login(user: Json<User>, pool: &State<PgPool>, crypt: &State<IronCrypt>) -> Result<String, rocket::response::status::Custom<String>> {
let result: (String,) = sqlx::query_as("SELECT password FROM users WHERE username = $1")
.bind(&user.username)
.fetch_one(&**pool)
.await
.map_err(|_| rocket::response::status::Custom(rocket::http::Status::Unauthorized, "User not found".to_string()))?;
let stored_password = result.0;
if crypt.verify_password(&stored_password, &user.password).unwrap_or(false) {
Ok("Login successful".to_string())
} else {
Err(rocket::response::status::Custom(rocket::http::Status::Unauthorized, "Invalid credentials".to_string()))
}
}
#[launch]
async fn rocket() -> _ {
let database_url = "postgres://user:password@localhost/database";
let pool = PgPoolOptions::new()
.max_connections(5)
.connect(&database_url)
.await
.expect("Failed to create pool.");
let config = IronCryptConfig::default();
let crypt = IronCrypt::new("keys", "v1", config).expect("Failed to initialize IronCrypt");
sqlx::query(
"CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL
)"
)
.execute(&pool)
.await
.expect("Failed to create table.");
rocket::build()
.manage(pool)
.manage(crypt)
.mount("/", routes![register, login])
}
IronCrypt can be configured in three ways, in order of precedence:
ironcrypt.toml file: Create this file in the directory where you run the command.IRONCRYPT_KEY_DIRECTORY.--key-directory override all other methods.For library usage, you can construct an IronCryptConfig struct and pass it to IronCrypt::new.
rotate-key command to update your encryption keys periodically.Contributions are welcome! If you'd like to contribute, please follow these steps:
IronCrypt is licensed under the MIT License. See the LICENSE file for details.