HMC SHA1-хеш - Java производит другой хеш-вывод, чем C # - PullRequest
6 голосов
/ 08 января 2012

Это вопрос до этого вопроса, но я пытаюсь перенести код C # на Java вместо кода Ruby на C #, как это было в соответствующем вопросе.Я пытаюсь проверить правильность зашифрованной подписи , возвращенной из API Recurly.js.К сожалению, у Recurly нет библиотеки Java для помощи в проверке, поэтому я должен сам выполнить проверку подписи.

Согласно приведенному выше вопросу ( this ), следующий код C # можетсоздайте хеш, необходимый для проверки подписи, возвращенной из Recurly:

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

Recurly предоставляет следующие примерные данные на своей странице документации signature :

незашифрованное подтверждающее сообщение : [1312701386, транзакция создана, [account_code: ABC, amount_in_cents: 5000, валюта: USD]]

закрытый ключ : 0123456789ABCDEF0123456789ABCDEF

результирующая подпись : 0f5630424b32402ec03800e977cd7a8b13dbd153-1312701386

Вот моя реализация Java:

String unencryptedMessage = "[1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]";
String privateKey = "0123456789ABCDEF0123456789ABCDEF";
String encryptedMessage = getHMACSHA1(unencryptedMessage, getSHA1(privateKey));

private static byte[] getSHA1(String source) throws NoSuchAlgorithmException, UnsupportedEncodingException{
    MessageDigest md = MessageDigest.getInstance("SHA-1");
    byte[] bytes = md.digest(source.getBytes("UTF-8"));
    return bytes;
}

private static String getHMACSHA1(String baseString, byte[] keyBytes) throws GeneralSecurityException, UnsupportedEncodingException {
    SecretKey secretKey = new SecretKeySpec(keyBytes, "HmacSHA1");
    Mac mac = Mac.getInstance("HmacSHA1");
    mac.init(secretKey);
    byte[] bytes = baseString.getBytes("ASCII");
    return Hex.encodeHexString(mac.doFinal(bytes));
}

Однако, когда я распечатываю переменную encryptedMessage, она не совпадает счасть сообщения примера подписи.В частности, я получаю значение «c8a9188dcf85d1378976729e50f1de5093fabb78» вместо «0f5630424b32402ec03800e977cd7a8b13dbd153».

Обновление *1050* код данных I, код данных на уровне данных, код данных: 1037 *

Perи он вернул тот же вывод, что и код Java.Так что, похоже, мой подход к хешированию правильный, но я передаю неверные данные (unencryptedMessage).Вздох.Я обновлю этот пост, если / когда смогу определить, какие именно данные необходимо зашифровать - поскольку в «незашифрованном сообщении о проверке», приведенном в документации Recurly, что-то отсутствует.

Обновление 2

Ошибка оказалась в виде данных / формата «незашифрованное сообщение проверки».Сообщение в данных примера на самом деле не зашифровывается до предоставленной подписи примера, так что, возможно, устаревшая документация?В любом случае, я подтвердил, что реализация Java будет работать для реальных данных.Спасибо всем.

Ответы [ 3 ]

5 голосов
/ 09 января 2012

Я думаю, что проблема в вашем .NET-коде.Configuration.RecurlySection.Current.PrivateKey возвращает строку?Это значение - ожидаемый вами ключ?

Используя следующий код, .NET и Java возвращают идентичные результаты.

.NET Code

string message = "[1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]";
string privateKey = "0123456789ABCDEF0123456789ABCDEF";

var hashedKey = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(privateKey));
var hmac = new HMACSHA1(hashedKey);
var hash = hmac.ComputeHash(Encoding.ASCII.GetBytes(message));

Console.WriteLine("  Message: {0}", message);
Console.WriteLine("      Key: {0}\n", privateKey);
Console.WriteLine("Key bytes: {0}", BitConverter.ToString(hashedKey).Replace("-", "").ToLower());
Console.WriteLine("   Result: {0}", BitConverter.ToString(hash).Replace("-", "").ToLower());

Результат:

  Message: [1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]
      Key: 0123456789ABCDEF0123456789ABCDEF

Key bytes: 4d857d2408b00c3dd17f0c4ffcf15b97f1049867
   Result: c8a9188dcf85d1378976729e50f1de5093fabb78

Java

String message = "[1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]";
String privateKey = "0123456789ABCDEF0123456789ABCDEF";

MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] keyBytes = md.digest(privateKey.getBytes("UTF-8"));

SecretKey sk = new SecretKeySpec(keyBytes, "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(sk);
byte[] result = mac.doFinal(message.getBytes("ASCII"));

System.out.println("  Message: " + message);
System.out.println("      Key: " + privateKey + "\n");
System.out.println("Key Bytes: " + toHex(keyBytes));
System.out.println("  Results: " + toHex(result));

Результат:

  Message: [1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]
      Key: 0123456789ABCDEF0123456789ABCDEF

Key Bytes: 4d857d2408b00c3dd17f0c4ffcf15b97f1049867
  Results: c8a9188dcf85d1378976729e50f1de5093fabb78
1 голос
/ 08 января 2012

Я подозреваю, что кодировка по умолчанию значений, над которыми вы работаете, может отличаться.Поскольку они не указали его, они будут использовать значение кодировки по умолчанию для строки, основанное на платформе, с которой вы работаете.

Я сделал быстрый поиск, чтобы убедиться, что это правда, и это все еще неокончательно, но это заставило меня думать, что строки в .NET по умолчанию имеют кодировку UTF-16, а Java по умолчанию - UTF-8.(Кто-нибудь может это подтвердить?)

Если это так, то ваш GetBytes метод с кодировкой UTF-8 уже производит разные выходные данные для каждого случая.

0 голосов
/ 08 января 2012

Исходя из этого примера кода, похоже, что Java ожидает, что вы еще не использовали ключ SHA1 перед созданием SecretKeySpec. Вы пробовали это?

...