1. Причина
Недавно на работе вдруг транзакция стала аномально медленной, а время звонка достигло 40wms, что серьезно повлияло на производительность всего кластера. Зная эту ситуацию, я начал анализировать всю транзакцию и в конце концов обнаружил, что это был котел алгоритма асимметричного шифрования RSA.
RSA — это алгоритм асимметричного шифрования, одна из важнейших особенностей которого заключается в том, что при передаче данных в сети,Ключ, используемый для шифрования данных, не нужно передавать вместе с данными.. Следовательно, это снижает вероятность компрометации ключей. RSA также полезен, когда шифрующей стороне не разрешено расшифровывать данные, шифрующая сторона использует ключ, называемыйоткрытый ключ, дешифрующая сторона использует другой ключ, называемыйзакрытый ключ, закрытый ключ должен оставаться закрытым.
RSA очень безопасен, но его эффективность очень низка.Длина его собственного ключа составляет 1024 бита.С развитием технологии разбора больших чисел длина ключа будет увеличиваться. В то же время, поскольку RSA будет блокировать поток при генерации случайных чисел для расшифровки, возникнет проблема перегрузки потока. Конечно, поскольку транзакций, использующих шифрование и дешифрование RSA, не так много, перегрузка считается особым случаем.
В общем, RSA — это неэффективный метод шифрования, который не подходит для шифрования большого объема данных, и даже в таких местах, как подписи, его следует использовать как можно реже, иначе он сильно повлияет на производительность.
Однако есть ограничения при написании этих кодов предыдущими коллегами: там, где требования безопасности не особо высоки, для шифрования используется RSA, и при этом не считается, что у этого модуля будет столько вызовов.
Итак, после тестирования и размышлений, я, наконец, решил обновить алгоритм шифрования и использовать алгоритм SM4.
2. Введение в национальный секретный алгоритм SM4
Алгоритм SMS4 — это алгоритм шифрования, используемый в широко распространенном в Китае стандарте беспроводной сети WAPI. Алгоритмы, используемые в процессе шифрования и дешифрования алгоритма SMS4, точно такие же, разница лишь в том, что ключ дешифрования алгоритма получается путем обратного преобразования его ключа шифрования.
Когда я собирался изучить алгоритм SM4, Китайский информационный центр сети Интернет больше не предоставлял стандартные документы для алгоритма SM4, поэтому мне пришлось выйти в интернет, чтобы проверить информацию. благодарныйВ этой статье вы познакомитесь с Java-реализацией отечественного алгоритма шифрования SM4.Эта статья.
1. Принцип алгоритма SM4
Структурная схема:
Мы видим, что к открытому тексту добавляется 128-битный секретный ключ, и после многих раундов преобразования окончательный результат представляет собой обратный порядок шифрования.При расшифровке порядок использования раундового ключа меняется на противоположный.
2. Сценарии применения алгоритма шифрования SM4
SM4 часто используется для шифрования передачи данных в государственных системах.Мы используем интерфейс для передачи информации на сервер или вызовы между различными модулями в распределенных сценариях.Этот алгоритм может быть использован. Зашифруйте данные параметров, а затем расшифруйте зашифрованные данные в фоновом режиме и сохраните их в базе данных, чтобы гарантировать отсутствие утечки данных в процессе передачи.
3. Реализация алгоритма SM4 java
Теперь я просто реализую функции шифрования и дешифрования алгоритма SM4.
Первый — это какие-то постоянные значения, в том числе кодировка, имя алгоритма, длина ключа и т. д. Лучше всего, если это возможно, написать значения параметров.
private static final String ENCODING = "UTF-8";
public static final String ALGORIGTHM_NAME = "SM4";
public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS7Padding";
public static final int DEFAULT_KEY_SIZE = 128;
Следующим шагом является генерация шифрования и дешифрования ECB.Шифрование и дешифрование осуществляются с помощью секретного ключа, освоенного бэкендом.Потому что алгоритм генерации секретного ключа тот же, и он используется в виде jar-пакета. , его можно записать вместе.
Функция этой функции заключается в использовании режима ECB (ECB (электронная кодовая книга, кодовая книга), режим ECB является одним из самых основных рабочих режимов блочных шифров. Зацикливание в зависимости от длины длины, будь то шифрование или дешифрование, в основном зависит от первые два параметра данных, чтобы решить.
Вот картинка, чтобы кратко представить несколько режимов.
/**
* @Description:生成ecb秘钥
*/
private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception {
Cipher cipher = Cipher.getInstance(algorithmName,BouncyCastleProvider.PROVIDER_NAME);
Key sm4Key = new SecretKeySpec(key, ALGORIGTHM_NAME);
cipher.init(mode, sm4Key);
return cipher;
}
/**
* @Description:自动生成密钥
*/
public static byte[] generateKey() throws Exception {
return generateKey(DEFAULT_KEY_SIZE);
}
public static byte[] generateKey(int keySize) throws Exception {
KeyGenerator kg = KeyGenerator.getInstance(ALGORIGTHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
kg.init(keySize, new SecureRandom());
return kg.generateKey().getEncoded();
}
Реализация конкретного класса шифрования и дешифрования выглядит следующим образом.:
/**
* @Description:加密
*/
public static String encryptEcb(String hexKey, String paramStr, String charset) throws Exception {
String cipherText = "";
if (null != paramStr && !"".equals(paramStr)) {
byte[] keyData = ByteUtils.fromHexString(hexKey);
charset = charset.trim();
if (charset.length() <= 0) {
charset = ENCODING;
}
byte[] srcData = paramStr.getBytes(charset);
byte[] cipherArray = encrypt_Ecb_Padding(keyData, srcData);
cipherText = ByteUtils.toHexString(cipherArray);
}
return cipherText;
}
/**
* @Description:加密模式之ecb
*/
public static byte[] encrypt_Ecb_Padding(byte[] key, byte[] data) throws Exception {
Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key);
byte[] bs = cipher.doFinal(data);
return bs;
/**
* @Description:sm4解密
*/
public static String decryptEcb(String hexKey, String cipherText, String charset) throws Exception {
String decryptStr = "";
byte[] keyData = ByteUtils.fromHexString(hexKey);
byte[] cipherData = ByteUtils.fromHexString(cipherText);
byte[] srcData = decrypt_Ecb_Padding(keyData, cipherData);
charset = charset.trim();
if (charset.length() <= 0) {
charset = ENCODING;
}
decryptStr = new String(srcData, charset);
return decryptStr;
}
/**
* @Description:ecb解密
*/
public static byte[] decrypt_Ecb_Padding(byte[] key, byte[] cipherText) throws Exception {
Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key);
return cipher.doFinal(cipherText);
}
}
Конечно, при выполнении тестов вы также можете добавить классы проверки.
/**
* @Description:密码校验
*/
public static boolean verifyEcb(String hexKey,String cipherText,String paramStr) throws Exception {
boolean flag = false;
byte[] keyData = ByteUtils.fromHexString(hexKey);
byte[] cipherData = ByteUtils.fromHexString(cipherText);
byte[] decryptData = decrypt_Ecb_Padding(keyData,cipherData);
byte[] srcData = paramStr.getBytes(ENCODING);
flag = Arrays.equals(decryptData,srcData);
return flag;
}
Наконец, добавьте простой тестовый класс, и все готово.Для проверки параллелизма используется пул потоков, и вы можете попробовать это сами.
/**
* @Description:测试类
*/
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(20,100,10, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());
Map map=new HashMap<>();
for (int i=0;i<1000;i++){
int finalI = i;
executor.submit(()->{
System.out.println(Thread.currentThread().getName());
int number = new Random().nextInt(100);
try {
long start,end;
start = System.currentTimeMillis();
String json = "{\"name\":\"color\",\"sex\":\"man\"}"+number;
// 自定义的32位16进制密钥
String key = "888368581322491ace9q79348a2757d1";
String cipher = Sm4Utils.encryptEcb(key, json,ENCODING);
System.out.println("加密之后:"+cipher);
Thread.sleep(100);
json = Sm4Utils.decryptEcb(key, cipher,ENCODING);
System.out.println("解密:"+json);
System.out.println(Sm4Utils.verifyEcb(key, cipher, json));
System.out.println("密码校验:"+json);
end = System.currentTimeMillis();
System.out.println(finalI+"Run Time:" + (end - start) + "(ms)");
map.put(finalI,json);
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
Некоторые скриншоты результатов выглядят следующим образом, вы можете попробовать сами
Иногда я могу ошибаться при использовании пакета jar, кстати, я выставлю пакет jar для всех
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
Нуждающиеся студенты могут добавить мой официальный аккаунт, последние статьи в будущем будут в нем впервые, или вы можете попросить у меня интеллект-карту