2
votes

I'm trying to port a crypto exchange API from JavaScript to Rust. The JavaScript version authenticates and connects. The payload and secret key are signed using Hmac Sha256 and encoded to Base64. Below is the working implementation in JavaScript.

var param = "test";
var privateKey = "secret";
var signature = crypto.createHmac('sha256', new Buffer(privateKey, 'utf8'))
    .update(param)
    .digest('base64');

It returns the following signature: Aymga2LNFrM+tnkr6MYLFY2Jou46h2/Omogeu0iMCRQ=

In Rust i'm using Hmac SHA256 and encoding the result back to Base64 yet i'm unable to get close to the expected signature. Here is my best 2 day attempt at this:

extern crate ring;
extern crate data_encoding;
extern crate hex;

use ring::{digest, hmac};
use data_encoding::BASE64;
use hex::encode as hex_encode;

fn main() {
    let secret_key = "secret";
    let payload = "test";
    let signed_key = hmac::SigningKey::new(&digest::SHA256, secret_key.as_bytes());
    let signature = hex_encode(hmac::sign(&signed_key, payload.as_bytes()).as_ref());
    let b64_encoded_sig = BASE64.encode(signature.as_ref());
    assert_eq!(b64_encoded_sig, "Aymga2LNFrM+tnkr6MYLFY2Jou46h2/Omogeu0iMCRQ=");
}

This returns the following signature: MDMyOWEwNmI2MmNkMTZiMzNlYjY3OTJiZThjNjBiMTU4ZDg5YTJlZTNhODc2ZmNlOWE4ODFlYmI0ODhjMDkxNA==

Would really appreciate getting a point in the right direction, gone around in circles for days now and not sure where exactly i'm going wrong. Thanks.

1
The rust signature is encoded twice: first hex and then base64. Therefore it's length is also different.Robert
Why the hex encoding ? It makes no sense to encode to hex then to base64. Both have the same purpose: produce a readable and easy to exchange string from an array of bytes. You never use both.Denys Séguret
correct good spot thank you!JoshuaBatty

1 Answers

4
votes

Just remove the hex-thing

extern crate ring;
extern crate data_encoding;

use ring::{digest, hmac};
use data_encoding::BASE64;

fn main() {
    let secret_key = "secret";
    let payload = "test";
    let signed_key = hmac::SigningKey::new(&digest::SHA256, secret_key.as_bytes());
    let signature = hmac::sign(&signed_key, payload.as_bytes());
    let b64_encoded_sig = BASE64.encode(signature.as_ref());
    assert_eq!(b64_encoded_sig, "Aymga2LNFrM+tnkr6MYLFY2Jou46h2/Omogeu0iMCRQ=");
}