Что выведет код?
#Tasks
public class Task250225 {
public static void main(String[] args) {
byte b = (byte) 200;
int i = b + 100;
double d = (double) i / 300;
System.out.println(b);
System.out.println(i);
System.out.println(d);
}
}
#Tasks
Варианты ответа:
Anonymous Quiz
54%
200 300 1.0
5%
-56 -56 0.0
36%
-56 44 0.14666666666666667
5%
200 200 0.6666666666666666
Please open Telegram to view this post
VIEW IN TELEGRAM
Вопросы с собеседования 👩💻
Что такое hashCode() в Java?
Что такое hashCode() в Java?
Anonymous Quiz
12%
Метод для сравнения строк
4%
Метод для преобразования чисел в строки
6%
Метод для работы с файлами
78%
Метод для получения уникального идентификатора объекта
Java Crypto API
Класс Signature (цифровые подписи)
Класс Signature используется для создания и проверки цифровых подписей. Цифровая подпись обеспечивает целостность данных и аутентификацию отправителя.
Как работает Signature под капотом?
Signature использует асимметричные алгоритмы (например, RSA, DSA, ECDSA) для создания и проверки подписей.
Процесс состоит из двух этапов:
Создание подписи: Закрытый ключ используется для создания подписи.
Проверка подписи: Открытый ключ используется для проверки подписи.
Основные методы Signature
getInstance(String algorithm): Создает экземпляр Signature для указанного алгоритма (например, "SHA256withRSA").
initSign(PrivateKey privateKey): Инициализирует объект для создания подписи с использованием закрытого ключа.
initVerify(PublicKey publicKey): Инициализирует объект для проверки подписи с использованием открытого ключа.
update(byte[] data): Обновляет данные для подписи или проверки.
sign(): Создает подпись.
verify(byte[] signature): Проверяет подпись.
Пример использования Signature
Плюсы и минусы Signature
Плюсы:
Обеспечивает целостность данных и аутентификацию.
Поддерживает различные алгоритмы (RSA, DSA, ECDSA).
Минусы:
Требует наличия пары ключей (открытый и закрытый).
Может быть медленным для больших данных.
Класс MessageDigest (хэш-функции)
Класс MessageDigest используется для вычисления хэш-значений данных. Хэш-функции применяются для обеспечения целостности данных и создания уникальных идентификаторов.
Как работает MessageDigest под капотом?
MessageDigest использует криптографические хэш-функции (например, SHA-256, MD5) для преобразования данных в фиксированный размер хэш-значения.
Хэш-функции являются односторонними: из хэша нельзя восстановить исходные данные.
Основные методы MessageDigest
getInstance(String algorithm): Создает экземпляр MessageDigest для указанного алгоритма (например, "SHA-256").
update(byte[] input): Обновляет данные для хэширования.
digest(): Вычисляет хэш-значение.
digest(byte[] input): Вычисляет хэш-значение для указанных данных.
Пример использования MessageDigest
#Java #Training #Medium #Java_Crypto_API #Signature #MessageDigest
Класс Signature (цифровые подписи)
Класс Signature используется для создания и проверки цифровых подписей. Цифровая подпись обеспечивает целостность данных и аутентификацию отправителя.
Как работает Signature под капотом?
Signature использует асимметричные алгоритмы (например, RSA, DSA, ECDSA) для создания и проверки подписей.
Процесс состоит из двух этапов:
Создание подписи: Закрытый ключ используется для создания подписи.
Проверка подписи: Открытый ключ используется для проверки подписи.
Основные методы Signature
getInstance(String algorithm): Создает экземпляр Signature для указанного алгоритма (например, "SHA256withRSA").
initSign(PrivateKey privateKey): Инициализирует объект для создания подписи с использованием закрытого ключа.
initVerify(PublicKey publicKey): Инициализирует объект для проверки подписи с использованием открытого ключа.
update(byte[] data): Обновляет данные для подписи или проверки.
sign(): Создает подпись.
verify(byte[] signature): Проверяет подпись.
Пример использования Signature
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
public class SignatureExample {
public static void main(String[] args) throws Exception {
// Генерация пары ключей
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(2048);
KeyPair keyPair = keyPairGen.generateKeyPair();
// Получение ключей
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
// Создание подписи
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
String data = "Hello, Java Crypto!";
signature.update(data.getBytes());
byte[] digitalSignature = signature.sign();
System.out.println("Digital Signature (Base64): " + Base64.getEncoder().encodeToString(digitalSignature));
// Проверка подписи
signature.initVerify(publicKey);
signature.update(data.getBytes());
boolean isVerified = signature.verify(digitalSignature);
System.out.println("Signature Verified: " + isVerified);
}
}
Плюсы и минусы Signature
Плюсы:
Обеспечивает целостность данных и аутентификацию.
Поддерживает различные алгоритмы (RSA, DSA, ECDSA).
Минусы:
Требует наличия пары ключей (открытый и закрытый).
Может быть медленным для больших данных.
Класс MessageDigest (хэш-функции)
Класс MessageDigest используется для вычисления хэш-значений данных. Хэш-функции применяются для обеспечения целостности данных и создания уникальных идентификаторов.
Как работает MessageDigest под капотом?
MessageDigest использует криптографические хэш-функции (например, SHA-256, MD5) для преобразования данных в фиксированный размер хэш-значения.
Хэш-функции являются односторонними: из хэша нельзя восстановить исходные данные.
Основные методы MessageDigest
getInstance(String algorithm): Создает экземпляр MessageDigest для указанного алгоритма (например, "SHA-256").
update(byte[] input): Обновляет данные для хэширования.
digest(): Вычисляет хэш-значение.
digest(byte[] input): Вычисляет хэш-значение для указанных данных.
Пример использования MessageDigest
import java.security.MessageDigest;
import java.util.Base64;
public class MessageDigestExample {
public static void main(String[] args) throws Exception {
// Создание MessageDigest для SHA-256
MessageDigest digest = MessageDigest.getInstance("SHA-256");
// Хэширование данных
String data = "Hello, Java Crypto!";
byte[] hash = digest.digest(data.getBytes());
// Вывод хэша в Base64
System.out.println("Hash (Base64): " + Base64.getEncoder().encodeToString(hash));
}
}
#Java #Training #Medium #Java_Crypto_API #Signature #MessageDigest
Плюсы и минусы MessageDigest
Плюсы:
Обеспечивает целостность данных.
Поддерживает различные алгоритмы (SHA-256, MD5, SHA-1).
Минусы:
Хэш-функции устаревают (например, MD5 и SHA-1 считаются небезопасными).
Не подходит для шифрования данных.
#Java #Training #Medium #Java_Crypto_API #Signature #MessageDigest
Плюсы:
Обеспечивает целостность данных.
Поддерживает различные алгоритмы (SHA-256, MD5, SHA-1).
Минусы:
Хэш-функции устаревают (например, MD5 и SHA-1 считаются небезопасными).
Не подходит для шифрования данных.
#Java #Training #Medium #Java_Crypto_API #Signature #MessageDigest
Base64 в Java Crypto API
Base64 — это алгоритм кодирования двоичных данных в текстовый формат с использованием 64 символов ASCII. Он используется для представления бинарных данных в виде строк, удобных для передачи по сетевым протоколам и хранения в текстовых форматах. В Java Crypto API Base64 часто применяется для кодирования криптографических ключей, сертификатов и других бинарных данных.
Как работает Base64
Base64 берет 3 байта (24 бита) входных данных и преобразует их в 4 символа из 64-символьного алфавита.
Алфавит Base64 включает:
Латинские буквы: A-Z и a-z (52 символа)
Цифры: 0-9 (10 символов)
Два специальных символа: + и / (или - и _ в URL-совместимой версии)
Заполнитель = (если входные данные не кратны 3 байтам)
Пример кодирования
Допустим, у нас есть строка "Man":
Преобразуем в ASCII-коды:
Переводим в двоичный вид (каждый символ занимает 8 бит):
Разбиваем на 6-битные блоки (24 бита → 4 группы по 6 бит):
Соотносим с таблицей Base64:
Если входные данные не кратны 3 байтам, добавляются =:
Base64 в Java
Java предоставляет встроенный класс Base64 в пакете java.util, начиная с Java 8.
Кодирование строки в Base64
Вывод:
Декодирование Base64
Вывод:
Варианты Base64 в Java
В Java есть три основных варианта Base64:
1. Base64.getEncoder() и Base64.getDecoder() (обычная версия)
Использует стандартный алфавит A-Z, a-z, 0-9, +, / и =.
Пример:
2. Base64.getUrlEncoder() и Base64.getUrlDecoder() (для URL)
Использует безопасный для URL алфавит A-Z, a-z, 0-9, -, _ (заменяет + на - и / на _, убирает =).
Пример:
3. Base64.getMimeEncoder() и Base64.getMimeDecoder() (для MIME)
Форматирует выходные данные в 76-символьные строки, разделенные \r\n, подходит для шифрования PGP, email-передачи.
Пример:
#Java #Training #Medium #Java_Crypto_API #Base64
Base64 — это алгоритм кодирования двоичных данных в текстовый формат с использованием 64 символов ASCII. Он используется для представления бинарных данных в виде строк, удобных для передачи по сетевым протоколам и хранения в текстовых форматах. В Java Crypto API Base64 часто применяется для кодирования криптографических ключей, сертификатов и других бинарных данных.
Как работает Base64
Base64 берет 3 байта (24 бита) входных данных и преобразует их в 4 символа из 64-символьного алфавита.
Алфавит Base64 включает:
Латинские буквы: A-Z и a-z (52 символа)
Цифры: 0-9 (10 символов)
Два специальных символа: + и / (или - и _ в URL-совместимой версии)
Заполнитель = (если входные данные не кратны 3 байтам)
Пример кодирования
Допустим, у нас есть строка "Man":
Преобразуем в ASCII-коды:
M = 77, a = 97, n = 110
Переводим в двоичный вид (каждый символ занимает 8 бит):
M a n
01001101 01100001 01101110
Разбиваем на 6-битные блоки (24 бита → 4 группы по 6 бит):
010011 010110 000101 101110
Соотносим с таблицей Base64:
010011 → T
010110 → W
000101 → F
101110 → u
Результат кодирования: "TWFu"
Если входные данные не кратны 3 байтам, добавляются =:
"Ma" (2 байта) → TWE=
"M" (1 байт) → TQ==
Base64 в Java
Java предоставляет встроенный класс Base64 в пакете java.util, начиная с Java 8.
Кодирование строки в Base64
import java.util.Base64;
public class Base64Example {
public static void main(String[] args) {
String originalString = "Hello, Java Crypto API!";
String encodedString = Base64.getEncoder().encodeToString(originalString.getBytes());
System.out.println("Encoded: " + encodedString);
}
}
Вывод:
Encoded: SGVsbG8sIEphdmEgQ3J5cHRvIEFQISTCoA==
Декодирование Base64
import java.util.Base64;
public class Base64DecodeExample {
public static void main(String[] args) {
String encodedString = "SGVsbG8sIEphdmEgQ3J5cHRvIEFQISTCoA==";
byte[] decodedBytes = Base64.getDecoder().decode(encodedString);
String decodedString = new String(decodedBytes);
System.out.println("Decoded: " + decodedString);
}
}
Вывод:
Decoded: Hello, Java Crypto API!
Варианты Base64 в Java
В Java есть три основных варианта Base64:
1. Base64.getEncoder() и Base64.getDecoder() (обычная версия)
Использует стандартный алфавит A-Z, a-z, 0-9, +, / и =.
Пример:
Base64.Encoder encoder = Base64.getEncoder();
Base64.Decoder decoder = Base64.getDecoder();
String encoded = encoder.encodeToString("Test".getBytes());
String decoded = new String(decoder.decode(encoded));
System.out.println("Encoded: " + encoded);
System.out.println("Decoded: " + decoded);
2. Base64.getUrlEncoder() и Base64.getUrlDecoder() (для URL)
Использует безопасный для URL алфавит A-Z, a-z, 0-9, -, _ (заменяет + на - и / на _, убирает =).
Пример:
Base64.Encoder urlEncoder = Base64.getUrlEncoder();
Base64.Decoder urlDecoder = Base64.getUrlDecoder();
String encoded = urlEncoder.encodeToString("https://example.com".getBytes());
String decoded = new String(urlDecoder.decode(encoded));
System.out.println("Encoded URL: " + encoded);
System.out.println("Decoded URL: " + decoded);
3. Base64.getMimeEncoder() и Base64.getMimeDecoder() (для MIME)
Форматирует выходные данные в 76-символьные строки, разделенные \r\n, подходит для шифрования PGP, email-передачи.
Пример:
Base64.Encoder mimeEncoder = Base64.getMimeEncoder();
Base64.Decoder mimeDecoder = Base64.getMimeDecoder();
String encoded = mimeEncoder.encodeToString("Example MIME data".getBytes());
String decoded = new String(mimeDecoder.decode(encoded));
System.out.println("Encoded MIME: " + encoded);
System.out.println("Decoded MIME: " + decoded);
#Java #Training #Medium #Java_Crypto_API #Base64
Где применяется Base64
Передача бинарных данных в текстовом формате
Встраивание изображений в HTML и CSS:
Кодирование бинарных данных в JSON
Шифрование и подписи в криптографии
Используется для кодирования RSA-ключей, хэшей, токенов JWT
Пример работы с шифрованием AES:
HTTP-заголовки и авторизация
Basic Auth:
Передача данных по email (MIME)
Base64 используется в email-кодировании, Content-Transfer-Encoding: base64
Сериализация бинарных данных
Применяется для кодирования файлов в JSON, передаваемых через API.
Ограничения и недостатки
Увеличение размера
Base64 увеличивает размер данных на ~33% (3 байта → 4 символа).
Не защищает данные
Base64 — это не шифрование и не хэширование. Оно только преобразует данные в строковый вид, но не защищает их.
Обратимость
Закодированные данные легко декодируются, поэтому Base64 не подходит для хранения паролей.
#Java #Training #Medium #Java_Crypto_API #Base64
Передача бинарных данных в текстовом формате
Встраивание изображений в HTML и CSS:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." />
Кодирование бинарных данных в JSON
Шифрование и подписи в криптографии
Используется для кодирования RSA-ключей, хэшей, токенов JWT
Пример работы с шифрованием AES:
byte[] encryptedData = encryptAES("Hello".getBytes(), secretKey);
String base64Encoded = Base64.getEncoder().encodeToString(encryptedData);
HTTP-заголовки и авторизация
Basic Auth:
String auth = "user:password";
String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
String header = "Authorization: Basic " + encodedAuth;
Передача данных по email (MIME)
Base64 используется в email-кодировании, Content-Transfer-Encoding: base64
Сериализация бинарных данных
Применяется для кодирования файлов в JSON, передаваемых через API.
Ограничения и недостатки
Увеличение размера
Base64 увеличивает размер данных на ~33% (3 байта → 4 символа).
Не защищает данные
Base64 — это не шифрование и не хэширование. Оно только преобразует данные в строковый вид, но не защищает их.
Обратимость
Закодированные данные легко декодируются, поэтому Base64 не подходит для хранения паролей.
#Java #Training #Medium #Java_Crypto_API #Base64
Что выведет код
#Tasks
public class Task260225 {
public static void main(String[] args) {
String value = "10";
print(value);
print((byte) value);
print((Object) value);
}
public static void print(String x) {
System.out.println("String");
}
public static void print(byte x) {
System.out.println("byte");
}
public static void print(Object x) {
System.out.println("Object");
}
}
#Tasks
Варианты ответа:
Anonymous Quiz
35%
String byte Object
16%
int byte Object
5%
Ничегошеньки
43%
Ошибка компиляции
Please open Telegram to view this post
VIEW IN TELEGRAM
Вопросы с собеседования 👩💻
Что такое default метод в интерфейсе?
Что такое default метод в интерфейсе?
Anonymous Quiz
2%
Абстрактный метод
4%
Статический метод
93%
Метод с реализацией по умолчанию
0%
Приватный метод
Криптографические протоколы (TLS/SSL, HMAC) в Java Crypto API
Криптографические протоколы обеспечивают безопасную передачу данных по сети, защищая их от перехвата, подделки и модификации. В Java Crypto API основными протоколами являются TLS/SSL для защиты соединений и HMAC для проверки целостности данных.
TLS/SSL
TLS (Transport Layer Security) и устаревший SSL (Secure Sockets Layer) — это криптографические протоколы, обеспечивающие безопасное соединение между клиентом и сервером.
TLS заменил SSL, так как SSL имеет уязвимости. На сегодня актуальная версия — TLS 1.3.
Как TLS/SSL защищает соединение
Аутентификация сервера — клиент проверяет подлинность сервера с помощью SSL-сертификата.
Шифрование — передача данных в зашифрованном виде с помощью алгоритмов AES, ChaCha20, RSA.
Целостность — защита данных от подмены с помощью HMAC (Message Authentication Code).
TLS и HTTPS
HTTPS (HyperText Transfer Protocol Secure) — это HTTP + TLS/SSL.
Гарантирует шифрование и проверку подлинности при доступе к сайтам.
В браузере замок означает, что соединение защищено TLS.
Как работает TLS в Java
Java использует библиотеку JSSE (Java Secure Socket Extension) для работы с TLS/SSL.
Установление защищенного HTTPS-соединения
Для отправки HTTPS-запроса в Java используется HttpsURLConnection:
Использование своего SSLContext
Для работы с кастомными сертификатами можно использовать SSLContext:
#Java #Training #Medium #Java_Crypto_API #TLS #SSL
Криптографические протоколы обеспечивают безопасную передачу данных по сети, защищая их от перехвата, подделки и модификации. В Java Crypto API основными протоколами являются TLS/SSL для защиты соединений и HMAC для проверки целостности данных.
TLS/SSL
TLS (Transport Layer Security) и устаревший SSL (Secure Sockets Layer) — это криптографические протоколы, обеспечивающие безопасное соединение между клиентом и сервером.
TLS заменил SSL, так как SSL имеет уязвимости. На сегодня актуальная версия — TLS 1.3.
Как TLS/SSL защищает соединение
Аутентификация сервера — клиент проверяет подлинность сервера с помощью SSL-сертификата.
Шифрование — передача данных в зашифрованном виде с помощью алгоритмов AES, ChaCha20, RSA.
Целостность — защита данных от подмены с помощью HMAC (Message Authentication Code).
TLS и HTTPS
HTTPS (HyperText Transfer Protocol Secure) — это HTTP + TLS/SSL.
Гарантирует шифрование и проверку подлинности при доступе к сайтам.
В браузере замок означает, что соединение защищено TLS.
Как работает TLS в Java
Java использует библиотеку JSSE (Java Secure Socket Extension) для работы с TLS/SSL.
Установление защищенного HTTPS-соединения
Для отправки HTTPS-запроса в Java используется HttpsURLConnection:
import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
public class HttpsClient {
public static void main(String[] args) throws Exception {
URL url = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
// Проверка сертификата
conn.setSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault());
conn.setRequestMethod("GET");
// Чтение ответа
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
in.close();
}
}
Использование своего SSLContext
Для работы с кастомными сертификатами можно использовать SSLContext:
import javax.net.ssl.*;
import java.io.FileInputStream;
import java.security.KeyStore;
public class CustomSSLContext {
public static void main(String[] args) throws Exception {
String keystorePath = "keystore.jks"; // Файл хранилища ключей
String keystorePassword = "password";
// Загрузка ключей
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(keystorePath), keystorePassword.toCharArray());
// Инициализация KeyManagerFactory
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, keystorePassword.toCharArray());
// Создание SSL-контекста
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
// Использование SSLContext
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(socketFactory);
}
}
#Java #Training #Medium #Java_Crypto_API #TLS #SSL
HMAC (Hash-based Message Authentication Code)
HMAC — это механизм проверки целостности данных и аутентификации отправителя.
Основан на криптографических хеш-функциях (SHA-256, SHA-512).
Использует секретный ключ, что делает его безопаснее обычного хеширования.
Как работает HMAC
Клиент и сервер имеют секретный ключ.
Отправитель вычисляет HMAC от сообщения с этим ключом.
Получатель повторно вычисляет HMAC и проверяет совпадение.
Реализация HMAC в Java
Генерация HMAC (SHA-256)
Вывод:
Проверка HMAC
Где применяется HMAC
Аутентификация API-запросов
Многие API используют HMAC для подписи запросов (например, AWS, Binance API).
Клиент вычисляет HMAC и отправляет вместе с запросом.
Сервер проверяет правильность HMAC.
Целостность сообщений в TLS/SSL
В TLS 1.2 использовался HMAC для проверки целостности передаваемых данных.
Подпись JSON Web Tokens (JWT)
JWT использует HMAC для подписи (HMAC-SHA256).
Сервер проверяет подпись перед обработкой запроса.
Хранение паролей в базе данных
HMAC можно использовать для защиты паролей перед хешированием.
#Java #Training #Medium #Java_Crypto_API #HMAC
HMAC — это механизм проверки целостности данных и аутентификации отправителя.
Основан на криптографических хеш-функциях (SHA-256, SHA-512).
Использует секретный ключ, что делает его безопаснее обычного хеширования.
Как работает HMAC
Клиент и сервер имеют секретный ключ.
Отправитель вычисляет HMAC от сообщения с этим ключом.
Получатель повторно вычисляет HMAC и проверяет совпадение.
Реализация HMAC в Java
Генерация HMAC (SHA-256)
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class HmacExample {
public static void main(String[] args) throws Exception {
String message = "Hello, Java Crypto API!";
String secretKey = "my_secret_key";
// Создание HMAC SHA-256
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
mac.init(keySpec);
// Вычисление HMAC
byte[] hmacBytes = mac.doFinal(message.getBytes());
String hmacBase64 = Base64.getEncoder().encodeToString(hmacBytes);
System.out.println("HMAC (Base64): " + hmacBase64);
}
}
Вывод:
HMAC (Base64): q8phcxg9DpPpMfKkczjRkkv6OiOBv2YoTbYJ46qZaYc=
Проверка HMAC
public static boolean verifyHmac(String message, String receivedHmac, String secretKey) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
mac.init(keySpec);
// Вычисляем HMAC заново
byte[] hmacBytes = mac.doFinal(message.getBytes());
String computedHmac = Base64.getEncoder().encodeToString(hmacBytes);
// Сравниваем с полученным HMAC
return computedHmac.equals(receivedHmac);
}
Где применяется HMAC
Аутентификация API-запросов
Многие API используют HMAC для подписи запросов (например, AWS, Binance API).
Клиент вычисляет HMAC и отправляет вместе с запросом.
Сервер проверяет правильность HMAC.
Целостность сообщений в TLS/SSL
В TLS 1.2 использовался HMAC для проверки целостности передаваемых данных.
Подпись JSON Web Tokens (JWT)
JWT использует HMAC для подписи (HMAC-SHA256).
Сервер проверяет подпись перед обработкой запроса.
Хранение паролей в базе данных
HMAC можно использовать для защиты паролей перед хешированием.
#Java #Training #Medium #Java_Crypto_API #HMAC