предисловие
цифровой подписи,шифрование информацииЭто технология, которая часто используется во фронтенде и бэкенде.Сценарии приложений включают в себя вход пользователя в систему, транзакцию, обмен информацией,oauth
Подождите, разные сценарии приложений также должны будут использовать разные алгоритмы шифрования подписи или должны соответствовать разнымАлгоритм шифрования подписидля достижения целей бизнеса. Вот краткое введение в несколько распространенных алгоритмов шифрования подписи и приложений в некоторых типичных сценариях.
текст
1. Цифровая подпись
цифровой подписи, просто предоставивидентифицируемыйизцифровая информацияпроверятьличностьпрочь. наборцифровой подписиобычно определяют двадополнительныйоперации, одна дляподписать, другой дляпроверять. соответственно поотправительспособен удерживатьпредставлять себяиззакрытый ключ(закрытый ключ не может быть раскрыт),получательсодержит соответствующий закрытый ключоткрытый ключ, может быть вприниматьиспользуется, когда сообщение приходит от отправителяпроверятьего личность.
Уведомление: на картинкепроцесс шифрованияотличается отшифрование с открытым ключом,БолееВведение нажмите здесь.подписатьНаиболее фундаментальное использование состоит в том, чтобы иметь возможность однозначноПодтвердите личность отправителя,не допуститьатака «человек посередине»,
CSRF
Подделка междоменной идентификации. На основании этого вСертификация устройства,Аутентификация пользователя,сторонняя сертификацияи другие системы сертификации будут использоватьсяАлгоритм подписи(могут быть различия в том, как каждый реализован).
2. Шифрование и дешифрование
2.1 Шифрование
шифрование данныхОсновной процесс заключается впростой текстфайл или данные печатикакой-то алгоритмпроцесс, чтобы он сталнечитаемыйчасть кода, обычно называемая"зашифрованный текст". Таким образом, для достижениязащитить данныене бытьнезаконная кража, цель чтения.
2.2. Расшифровка
шифрованиеизобратный процессзарасшифровать, Собираюсьинформация о кодированиипреобразовать висходные данныепроцесс.
3. Симметричное и асимметричное шифрование
алгоритм шифрованияСимметричное шифрованиеиАсимметричное шифрование, в котором шифрование и дешифрование алгоритма симметричного шифрованиятот же ключ, ключ шифрования и расшифровка алгоритма асимметричного шифрованияразные ключи, кроме того, есть классключ не требуетсяизхеш-алгоритм.
ОбщийСимметричное шифрованиеАлгоритм в основном имеет
DES
,3DES
,AES
и т. д., общийАсимметричные алгоритмыЕстьRSA
,DSA
Ждать,хеш-алгоритмЕстьSHA-1
,MD5
Ждать.
3.1 Симметричное шифрование
Алгоритм симметричного шифрованияявляется применением более раннего алгоритма шифрования, также известного какАлгоритм шифрования с общим ключом. существуетАлгоритм симметричного шифрования, используется только один ключ,ОтправитьиперениматьОбе стороны используют этот ключ для шифрования данныхшифрованиеирасшифровать. Это требует, чтобы и шифрующая, и дешифрующая стороны заранее знали ключ шифрования.
-
Процесс шифрования данных: в алгоритме симметричного шифрованияотправитель данныхбудетпростой текст(необработанные данные) иключ шифрованиячерез специальныйШифрование, генераторный комплексзашифрованный зашифрованный текстотправлять.
-
Процесс расшифровки данных:получатель данныхПосле получения зашифрованного текста, если вы хотите прочитать исходные данные, вам нужно использоватьключ шифрованияи тот же алгоритмОбратный алгоритмРасшифруйте зашифрованный зашифрованный текст, чтобы восстановить егочитаемый открытый текст.
3.2 Асимметричное шифрование
Алгоритм асимметричного шифрования,Также известен какалгоритм шифрования с открытым ключом. Для этого требуется два ключа, один из которых называетсяоткрытый ключ (public key
),которыйоткрытый ключ, другой звонилзакрытый ключ (private key
),которыйзакрытый ключ.
так какшифрованиеирасшифроватьИспользуются два разных ключа, поэтому этот алгоритм называетсяАлгоритм асимметричного шифрования.
-
При использованииоткрытый ключк даннымшифровать, только с соответствующимзакрытый ключталантрасшифровать.
-
При использованиизакрытый ключк даннымшифровать, только с соответствующимоткрытый ключталантрасшифровать.
пример: Сторона А создаетпара ключейи возьмем один из них какоткрытый ключОткройте для других, получите открытый ключСторона БИспользуйте этот ключ для секретной информациишифроватьЗатем отправьте его Стороне А, и Сторона А воспользуется другим, сохраненным ею.закрытый ключ (закрытый ключ),правильношифрованиеинформация послерасшифровать.
4. Общие алгоритмы шифрования подписи
4.1 Алгоритм MD5
MD5
используетсяхэш-функция, его типичное применение — генерировать часть информацииСводка информации,отзащищенный от несанкционированного доступа. строго говоря,MD5
не видАлгоритм шифрованияноАлгоритм дайджеста. Независимо от того, как долго ввод,MD5
выведет длину128bits
строка (обычно используется16
базаВыражается как32
символы).
public static final byte[] computeMD5(byte[] content) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
return md5.digest(content);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
4.2 Алгоритм SHA1
SHA1
да иMD5
как популярныйалгоритм дайджеста сообщения,Тем не мениеSHA1
СравниватьMD5
изболее безопасный. Для длин менее2 ^ 64
битовое сообщение,SHA1
произведет160
немногоДайджест сообщения. на основеMD5
,SHA1
Функция сводки информации , инеобратимый(в общем), можно использовать для проверкицелостность файлаа такжецифровой подписисцена.
public static byte[] computeSHA1(byte[] content) {
try {
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
return sha1.digest(content);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
4.3 Алгоритм HMAC
HMAC
связано с ключомХэш-код аутентификации сообщения(Код аутентификации сообщения на основе хэша),HMAC
Оперативное использованиехеш-алгоритм (MD5
,SHA1
д.), сключисообщениеДля ввода сгенерируйтеДайджест сообщенияв видевывод.
HMAC
отправительиполучательобаkey
делать расчеты без этогоkey
третье лицо, этоНевозможно рассчитатьиз правильногохэш-значениеДа так, чтоПредотвращение подделки данных.
package net.pocrd.util;
import net.pocrd.annotation.NotThreadSafe;
import net.pocrd.define.ConstField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;
@NotThreadSafe
public class HMacHelper {
private static final Logger logger = LoggerFactory.getLogger(HMacHelper.class);
private Mac mac;
/**
* MAC算法可选以下多种算法
* HmacMD5/HmacSHA1/HmacSHA256/HmacSHA384/HmacSHA512
*/
private static final String KEY_MAC = "HmacMD5";
public HMacHelper(String key) {
try {
SecretKey secretKey = new SecretKeySpec(key.getBytes(ConstField.UTF8), KEY_MAC);
mac = Mac.getInstance(secretKey.getAlgorithm());
mac.init(secretKey);
} catch (Exception e) {
logger.error("create hmac helper failed.", e);
}
}
public byte[] sign(byte[] content) {
return mac.doFinal(content);
}
public boolean verify(byte[] signature, byte[] content) {
try {
byte[] result = mac.doFinal(content);
return Arrays.equals(signature, result);
} catch (Exception e) {
logger.error("verify sig failed.", e);
}
return false;
}
}
Заключение теста:
HMAC
Пример алгоритма находится вмногопоточная средаследующийнебезопасный. Но нужномногопоточный доступКогда вспомогательный класс для синхронизации использоватьThreadLocal
зана кэш потокаЭкземпляр может избежать операций блокировки.
4.4 Алгоритм AES/DES/3DES
AES
,DES
,3DES
обасимметрияизблочный алгоритм шифрования,Шифрование и дешифрованиеПроцессобратимый. Обычно используютсяAES128
,AES192
,AES256
(устанавливается по умолчаниюJDK
Пока не поддерживаетсяAES256
, необходимо установить соответствующийjce
Патч для обновленияjce1.7
,jce1.8
).
4.4.1 Алгоритм DES
DES
алгоритм шифрования этоблочный шифр,от64
битсгруппированные данныешифрование, егодлина ключада56
немного,шифровать и декодироватьиспользоватьтот же алгоритм.
DES
алгоритм шифрованияключсохранять конфиденциальность иобщедоступный алгоритм, включая алгоритмы шифрования и дешифрования. Таким образом, только мастер и отправительтот же ключлюдей могут интерпретироватьDES
Данные зашифрованного текста, зашифрованные алгоритмом шифрования. Таким образом, расшифровкаDES
Алгоритм шифрования на самом делеКодировка ключа поиска. за56
битовая длинаключНапример, если использоватьИсчерпывающий методДля поиска количество операций2 ^ 56
Второсортный.
4.4.2 Алгоритм 3DES
основан наDES
изСимметричный алгоритм,правильночасть данныхиспользоватьтри разных ключапровестиТройное шифрование,более высокая прочность.
4.4.3 Алгоритм AES
AES
Алгоритм шифрования находится в криптографииРасширенный стандарт шифрования, алгоритм шифрования используетСимметричная блочная система шифрования, минимальная поддерживаемая длина ключа128
немного,192
немного,256
Бит, длина пакета128
бит, алгоритм должен легко реализовываться в различных аппаратных и программных средствах. Этот алгоритм шифрования используется федеральным правительством США.Стандарт блочного шифрования.
AES
сам должен заменитьDES
из,AES
с лучшимбезопасность,эффективныйигибкость.
import net.pocrd.annotation.NotThreadSafe;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
@NotThreadSafe
public class AesHelper {
private SecretKeySpec keySpec;
private IvParameterSpec iv;
public AesHelper(byte[] aesKey, byte[] iv) {
if (aesKey == null || aesKey.length < 16 || (iv != null && iv.length < 16)) {
throw new RuntimeException("错误的初始密钥");
}
if (iv == null) {
iv = Md5Util.compute(aesKey);
}
keySpec = new SecretKeySpec(aesKey, "AES");
this.iv = new IvParameterSpec(iv);
}
public AesHelper(byte[] aesKey) {
if (aesKey == null || aesKey.length < 16) {
throw new RuntimeException("错误的初始密钥");
}
keySpec = new SecretKeySpec(aesKey, "AES");
this.iv = new IvParameterSpec(Md5Util.compute(aesKey));
}
public byte[] encrypt(byte[] data) {
byte[] result = null;
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
result = cipher.doFinal(data);
} catch (Exception e) {
throw new RuntimeException(e);
}
return result;
}
public byte[] decrypt(byte[] secret) {
byte[] result = null;
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
result = cipher.doFinal(secret);
} catch (Exception e) {
throw new RuntimeException(e);
}
return result;
}
public static byte[] randomKey(int size) {
byte[] result = null;
try {
KeyGenerator gen = KeyGenerator.getInstance("AES");
gen.init(size, new SecureRandom());
result = gen.generateKey().getEncoded();
} catch (Exception e) {
throw new RuntimeException(e);
}
return result;
}
}
4.5 Алгоритм RSA
RSA
Алгоритм шифрования в настоящее время является наиболее влиятельнымалгоритм шифрования с открытым ключом, и обычно считается текущимЛучшая схема с открытым ключомодин.RSA
является первым, который используется одновременношифрованиеицифровой подписиалгоритм, который можетсопротивлениеизвестно до сих порВсе атаки на пароль,БылISO
Рекомендуется в качестве стандарта шифрования данных с открытым ключом.
RSA
Алгоритм шифрованияОснованный на очень простом факте теории чисел: объединении двух большихпростое числоУмножать легко, но хочется сделатьфакторизациячрезвычайно сложно, поэтомупродуктпубличный какключ шифрования.
import net.pocrd.annotation.NotThreadSafe;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.Security;
import java.security.Signature;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
@NotThreadSafe
public class RsaHelper {
private static final Logger logger = LoggerFactory.getLogger(RsaHelper.class);
private RSAPublicKey publicKey;
private RSAPrivateCrtKey privateKey;
static {
Security.addProvider(new BouncyCastleProvider()); //使用bouncycastle作为加密算法实现
}
public RsaHelper(String publicKey, String privateKey) {
this(Base64Util.decode(publicKey), Base64Util.decode(privateKey));
}
public RsaHelper(byte[] publicKey, byte[] privateKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
if (publicKey != null && publicKey.length > 0) {
this.publicKey = (RSAPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
}
if (privateKey != null && privateKey.length > 0) {
this.privateKey = (RSAPrivateCrtKey)keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public RsaHelper(String publicKey) {
this(Base64Util.decode(publicKey));
}
public RsaHelper(byte[] publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
if (publicKey != null && publicKey.length > 0) {
this.publicKey = (RSAPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public byte[] encrypt(byte[] content) {
if (publicKey == null) {
throw new RuntimeException("public key is null.");
}
if (content == null) {
return null;
}
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
int size = publicKey.getModulus().bitLength() / 8 - 11;
ByteArrayOutputStream baos = new ByteArrayOutputStream((content.length + size - 1) / size * (size + 11));
int left = 0;
for (int i = 0; i < content.length; ) {
left = content.length - i;
if (left > size) {
cipher.update(content, i, size);
i += size;
} else {
cipher.update(content, i, left);
i += left;
}
baos.write(cipher.doFinal());
}
return baos.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public byte[] decrypt(byte[] secret) {
if (privateKey == null) {
throw new RuntimeException("private key is null.");
}
if (secret == null) {
return null;
}
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
int size = privateKey.getModulus().bitLength() / 8;
ByteArrayOutputStream baos = new ByteArrayOutputStream((secret.length + size - 12) / (size - 11) * size);
int left = 0;
for (int i = 0; i < secret.length; ) {
left = secret.length - i;
if (left > size) {
cipher.update(secret, i, size);
i += size;
} else {
cipher.update(secret, i, left);
i += left;
}
baos.write(cipher.doFinal());
}
return baos.toByteArray();
} catch (Exception e) {
logger.error("rsa decrypt failed.", e);
}
return null;
}
public byte[] sign(byte[] content) {
if (privateKey == null) {
throw new RuntimeException("private key is null.");
}
if (content == null) {
return null;
}
try {
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initSign(privateKey);
signature.update(content);
return signature.sign();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public boolean verify(byte[] sign, byte[] content) {
if (publicKey == null) {
throw new RuntimeException("public key is null.");
}
if (sign == null || content == null) {
return false;
}
try {
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(publicKey);
signature.update(content);
return signature.verify(sign);
} catch (Exception e) {
logger.error("rsa verify failed.", e);
}
return false;
}
}
4.6 Алгоритм ЕСС
ECC
такжеАлгоритм асимметричного шифрования, главное преимущество в том, что в некоторых случаях он используется по сравнению с другими методамименьший ключ,НапримерRSA
Алгоритм шифрования,поставкаэквивалент или вышеуровень безопасности. Но один недостаток в том, чтоОперации шифрования и дешифрованияреализации, чем другие механизмымного времени(по сравнению сRSA
алгоритм, которыйCPU
сильное потребление).
import net.pocrd.annotation.NotThreadSafe;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.Security;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
@NotThreadSafe
public class EccHelper {
private static final Logger logger = LoggerFactory.getLogger(EccHelper.class);
private static final int SIZE = 4096;
private BCECPublicKey publicKey;
private BCECPrivateKey privateKey;
static {
Security.addProvider(new BouncyCastleProvider());
}
public EccHelper(String publicKey, String privateKey) {
this(Base64Util.decode(publicKey), Base64Util.decode(privateKey));
}
public EccHelper(byte[] publicKey, byte[] privateKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
if (publicKey != null && publicKey.length > 0) {
this.publicKey = (BCECPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
}
if (privateKey != null && privateKey.length > 0) {
this.privateKey = (BCECPrivateKey)keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
}
} catch (ClassCastException e) {
throw new RuntimeException("", e);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public EccHelper(String publicKey) {
this(Base64Util.decode(publicKey));
}
public EccHelper(byte[] publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
if (publicKey != null && publicKey.length > 0) {
this.publicKey = (BCECPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public byte[] encrypt(byte[] content) {
if (publicKey == null) {
throw new RuntimeException("public key is null.");
}
try {
Cipher cipher = Cipher.getInstance("ECIES", "BC");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
int size = SIZE;
ByteArrayOutputStream baos = new ByteArrayOutputStream((content.length + size - 1) / size * (size + 45));
int left = 0;
for (int i = 0; i < content.length; ) {
left = content.length - i;
if (left > size) {
cipher.update(content, i, size);
i += size;
} else {
cipher.update(content, i, left);
i += left;
}
baos.write(cipher.doFinal());
}
return baos.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public byte[] decrypt(byte[] secret) {
if (privateKey == null) {
throw new RuntimeException("private key is null.");
}
try {
Cipher cipher = Cipher.getInstance("ECIES", "BC");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
int size = SIZE + 45;
ByteArrayOutputStream baos = new ByteArrayOutputStream((secret.length + size + 44) / (size + 45) * size);
int left = 0;
for (int i = 0; i < secret.length; ) {
left = secret.length - i;
if (left > size) {
cipher.update(secret, i, size);
i += size;
} else {
cipher.update(secret, i, left);
i += left;
}
baos.write(cipher.doFinal());
}
return baos.toByteArray();
} catch (Exception e) {
logger.error("ecc decrypt failed.", e);
}
return null;
}
public byte[] sign(byte[] content) {
if (privateKey == null) {
throw new RuntimeException("private key is null.");
}
try {
Signature signature = Signature.getInstance("SHA1withECDSA", "BC");
signature.initSign(privateKey);
signature.update(content);
return signature.sign();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public boolean verify(byte[] sign, byte[] content) {
if (publicKey == null) {
throw new RuntimeException("public key is null.");
}
try {
Signature signature = Signature.getInstance("SHA1withECDSA", "BC");
signature.initVerify(publicKey);
signature.update(content);
return signature.verify(sign);
} catch (Exception e) {
logger.error("ecc verify failed.", e);
}
return false;
}
}
5. Сравнение различных алгоритмов шифрования
5.1 Сравнение алгоритмов хеширования
название | безопасность | скорость |
---|---|---|
SHA-1 | высокий | медленный |
MD5 | середина | быстрый |
5.2 Сравнение алгоритмов симметричного шифрования
название | имя ключа | скорость бега | безопасность | НЧ |
---|---|---|---|---|
DES | 56 бит | Быстрее | Низкий | середина |
3DES | 112-битный или 168-битный | медленный | середина | высокий |
AES | 128, 192, 256 бит | быстрый | высокий | Низкий |
5.3 Сравнение алгоритмов асимметричного шифрования
название | зрелость | безопасность | расчет скорости | НЧ |
---|---|---|---|---|
RSA | высокий | высокий | середина | середина |
ECC | высокий | высокий | медленный | высокий |
5.4 Алгоритмы симметричного и асимметричного шифрования
5.4.1 Симметричные алгоритмы
-
ключевой менеджмент: более сложный, не подходит для Интернета, обычно используется для внутренних систем.
-
безопасность:середина
-
скорость шифрования: хорошо скореенесколько порядков(Программное шифрование и скорость дешифрования не ниже высокой
100
раз, количество шифровок и расшифровок в секундуM
битыданные), подходит для шифрования и дешифрования обработки больших объемов данных
5.4.2 Асимметричные алгоритмы
-
ключевой менеджмент: Клавишами легко управлять
-
безопасность:высокий
-
скорость шифрования: относительно медленный, подходящийнебольшой объем данныхШифрование и дешифрование или подпись данных
резюме
В этой статье описываетсяцифровой подписи,Шифровать и расшифровывать,Симметричное и асимметричное шифрование, а потом подробностиMD5
,SHA-1
,HMAC
,DES/AES
,RSA
иECC
Эти несколько алгоритмов шифрования и примеры кода.
Добро пожаловать в технический публичный аккаунт: Zero One Technology Stack
Эта учетная запись будет продолжать делиться сухими товарами серверных технологий, включая основы виртуальных машин, многопоточное программирование, высокопроизводительные фреймворки, асинхронное ПО, промежуточное ПО для кэширования и обмена сообщениями, распределенные и микросервисы, материалы для обучения архитектуре и расширенные учебные материалы и статьи.