четверг, 1 июля 2010 г.

Освоение криптографии - 3: SHA-1

Симметричное шифрование, которое я "освоил" в двух предыдущих постах иногда является излишним. Например, между приложениями есть https-канал и перехват данных нам не грозит. Но нам грозит другое: данные могут быть подделаны. Обычная схема защиты в таком случае сгенерировать сигнатуру и послать её вместе с данными. Сигнатура при этом получается как результат необратимого шифрования строки, составленной из передаваемых данных и пароля, известного получателю и отправителю. Получатель не расшифровывает сигнатуру (это невозможно), а создаёт её заново: запрос он получил, а пароль он знает. Совпадение сигнатуры с полученной подтверждает что данные не изменились при передаче, а отправитель знает верный пароль.
Ключевой элемент этой схемы - необратимое шифрование. Одним из самых популярных алгоритмов тут является SHA-1.
Итак, задача прежняя: на серверной стороне java. Код тут такой:
  1.     /**
  2.      * Хэширование sha1
  3.      * @param Param строка для хеширования
  4.      * @param Encode
  5.      * @return hex-представление хэш-строки
  6.      * @throws NoSuchAlgorithmException
  7.      * @throws UnsupportedEncodingException
  8.      */
  9.     public static String sha1(String Param) throws NoSuchAlgorithmException, UnsupportedEncodingException {
  10.         MessageDigest SHA = MessageDigest.getInstance("SHA-1");
  11.         SHA.reset();
  12.         SHA.update(Param.getBytes("UTF-8"), 0, Param.length());
  13.         byte[] sha1hash = SHA.digest();
  14.         return bytesToHexStr(sha1hash);
  15.     }
Тут полученный хэш мы сразу представляем в виде hex-строки. Для этого используем метод:
  1.     /**
  2.      * Преобразование байтового массива в hex-строку
  3.      * @param raw
  4.      * @return String
  5.      */
  6.     public static String bytesToHexStr(byte[] raw) {
  7.         char[] kDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
  8.         int length = raw.length;
  9.         char[] hex = new char[length * 2];
  10.         for (int i = 0; i < length; i++) {
  11.             int value = (raw[i] + 256) % 256;
  12.             int highIndex = value >> 4;
  13.             int lowIndex = value & 0x0f;
  14.             hex[i * 2 + 0] = kDigits[highIndex];
  15.             hex[i * 2 + 1] = kDigits[lowIndex];
  16.         }
  17.         return new String(hex);
  18.     }

Теперь аналогичное действие делаем во flex:
  1. var h:IHash = Crypto.getHash("sha1");
  2. var sidn:String = Hex.fromArray(h.hash(Hex.toArray(Hex.fromString("your_secret_string"))));
Тут, как видите, всё совсем просто. Конечно, если использовать правильные библиотеки :)
Я, как и в предыдущих случаях использовал библиотеку as3crypto