Argon 2 стал победителем конкурса По хэшированию паролей в июле 2015 года, функция одностороннего хэширования, которая намеренно требует больших ресурсов (процессор, память и т. Д.). В Argon 2 мы можем настроить длину соли, длину сгенерированного хэша, итерации, стоимость памяти и стоимость процессора для управления ресурсами, необходимыми для хэширования пароля.
Алгоритм Argon2 имеет три варианта:
Argon2d
, максимизирует устойчивость к атакам взлома графического процессора, подходит для криптовалют.Argon2i
, оптимизированный для защиты от атак по боковым каналам , подходит для хэширования паролей.Argon2id
, гибридная версия, если не уверена, выбирает это.
Алгоритм Argon2 принимает пять настраиваемых параметров:
- Длина соли — длина случайной соли, рекомендуется 16 байт.
- Длина ключа — длина сгенерированного хэша, рекомендуется 16 байт, но большинство предпочитает 32 байта.
- Итерации — Количество итераций, влияющих на временные затраты.
- Память — объем памяти, используемый алгоритмом (в кибибайтах, байтах), влияет на стоимость памяти.
- Параллелизм — Количество потоков (или полос), используемых алгоритмом, влияет на степень параллелизма.
Прочитайте это Технический документ Argon2 .
Зачем нужно медленное хеширование паролей?
Современное оборудование (процессор и графический процессор) становится все лучше и дешевле. Потребительский процессор, такой как AMD Ryzen Thread ripper, с каждым годом увеличивает количество ядер, например, AMD 3990X имеет 64 ядра, 128 потоков.
Кроме того, благодаря росту криптовалюты майнинга, графический процессор продолжает развиваться, FPGA или выделенный ASIC может выполнять миллиарды вычислений хэша в секунду .
Квантовые вычисления , еще слишком рано говорить об этом, но рано или поздно мы вступим в эпоху квантовых вычислений, и никто не знает, насколько быстрее квантовые компьютеры могут работать со скоростью хэширования.
Закон Мура , перенесемся на десять лет вперед, скорость хэша будет расти экспоненциально, очень возможно, что мы сможем декодировать MD5
, SHA1
, SHA-256
, SHA512
или ЧЕРНЫЙ 2
пароль хэшируется в течение секунды или даже быстрее (даже засолка не помогает).
В двух словах, все быстрые алгоритмы хэширования не подходят для хэширования паролей, и нам нужны некоторые медленные алгоритмы хэширования и ресурсоемкие алгоритмы, такие как Bcrypt , Сценарий , или
Аргон2
В Java мы можем использовать следующие библиотеки для выполнения хэширования паролей Argon 2.
- аргон2-спм
- Безопасность пружины Кодер Argon2PasswordEncoder
1. Java Аргон2 Хэширование паролей – argon2-jvm
Это argon2-jvm , внутренне использует Собственный доступ к Java (JNA) для вызова библиотеки Argon2 C .
1.1 Этот argon2-jvm
доступен в центральном репозитории Maven.
de.mkammerer argon2-jvm 2.7
1.2 Завод по умолчанию Argon 2.create()
возвращает вариант argon2i
с 16 байтами соли и длиной хэша 32 байта.
// Argon2Types.ARGON2i // salt 16 bytes // Hash length 32 bytes Argon2 argon2 = Argon2Factory.create();
Мы можем настроить вариант Argon2, длину соли и длину сгенерированного хэша.
// Argon2Types.ARGON2id // salt 32 bytes // Hash length 64 bytes Argon2 argon2 = Argon2Factory.create( Argon2Factory.Argon2Types.ARGON2id, 32, 64);
1.3 Просмотрите основной метод хэширования; для хэширования требуется четыре параметра, итерации, память, параллелизм и пароль.
package de.mkammerer.argon2; public interface Argon2 { /** * Hashes a password. ** Uses UTF-8 encoding. * * @param iterations Number of iterations * @param memory Sets memory usage to x kibibytes * @param parallelism Number of threads and compute lanes * @param password Password to hash * @return Hashed password. */ String hash(int iterations, int memory, int parallelism, char[] password); //...
1.4 Этот пример Java предоставляет следующие входные данные для выполнения хэширования пароля Argon 2.
- Варианты =
argon2i
(по умолчанию) - Байты соли, 128 бит (по умолчанию)
- Байты хэша, 256 бит (по умолчанию)
- Итерации
- Память, 64 M
- Параллелизм
Мы запускаем приведенный ниже код четыре раза на нашем тестовом компьютере, основная спецификация – 12-ядерный процессор AMD 3900X, 16 м памяти, и для хэширования пароля с помощью алгоритма Argon2 требуется около 450-500 мс.
package com.mkyong.crypto.password; import de.mkammerer.argon2.Argon2; import de.mkammerer.argon2.Argon2Factory; import java.time.Instant; import java.time.temporal.ChronoUnit; public class PasswordArgon2Jvm { public static void main(String[] args) { // default argon2i, salt 16 bytes, hash length 32 bytes. Argon2 argon2 = Argon2Factory.create(); char[] password = "Hello World".toCharArray(); Instant start = Instant.now(); // start timer try { // iterations = 10 // memory = 64m // parallelism = 1 String hash = argon2.hash(22, 65536, 1, password); System.out.println(hash); // argon2 verify hash /*if (argon2.verify(hash, password)) { System.out.println("Hash matches password."); }*/ //int iterations = Argon2Helper.findIterations(argon2, 1000, 65536, 1); //System.out.println(iterations); } finally { // Wipe confidential data argon2.wipeArray(password); } Instant end = Instant.now(); // end timer System.out.println(String.format( "Hashing took %s ms", ChronoUnit.MILLIS.between(start, end) )); } }
Выход. Выходные данные закодированы в кодировке base64, которая состоит из вариантов Argon 2, версии Argon 2 $v
, стоимости памяти $m
, итераций $t
, параллелизма (полоса) $p
, 16 байт соли и хэша, сгенерированного Argon2.
# 1st time $argon2i$v=19$m=65536,t=10,p=1$cGjkgKPK111PPp7t2VEQrA$eowEcB27XAH9wSC1oUjaGuW0jA1iQSmaL4cs7W2Vd0k Hashing took 500 ms # 2nd time $argon2i$v=19$m=65536,t=10,p=1$YkDFUQRhJGa0KjEWusHYQQ$t8IPgKRRFCMkb84cU1PB8JlS3aa+hTQfzFmmbz5omnk Hashing took 489 ms # 3rd time $argon2i$v=19$m=65536,t=10,p=1$h2X+NkgqWtnpnfoQq2NDaw$xWqR9NaL7t6SaJJLiXeFtrGFNp4j08FJJIuTXe0oRiI Hashing took 457 ms # 4th time $argon2i$v=19$m=65536,t=10,p=1$/bY1iOq+C8sRpIGcrwb2fQ$d1Ed4lLAeVrxBjFxINEbC4wNl0FZ2lZ2JsNkJjJkODA Hashing took 507 ms
1.5 Мы можем предоставить различные входные данные для увеличения времени хэширования пароля, скажем, мы хотим, чтобы хэш-функция занимала не более 1 секунды, давая 64 м и один поток, мы можем использовать Помощник Argon 2. найдите итерации
, чтобы узнать оптимизированные итерации.
// 1000 = Time in ms, we want this 1 second // 65536 = Memory cost, 64Mb // 1 = parallelism int iterations = Argon2Helper.findIterations(argon2, 1000, 65536, 1); System.out.println(iterations);
Выход
22
Повторите программу с предложенными 22 итерациями. Теперь хэширование пароля Argon2 занимает около 1 секунды.
String hash = argon2.hash(22, 65536, 1, password); System.out.println(hash);
Выход
# 1st $argon2i$v=19$m=65536,t=22,p=1$LqszYnhGhlM6AW3ehXhXmA$hgFiUxZUbgdodrIOUHhUzPdiWecYYFmHdFPQEf6beBc Hashing took 1004 ms # 2nd $argon2i$v=19$m=65536,t=22,p=1$kySDkzqRkEr748trey63Dg$OsKcqvoK/Y5pywATXw0P8RmKeMAzurNsgbGlmnw8Svs Hashing took 991 ms
2. Java Аргон2 Хэширование Паролей – Безопасность Spring
2.1 В Spring Security мы можем использовать Кодер паролей Argon 2
для выполнения хэширования пароля Argon 2. Реализация кодера паролей Argon 2
требует Надувной замок .
org.springframework.security spring-security-crypto 5.3.2.RELEASE commons-logging commons-logging 1.2 org.bouncycastle bcpkix-jdk15on 1.65
2.2 Кодер пароля Argon 2
, внутренне использует Надувной замок
API, такие как Параметры Аргона 2
и Генератор 2 байт Аргона
для обеспечения хэширования Argon2.
package org.springframework.security.crypto.argon2; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.bouncycastle.crypto.generators.Argon2BytesGenerator; import org.bouncycastle.crypto.params.Argon2Parameters; import org.springframework.security.crypto.keygen.BytesKeyGenerator; import org.springframework.security.crypto.keygen.KeyGenerators; import org.springframework.security.crypto.password.PasswordEncoder; public class Argon2PasswordEncoder implements PasswordEncoder { private static final int DEFAULT_SALT_LENGTH = 16; private static final int DEFAULT_HASH_LENGTH = 32; private static final int DEFAULT_PARALLELISM = 1; private static final int DEFAULT_MEMORY = 1 << 12; private static final int DEFAULT_ITERATIONS = 3; //... public Argon2PasswordEncoder(int saltLength, int hashLength, int parallelism, int memory, int iterations) { this.hashLength = hashLength; this.parallelism = parallelism; this.memory = memory; this.iterations = iterations; this.saltGenerator = KeyGenerators.secureRandom(saltLength); } public Argon2PasswordEncoder() { this(DEFAULT_SALT_LENGTH, DEFAULT_HASH_LENGTH, DEFAULT_PARALLELISM, DEFAULT_MEMORY, DEFAULT_ITERATIONS); } @Override public String encode(CharSequence rawPassword) { byte[] salt = saltGenerator.generateKey(); byte[] hash = new byte[hashLength]; Argon2Parameters params = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id). withSalt(salt). withParallelism(parallelism). withMemoryAsKB(memory). withIterations(iterations). build(); Argon2BytesGenerator generator = new Argon2BytesGenerator(); generator.init(params); generator.generateBytes(rawPassword.toString().toCharArray(), hash); return Argon2EncodingUtils.encode(hash, params); } //...
2.3 В этом примере Java используется Кодер пароля Argon 2
для выполнения хэширования пароля Argon 2 с использованием входных данных по умолчанию:
- Варианты =
аргон2ид
- Байты соли, 128-битные
- Байты хэша, 256 бит
- Итерация
- Память <<12, или 2^12, 4096k
- Параллелизм
package com.mkyong.crypto.password; import org.springframework.security.crypto.argon2.Argon2PasswordEncoder; import java.time.Instant; import java.time.temporal.ChronoUnit; public class PasswordArgon2SpringSecurity { public static void main(String[] args) { Argon2PasswordEncoder encoder = new Argon2PasswordEncoder(); String password = "Hello World"; Instant start = Instant.now(); // start timer String hash = encoder.encode(password); System.out.println(hash); // argon2 verify hash /*if (encoder.matches("Hello World", hash)) { System.out.println("match"); }*/ Instant end = Instant.now(); // end timer System.out.println(String.format( "Hashing took %s ms", ChronoUnit.MILLIS.between(start, end) )); } }
Выход
# 1st $argon2id$v=19$m=4096,t=3,p=1$iurr6y6xk2X7X/YVOEQXBg$ti9/be9VgbXtJWpm1hoYyLm8V0wBGr+dxu9X+PFbpZI Hashing took 176 ms # 2nd $argon2id$v=19$m=4096,t=3,p=1$vnOEfUC3oZ3sVBj/yKG/4g$LdVFmw9N5D49tuJiYT0LGZ8YOqYetqz5UzDyku+7PRs Hashing took 156 ms
2.4 Входы настраиваются.
public Argon2PasswordEncoder(int saltLength, int hashLength, int parallelism, int memory, int iterations) { this.hashLength = hashLength; this.parallelism = parallelism; this.memory = memory; this.iterations = iterations; this.saltGenerator = KeyGenerators.secureRandom(saltLength); }
Например,
// int saltLength, int hashLength, int parallelism, int memory, int iterations Argon2PasswordEncoder encoder = new Argon2PasswordEncoder(16, 32, 1, 65536, 10);
- Варианты =
аргон2ид
- Байты соли, 128-битные
- Байты хэша, 256 бит
- Итерация
- Память <<16, или 2^16, 65536k, 64M
- Параллелизм
Кодер пароля Argon 2
не позволяет изменять варианты Argon2.
3. Часто задаваемые вопросы
3.1 Каковы рекомендуемые параметры Argon2?
Помимо 16 байт соли и 32 байт длины ключа, остальные параметры зависят от емкости сервера. Запустите хэширование паролей Argon2 на рабочем сервере и точно настройте итерации, потоки, память и время, которые может позволить себе каждый вызов. Как правило, рекомендуется аутентификация Argon2, которая занимает от 0,5 мс до 1 секунды.
Скачать Исходный Код
$клон git $клон git
$cd java-крипто
Рекомендации
- Хэш пароля Argon2
- Технический документ Argon2
- Википедия – Аргон2
- Википедия – Bcrypt
- Википедия – Шифрование
- Аргон2-СПМ
- Надувной замок
- Хранилище паролей Spring Security
- Кодировщик паролей Argon2PasswordEncoder
- Соревнование по хэшированию Паролей
- Java 8 – Примеры периодов и продолжительности
Оригинал: “https://mkyong.com/java/java-password-hashing-with-argon2/”