Reputation: 797
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
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