Skip to main content

Module pbkdf2

Module pbkdf2 

Available on crate features crypto and ring and std only.
Expand description

PBKDF2 derivation and verification.

Use derive to derive PBKDF2 outputs. Use verify to verify secret against previously-derived outputs.

PBKDF2 is specified in RFC 2898 Section 5.2 with test vectors given in RFC 6070. See also NIST Special Publication 800-132.

§Examples

§Password Database Example

use ring::{digest, pbkdf2};
use std::{collections::HashMap, num::NonZeroU32};

static PBKDF2_ALG: pbkdf2::Algorithm = pbkdf2::PBKDF2_HMAC_SHA256;
const CREDENTIAL_LEN: usize = digest::SHA256_OUTPUT_LEN;
pub type Credential = [u8; CREDENTIAL_LEN];

enum Error {
    WrongUsernameOrPassword
}

struct PasswordDatabase {
    pbkdf2_iterations: NonZeroU32,
    db_salt_component: [u8; 16],

    // Normally this would be a persistent database.
    storage: HashMap<String, Credential>,
}

impl PasswordDatabase {
    pub fn store_password(&mut self, username: &str, password: &str) {
        let salt = self.salt(username);
        let mut to_store: Credential = [0u8; CREDENTIAL_LEN];
        pbkdf2::derive(PBKDF2_ALG, self.pbkdf2_iterations, &salt,
                       password.as_bytes(), &mut to_store);
        self.storage.insert(String::from(username), to_store);
    }

    pub fn verify_password(&self, username: &str, attempted_password: &str)
                           -> Result<(), Error> {
        match self.storage.get(username) {
           Some(actual_password) => {
               let salt = self.salt(username);
               pbkdf2::verify(PBKDF2_ALG, self.pbkdf2_iterations, &salt,
                              attempted_password.as_bytes(),
                              actual_password)
                    .map_err(|_| Error::WrongUsernameOrPassword)
           },

           None => Err(Error::WrongUsernameOrPassword)
        }
    }

    // The salt should have a user-specific component so that an attacker
    // cannot crack one password for multiple users in the database. It
    // should have a database-unique component so that an attacker cannot
    // crack the same user's password across databases in the unfortunate
    // but common case that the user has used the same password for
    // multiple systems.
    fn salt(&self, username: &str) -> Vec<u8> {
        let mut salt = Vec::with_capacity(self.db_salt_component.len() +
                                          username.as_bytes().len());
        salt.extend(self.db_salt_component.as_ref());
        salt.extend(username.as_bytes());
        salt
    }
}

fn main() {
    // Normally these parameters would be loaded from a configuration file.
    let mut db = PasswordDatabase {
        pbkdf2_iterations: NonZeroU32::new(100_000).unwrap(),
        db_salt_component: [
            // This value was generated from a secure PRNG.
            0xd6, 0x26, 0x98, 0xda, 0xf4, 0xdc, 0x50, 0x52,
            0x24, 0xf2, 0x27, 0xd1, 0xfe, 0x39, 0x01, 0x8a
        ],
        storage: HashMap::new(),
    };

    db.store_password("alice", "@74d7]404j|W}6u");

    // An attempt to log in with the wrong password fails.
    assert!(db.verify_password("alice", "wrong password").is_err());

    // Normally there should be an expoentially-increasing delay between
    // attempts to further protect against online attacks.

    // An attempt to log in with the right password succeeds.
    assert!(db.verify_password("alice", "@74d7]404j|W}6u").is_ok());
}

Structs§

Algorithm
A PBKDF2 algorithm.

Statics§

PBKDF2_HMAC_SHA1
PBKDF2 using HMAC-SHA1.
PBKDF2_HMAC_SHA256
PBKDF2 using HMAC-SHA256.
PBKDF2_HMAC_SHA384
PBKDF2 using HMAC-SHA384.
PBKDF2_HMAC_SHA512
PBKDF2 using HMAC-SHA512.

Functions§

derive
Fills out with the key derived using PBKDF2 with the given inputs.
verify
Verifies that a previously-derived (e.g., using derive) PBKDF2 value matches the PBKDF2 value derived from the other inputs.