HMC SHA1 hash - C # producing a different hash output than Ruby

I am trying to quickly get the wrong .Net client library for the third-party service that I use to work. The source library (which works) is written in Ruby, but their equivalent library for DotNet creates different hash output for the Ruby library.

The Ruby encryption code is as follows:

def self.encrypt_string(input_string) raise Recurly::ConfigurationError.new("Recurly gem not configured") unless Recurly.private_key.present? digest_key = ::Digest::SHA1.digest(Recurly.private_key) sha1_hash = ::OpenSSL::Digest::Digest.new("sha1") ::OpenSSL::HMAC.hexdigest(sha1_hash, digest_key, input_string.to_s) end 

Estimated equivalent C # code:

 private static string ComputePrivateHash(string dataToProtect) { if(String.IsNullOrEmpty(Configuration.RecurlySection.Current.PrivateKey)) throw new RecurlyException("A Private Key must be configured to use the Recurly Transparent Post API."); byte[] salt_binary = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(dataToProtect)); string salt_hex = BitConverter.ToString(salt_binary).Replace("-", "").ToLower(); string salt = salt_hex.Substring(0, 20); HMACSHA1 hmac_sha1 = new HMACSHA1(Encoding.ASCII.GetBytes(Configuration.RecurlySection.Current.PrivateKey)); hmac_sha1.Initialize(); byte[] private_key_binary = Encoding.ASCII.GetBytes(salt); byte[] passkey_binary = hmac_sha1.ComputeHash(private_key_binary, 0, private_key_binary.Length); return BitConverter.ToString(passkey_binary).Replace("-", "").ToLower(); } 

The actual hash output is different, however, given the same input and private key. What is wrong with the C # method, which forces it to generate incorrect hash output?

EDIT
So I would write the code, although it still produces the wrong output:

 private static string ComputePrivateHash(string dataToProtect) { if(String.IsNullOrEmpty(Configuration.RecurlySection.Current.PrivateKey)) throw new RecurlyException("A Private Key must be configured to use the Recurly Transparent Post API."); var privateKey = Configuration.RecurlySection.Current.PrivateKey; var hashedData = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(dataToProtect)); var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(privateKey)); var hash = hmac.ComputeHash(hashedData); return BitConverter.ToString(hash).Replace("-", "").ToLower(); } 

CORRECTED RESPONSE

Thanks to Henning's answer below, I was able to determine what the correct code is:

 var privateKey = Configuration.RecurlySection.Current.PrivateKey; var hashedKey = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(privateKey)); var hmac = new HMACSHA1(hashedKey); var hash = hmac.ComputeHash(Encoding.ASCII.GetBytes(dataToProtect)); return BitConverter.ToString(hash).Replace("-", "").ToLower(); 
+5
source share
1 answer

If I understand the code, it seems that the Ruby code hashes the key separately before submitting it to the HMAC (which will not be cryptographically necessary, since the HMAC itself uses the long key) and sends the hashed key to the HMAC along with the original message.

On the other hand, your C # code computes the HMAC with the source key and message hash. (Optional, the variables in which you store the hashed message are called salt and private_key_binary , although the content is neither salt nor key ...)

I cannot imagine that Ruby and C # libraries will handle HMAC in a different way that this is the right thing.

+4
source

Source: https://habr.com/ru/post/905467/


All Articles