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

旧街凉风 提交于 2019-12-07 06:27:16

问题


I'm trying to quickly get a buggy .Net client library for a third party service I'm using to work. The original library (which works) is written in Ruby, but their equivalent library for DotNet produces differing hash output to 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

The (supposedly) equivalent C# code is:

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 differs though, given the same input and private key. What is wrong with the C# method that causes it to produce the wrong hash output?

EDIT
This is the way I would have written the code, though 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();
}

CORRECT ANSWER

Thanks to Henning's answer below, I was able to determine that 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();

回答1:


If I understand the code, it seems the Ruby code is hashing the key separately before feeding it to HMAC (which shoudln't be cryptographically necessary, as HMAC will hash a long key itself if necessary), and feeds the hashed key to HMAC together with the original message.

On the other hand, your C# code computes a HMAC with the original key and a hash of the message. (Inexplicably, the variables where you store the hashed message are called salt and private_key_binary, though the content is neither a salt nor a key...)

I cannot imagine that the Ruby and C# libraries would treat HMAC so differently that this is the right thing to do.



来源:https://stackoverflow.com/questions/7175067/hmc-sha1-hash-c-sharp-producing-different-hash-output-than-ruby

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!