How Do You Slow Down Rust? Use the PBKDF2 solution

So sorry for confusion in the title. But, by “Rust” I mean the programming language, and by “the PBKDF2 solution” I focusing on the process…

Photo by Zdeněk Macháček on Unsplash

How Do You Slow Down Rust? Use the PBKDF2 solution

So sorry for confusion in the title. But, by “Rust” I mean the programming language, and by “the PBKDF2 solution” I focusing on the process of slowing the hashing of your password.

PBKDF2 (Password-Based Key Derivation Function 2) is defined in RFC 2898 and generates a salted hash. Often this is used to create an encryption key from a defined password, and where it is not possible to reverse the password from the hashed value. It is used in TrueCrypt to generate the key required to read the header information of the encrypted drive, and which stores the encryption keys. Overall it is used in many applications, such as in protecting your password within Wi-fi networks.

In many applications we need to generate an encryption key. For this we could create a random key, but we would need to store it, and where it could be discovered. A typical method is thus to use a Key Derivation Function (KDF) with a salt value in order to generate a hashed value, and then use this hash to generate the encryption. As this method would be open to brute force, we often use a method which will slow the hashing process down, and defeat a hash cracker based on parallel processing. This is normally implemented using a hashing loop, and where we hash over a number of rounds. Typical methods are PBKDF2, bcrypt and scrypt, as these are more robust against default hash crackers. This page implements these methods with a given salt value, along with including HKDF, and which is not recommended for generating encryption keys.

In computing, we often need things to be fast, but sometimes we need to slow things down and create a problem that cannot be scaled onto parallel processors. One of these applications is in the hashing of a password. The fast hash crackers can process SHA-1 and SHA-256 hashes at rates that can be over 1 terahashes per second. That’s 1,000 billion passwords tried every second. These crackers often run on Cloud-based systems and use GPUs with over 4,000 cores.

In many applications, we need to generate an encryption key. For this, we could create a random key, but we would need to store it, and where it could be discovered. A typical alternative method is thus to use a Key Derivation Function (KDF) with a salt value in order to generate a hashed value and then use this hash to generate the encryption key. As this method would be open to brute force, we often use a method that will slow the hashing process down, and defeat a hash cracker using parallel processing. This increased difficulity is normally implemented using a hashing loop, and where we hash over a number of rounds. Typical methods are PBKDF2 (Password-Based Key Derivation Function 2), bcrypt and scrypt, as these are more robust against default hash crackers. A sample run here shows some of the speeds:

Method:   Hashes per second
SHA-1: 588235
SHA-256: 602409
SHA-512: 75216
MD5: 606060
SHA-3 (224-bit): 331674
DES: 396
Bcrypt: 215
APR1: 692
PBKDF2 (SHA1): 4884
PBKDF2 (SHA-256): 9648

LM Hash: 2480
NT Hash: 33112
MS DCC: 53361
LDAP (MD5): 11928
LDAP (SHA1): 48828
MS SQL 2000: 16654
MySQL: 30769
Oracle 10: 201
Postgres (MD5): 23900
Cisco PIX: 16297
Cisco Type 7: 16223
Murmur: 2499999

A Rust implementation

Rust is one of the most secure and robust programming environments, and which compiles to navite code. An outline of the Rust code is [here]:

extern crate crypto;
use crypto::pbkdf2::{pbkdf2_check, pbkdf2_simple};
use std::env;
fn main() {
let mut c=1;
    let mut inpass = String::from("Hello world!");
    let args: Vec<String> = env::args().collect();

if args.len() >1 { inpass = args[1].clone();}
if args.len() >2 { c = args[2].trim().parse().unwrap(); }
    if (c>10000) {return;}
    let pass: &str = &inpass[..];
    let out=pbkdf2_simple(pass,c).unwrap().to_string();
println!("Password: {}",pass);
println!("Count: {}",c);
println!("\nPBKDF2: {}",out);
   let rtn=pbkdf2_check(pass, &out).unwrap().to_string();

   if rtn=="true" { println!("Password check correct"); }
else { println!("Password not correct"); }
}

Finally we simply build with:

cargo build

A sample run with a password of “Qwerty123” and a count of 10 is [here]:

Password: Qwerty123
Count: 10
PBKDF2: $rpbkdf2$0$AAAACg==$nZognaeZC+9qywLBOgTtKQ==$6x3YtPcJmqmrwphYH3Kmx6BHb4I640pipp9hnxYbens=$
Password check correct

Conclusion

No better way to implement PBKDF2 than in Rust.