HMC SHA1-хеш - C # производит другой хеш-вывод, чем Ruby - PullRequest
5 голосов
/ 24 августа 2011

Я пытаюсь быстро получить глючную клиентскую библиотеку .Net для стороннего сервиса, который я использую для работы.Исходная библиотека (которая работает) написана на Ruby, но их эквивалентная библиотека для DotNet создает различный хэш-вывод для библиотеки Ruby.

Код шифрования Ruby выглядит следующим образом:

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

(Предположительно) эквивалентный код C #:

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();
}

Фактический хэш-вывод отличается, хотя, учитывая тот же ввод и закрытый ключ.Что не так с методом C #, который заставляет его выдавать неправильный вывод хеша?

РЕДАКТИРОВАТЬ
Так I написал бы код,хотя он по-прежнему выдает неправильный вывод:

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();
}

ПРАВИЛЬНЫЙ ОТВЕТ

Благодаря ответу Хеннинга ниже я смог определить, что правильный код:

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 Ответ

4 голосов
/ 24 августа 2011

Если я понимаю код, кажется, что код Ruby хэширует ключ отдельно перед передачей его в HMAC (который не должен быть криптографически необходим, поскольку HMAC сам при необходимости хеширует длинный ключ)и передает хешированный ключ в HMAC вместе с исходным сообщением.

С другой стороны, ваш код C # вычисляет HMAC с ключом original и hash сообщения.(Необъяснимо, что переменные, в которых вы храните хэшированное сообщение, называются salt и private_key_binary, хотя содержимое не является ни солью, ни ключом ...)

Я не могу представить, что библиотеки Ruby и C #будет относиться к HMAC так по-другому, что это правильно.

...