Olof
Olof

Reputation: 797

Openssl hmac generates different result

I am working on library that HMAC input to get a signature, the signature will then be checked on the server to validated the sender. My problem is that the library and server generates different HMAC. I use the HMAC function provided by the OpenSSL package.

The key is Secret and secure key! and the package (data) is {"alg":"SHA256","id":1,"data":"DOGOOS","time":3,"expire":1} and it generates the following signature egL2gFU2DZVNkTk7jzhl7YJOKhHOWqTh/pUi3G2G2C4= while my server generates 6DE3KUbbF6nKttaKIWRQaKAgdA7gG1JiPU63L1uPOww= for the same data.

I also tested to generate a signature from this website https://www.liavaag.org/English/SHA-Generator/HMAC/ with the following settings and it yields the same result as my server.

Input type: Text
Key type: Text 
Sha variant: SHA256
Output type: Base64

I have verified that the Base64Encode function works properly.

unsigned char* sign(char* package, int package_len, char* key, int key_len, unsigned char* signature, unsigned int *signature_len, char** b64){
    HMAC(EVP_sha256(), key, key_len, package, package_len, signature, signature_len);

    Base64Encode(signature, *signature_len, b64);
    return 0;
}

int main(int argc, const char * argv[]) {

    int average = 3;
    uint package_size = 100;
    uint id = 1;
    char *package = (char*)malloc(package_size * sizeof(char));
    char *data = "DOGOOS";
    format(&package, package_size, data, SHA256, id, average, 1);

    unsigned char* key = "Secret and secure key!";
    int key_len = 22;
    uint signature_len = 200;
    char* signature = (char*)malloc(signature_len * sizeof(char));
    char* base64_output;

    unsigned char* output = sign(package, package_size, key, key_len, signature, &signature_len, &base64_output);
    printf("package: %s\n", package);
    printf("SIGNATURE: %s\n", base64_output);


    free(base64_output);
    free(signature);
    free(output);
    free(package);
    return 0;
}

As requested this is the code on the server side. It is written in rust. I generates the same result as the websites I trired so for all tests I have done the server yields the correct output.

#[derive(Debug, Clone, Copy)]
pub enum Algorithm {
    SHA256,
    SHA512,
}

pub struct Packet{

    algorithm:      types::Algorithm,
    payload:        String,
    signature:      Vec<u8>,
    start_time:     u64,
    timestamp:      u64,
    expire:         u64,
}
impl Packet {
    /**
     * Returns the algorithm used.
     */
    pub fn get_algorithm(&self) -> types::Algorithm {
        self.algorithm.clone()
    }
    /**
     * Returns the signature.
     */
    pub fn get_signature(&self) -> &Vec<u8> {
        &self.signature
    }

    pub fn get_payload(&self) -> String {
        self.payload.clone()
    }
}

/**
 * Validates the signature of the packet
 */
fn validate_packet(packet: &packet::Packet, key: &str) -> bool{

    let result = match packet.get_algorithm(){
        packet::types::Algorithm::SHA256 => {
            let mut mac = Hmac::<Sha256>::new(key.as_bytes());
            mac.input(packet.get_payload().as_bytes());
            let signature = packet.get_signature();
            mac.verify(signature)
        },
        packet::types::Algorithm::SHA512 => {
            let mut mac = Hmac::<Sha512>::new(key.as_bytes());
            mac.input(packet.get_payload().as_bytes());
            let signature = packet.get_signature();
            mac.verify(signature)
        },
    };

    return result;
} 

Upvotes: 0

Views: 780

Answers (1)

user2722968
user2722968

Reputation: 16535

Your C implementation is incorrect with respect to package_size, which you hardcoded at 100 bytes. You effectively use the message {"alg":"SHA256","id":1,"data":"DOGOOS","time":3,"expire":1}\x00\x00\x00\x00...\x00 in your C-implementation while your rust-code uses the correct message.

Demonstrated in python:

>>> import hashlib
>>> import hmac
>>> import base64
>>> correct_msg = b'{"alg":"SHA256","id":1,"data":"DOGOOS","time":3,"expire":1}'
>>> badly_padded_msg = correct_msg + b'\x00'*(100-len(msg))
>>> key = b'Secret and secure key!';
>>> base64.encodebytes(hmac.HMAC(key, correct_msg, hashlib.sha256).digest())
b'6DE3KUbbF6nKttaKIWRQaKAgdA7gG1JiPU63L1uPOww=\n'
>>> base64.encodebytes(hmac.HMAC(key, badly_padded_msg, hashlib.sha256).digest())
b'egL2gFU2DZVNkTk7jzhl7YJOKhHOWqTh/pUi3G2G2C4=\n'

Upvotes: 1

Related Questions