2

I am currently working on creating a client for Standard File, which involves using PBKDF2 for security. I'm using rust-crypto, although I have experimented with ring and rust-openssl.

First, you retrieve a salt, cost and version number from the server through the /auth/param endpoint. I have these serialized into a struct with Serde.

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct PWHash {
    pub pw_salt: String,
    pub pw_cost: u32,
    pub version: String,
}

Previous clients I have looked at implemented using Python, where the PBKDF2 functions all seem to accept strings. However, for PBKDF2 with Rust, they all accept &[u8] as the parameter.

I use .as_bytes() when calling the function, and then str::from_utf8 to output the derived key. However, when doing so, it fails with Err(Utf8Error { valid_up_to: 0, error_len: Some(1) }).

Here is a code snippet:

pub fn hashcompute(&self, password: String) {
    let mut dk = [0u8; 768]; // derived key
    let mut mac = Hmac::new(Sha512::new(), password.as_bytes());
    pbkdf2::pbkdf2(&mut mac, self.pw_salt.as_bytes(), self.pw_cost, &mut dk);

    println!("{:?}", str::from_utf8(&dk));
}

Even String::from_utf8_lossy returns a result of unreadable characters.

How do I properly format a Rust string for proper cryptographic use? Is there another library that is functional? Or is this a lost cause?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
alcao758
  • 165
  • 1
  • 2
  • 7
  • 1
    Why would you expect the key to be proper UTF-8? – mcarton Mar 04 '18 at 23:00
  • @mcarton I'm guessing that's part of the "user-readable" part. Wild guess: other languages automatically hex- or base64-encode the raw data. – Shepmaster Mar 04 '18 at 23:13
  • 1
    @Shepmaster: your comment shows exactly why automatically encoding the raw data would be a bad idea: there are two (common) ways to represent a key. – mcarton Mar 04 '18 at 23:16

1 Answers1

4

According to the Standard File documentation, the key should be hex-encoded (see the comments in the code sample). So something like this should work:

extern crate rustc_serialize as serialize;
use serialize::hex::{FromHex, ToHex};

pub fn hashcompute(&self, password: String) {
    let mut dk = [0u8; 768]; // derived key
    let mut mac = Hmac::new(Sha512::new(), password.as_bytes());
    pbkdf2::pbkdf2(&mut mac, self.pw_salt.from_hex().unwrap(), self.pw_cost, &mut dk);

    println!("{}", dk.to_hex());
}

Note that I've also used from_hex to convert the salt from a string to a &[u8] since it looks like the salt should also be hex-encoded.

Jmb
  • 18,893
  • 2
  • 28
  • 55
  • 1
    `rustc_serialize` is deprecated, usually in favour of `serde`, but for once, I don't think `serde` has this feature. There is a [`hex`](https://docs.rs/hex/0.3.1/hex/) crate which seems to well suited, although I've never used it. – mcarton Mar 05 '18 at 18:49