Initial Commit
This commit is contained in:
commit
ef7473a29e
5 changed files with 381 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
132
Cargo.lock
generated
Normal file
132
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rs-random"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
22
Cargo.toml
Normal file
22
Cargo.toml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
[package]
|
||||
name = "rs-random"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
rand = { version = "0.8", default-features = false, features = ["std_rng", "getrandom"] }
|
||||
|
||||
[profile.release]
|
||||
opt-level = "z" # Optimize aggressively for size
|
||||
lto = true # Link-time optimization
|
||||
codegen-units = 1 # Maximum optimization opportunities
|
||||
panic = "abort" # Smaller panic handling
|
||||
strip = true # Strip symbols (Rust 1.59+)
|
||||
overflow-checks = false # Disable overflow checks for size
|
||||
debug = false # No debug info
|
||||
debug-assertions = false # No debug assertions
|
||||
incremental = false # Disable incremental compilation
|
||||
rpath = false # Don't use rpath
|
||||
|
||||
[profile.release.package."*"]
|
||||
opt-level = "z" # Apply size optimization to all dependencies
|
||||
69
README.md
Normal file
69
README.md
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# rs-random
|
||||
|
||||
**Secure String Generator**
|
||||
|
||||
A minimal, blazing-fast Rust command-line tool for generating secure random strings with the tiniest possible footprint. Perfect for standalone use or integration into other applications.
|
||||
|
||||
## Features
|
||||
|
||||
- Uses operating system entropy (`OsRng`) for cryptographically secure randomness
|
||||
- Very small binary size (optimized release profile)
|
||||
- Minimal dependencies (only the `rand` crate with `std_rng` and `getrandom` features)
|
||||
- Flexible selection of character sets, including alphabets, numbers, symbols, and more
|
||||
|
||||
## About
|
||||
|
||||
I created `rs-random` to have a super simple, minimal way to generate secure strings that I could build into other applications, ensuring security, speed, and a tiny footprint.
|
||||
|
||||
## Installation
|
||||
|
||||
### From Source
|
||||
|
||||
```bash
|
||||
git clone https://git.caileb.com/Caileb/rs-random.git
|
||||
cd rs-random
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
rs-random [LENGTH]
|
||||
rs-random -l <LENGTH> [-s <SETS>] [-c <COUNT>]
|
||||
rs-random -h | --help
|
||||
```
|
||||
|
||||
- `LENGTH` <number>: Length of each string (default: `16`)
|
||||
- `-l, --length <LENGTH>`: Specify the string length
|
||||
- `-s, --sets <SETS>`: Comma-separated list of character sets to include (default: `lowercase,uppercase,numbers,special-safe`)
|
||||
- `-c, --count <COUNT>`: Number of strings to generate (default: `1`)
|
||||
- `-h, --help`: Show help information
|
||||
|
||||
### Available Character Sets
|
||||
|
||||
| Name | Description |
|
||||
| ---------------- | ---------------------------------------- |
|
||||
| lowercase | English lowercase letters (a-z) |
|
||||
| uppercase | English uppercase letters (A-Z) |
|
||||
| numbers | Numbers (0-9) |
|
||||
| special | Special characters |
|
||||
| special-safe | Safe special chars (no pipes/brackets) |
|
||||
| cyrillic-lower | Cyrillic lowercase letters |
|
||||
| cyrillic-upper | Cyrillic uppercase letters |
|
||||
| greek-lower | Greek lowercase letters |
|
||||
| greek-upper | Greek uppercase letters |
|
||||
| symbols | Extended symbols (©®, ™, €, £, etc.) |
|
||||
|
||||
### Examples
|
||||
|
||||
Generate a single 32-character string (default sets):
|
||||
|
||||
```bash
|
||||
rs-random 32
|
||||
```
|
||||
|
||||
Generate five 12-character strings using only lowercase and numbers:
|
||||
|
||||
```bash
|
||||
rs-random -l 12 -s lowercase,numbers -c 5
|
||||
```
|
||||
157
src/main.rs
Normal file
157
src/main.rs
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
use rand::{rngs::OsRng, seq::SliceRandom};
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::process;
|
||||
|
||||
static CHARACTER_SETS: [(&str, &str, &str); 10] = [
|
||||
("lowercase", "abcdefghijklmnopqrstuvwxyz", "English lowercase letters (a-z)"),
|
||||
("uppercase", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "English uppercase letters (A-Z)"),
|
||||
("numbers", "0123456789", "Numbers (0-9)"),
|
||||
("special", "!@#$%^&*()_+-=[]{}|;:,.<>?", "Special characters"),
|
||||
("special-safe", "!@#$%^&*_+-=<>?", "Safe special chars (no pipes/brackets)"),
|
||||
("cyrillic-lower", "абвгдежзийклмнопрстуфхцчшщъыьэюя", "Cyrillic lowercase"),
|
||||
("cyrillic-upper", "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "Cyrillic uppercase"),
|
||||
("greek-lower", "αβγδεζηθικλμνξοπρστυφχψω", "Greek lowercase"),
|
||||
("greek-upper", "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ", "Greek uppercase"),
|
||||
("symbols", "©®™€£¥§¶†‡•…‰′″‹›\"\'–—", "Extended symbols"),
|
||||
];
|
||||
|
||||
fn print_help() {
|
||||
println!("rs-random: Secure String Generator\n");
|
||||
println!("Usage:");
|
||||
println!(" rs-random [LENGTH] (uses safe defaults)");
|
||||
println!(" rs-random -l <LEN> [-s <SETS>] [-c <COUNT>]");
|
||||
println!(" rs-random -h | --help\n");
|
||||
println!("Available sets (for -s, comma-separated):");
|
||||
for &(name, _, desc) in &CHARACTER_SETS {
|
||||
println!(" {:<15} - {}", name, desc);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_chars(selected_sets: &[&str]) -> Result<Vec<char>, String> {
|
||||
let mut all_chars = Vec::new();
|
||||
let mut unknown = Vec::new();
|
||||
|
||||
for &set_name in selected_sets {
|
||||
match CHARACTER_SETS.iter().find(|&&(name, _, _)| name == set_name) {
|
||||
Some(&(_, chars, _)) => all_chars.extend(chars.chars()),
|
||||
None => unknown.push(set_name),
|
||||
}
|
||||
}
|
||||
|
||||
if !unknown.is_empty() {
|
||||
return Err(format!("Unknown sets: {}", unknown.join(",")));
|
||||
}
|
||||
if all_chars.is_empty() {
|
||||
return Err("Empty character pool".to_string());
|
||||
}
|
||||
|
||||
// Remove duplicates
|
||||
let mut unique_chars = Vec::new();
|
||||
let mut seen = HashSet::new();
|
||||
for ch in all_chars {
|
||||
if seen.insert(ch) {
|
||||
unique_chars.push(ch);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(unique_chars)
|
||||
}
|
||||
|
||||
fn generate_random_string(chars: &[char], length: usize) -> String {
|
||||
let mut rng = OsRng;
|
||||
(0..length)
|
||||
.map(|_| *chars.choose(&mut rng).unwrap())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
||||
if args.len() < 2 || args.contains(&"-h".to_string()) || args.contains(&"--help".to_string()) {
|
||||
print_help();
|
||||
return;
|
||||
}
|
||||
|
||||
let mut length = 16;
|
||||
let mut count = 1;
|
||||
let mut sets = "lowercase,uppercase,numbers,special-safe";
|
||||
|
||||
let mut i = 1;
|
||||
while i < args.len() {
|
||||
match args[i].as_str() {
|
||||
"-l" | "--length" => {
|
||||
if i + 1 < args.len() {
|
||||
if let Ok(n) = args[i + 1].parse::<usize>() {
|
||||
length = n;
|
||||
} else {
|
||||
eprintln!("Error: Invalid length");
|
||||
process::exit(1);
|
||||
}
|
||||
i += 2;
|
||||
} else {
|
||||
eprintln!("Error: Missing length value");
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
"-s" | "--sets" => {
|
||||
if i + 1 < args.len() {
|
||||
sets = &args[i + 1];
|
||||
i += 2;
|
||||
} else {
|
||||
eprintln!("Error: Missing sets value");
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
"-c" | "--count" => {
|
||||
if i + 1 < args.len() {
|
||||
if let Ok(n) = args[i + 1].parse::<usize>() {
|
||||
count = n;
|
||||
} else {
|
||||
eprintln!("Error: Invalid count");
|
||||
process::exit(1);
|
||||
}
|
||||
i += 2;
|
||||
} else {
|
||||
eprintln!("Error: Missing count value");
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
arg if i == 1 && !arg.starts_with("-") => {
|
||||
if let Ok(n) = arg.parse::<usize>() {
|
||||
length = n;
|
||||
} else {
|
||||
eprintln!("Error: Invalid length");
|
||||
process::exit(1);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
_ => {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if length == 0 {
|
||||
eprintln!("Error: Length must be > 0");
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let selected_sets: Vec<&str> = sets.split(',').map(|s| s.trim()).filter(|s| !s.is_empty()).collect();
|
||||
|
||||
match get_chars(&selected_sets) {
|
||||
Ok(chars) => {
|
||||
for i in 0..count {
|
||||
let random_string = generate_random_string(&chars, length);
|
||||
if count > 1 {
|
||||
print!("{}: ", i + 1);
|
||||
}
|
||||
println!("{}", random_string);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error: {}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue