package com.ruoyi.system.utils;
|
|
import com.ruoyi.common.exception.ServiceException;
|
import org.apache.commons.codec.digest.DigestUtils;
|
|
import javax.crypto.Cipher;
|
import javax.crypto.spec.GCMParameterSpec;
|
import javax.crypto.spec.SecretKeySpec;
|
import java.nio.charset.StandardCharsets;
|
import java.security.SecureRandom;
|
import java.util.Arrays;
|
import java.util.Base64;
|
|
/**
|
* 门禁设备登录密码加解密工具。
|
*/
|
public final class DoorDeviceCredentialCrypto
|
{
|
private static final String ENV_KEY = "DOOR_DEVICE_CREDENTIAL_KEY";
|
private static final String SYSTEM_PROPERTY_KEY = "door.device.credential.key";
|
private static final String PREFIX = "v1:";
|
private static final byte[] AAD = "FangKeJiDoorDeviceCredential".getBytes(StandardCharsets.UTF_8);
|
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
|
|
private DoorDeviceCredentialCrypto()
|
{
|
}
|
|
public static String encrypt(String plainText)
|
{
|
if (plainText == null || plainText.length() == 0)
|
{
|
throw new ServiceException("设备登录密码不能为空");
|
}
|
try
|
{
|
byte[] nonce = new byte[12];
|
SECURE_RANDOM.nextBytes(nonce);
|
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
cipher.init(Cipher.ENCRYPT_MODE, secretKey(), new GCMParameterSpec(128, nonce));
|
cipher.updateAAD(AAD);
|
byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
|
byte[] payload = new byte[nonce.length + encrypted.length];
|
System.arraycopy(nonce, 0, payload, 0, nonce.length);
|
System.arraycopy(encrypted, 0, payload, nonce.length, encrypted.length);
|
return PREFIX + Base64.getEncoder().encodeToString(payload);
|
}
|
catch (ServiceException e)
|
{
|
throw e;
|
}
|
catch (Exception e)
|
{
|
throw new ServiceException("设备登录密码加密失败");
|
}
|
}
|
|
public static String decrypt(String cipherText)
|
{
|
if (cipherText == null || cipherText.length() == 0)
|
{
|
throw new ServiceException("设备未配置登录密码");
|
}
|
if (!cipherText.startsWith(PREFIX))
|
{
|
throw new ServiceException("设备登录密码密文版本不支持");
|
}
|
try
|
{
|
byte[] payload = Base64.getDecoder().decode(cipherText.substring(PREFIX.length()));
|
if (payload.length <= 28)
|
{
|
throw new IllegalArgumentException("invalid payload");
|
}
|
byte[] nonce = Arrays.copyOfRange(payload, 0, 12);
|
byte[] encrypted = Arrays.copyOfRange(payload, 12, payload.length);
|
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
cipher.init(Cipher.DECRYPT_MODE, secretKey(), new GCMParameterSpec(128, nonce));
|
cipher.updateAAD(AAD);
|
return new String(cipher.doFinal(encrypted), StandardCharsets.UTF_8);
|
}
|
catch (ServiceException e)
|
{
|
throw e;
|
}
|
catch (Exception e)
|
{
|
throw new ServiceException("设备登录密码解密失败,请检查主密钥");
|
}
|
}
|
|
private static SecretKeySpec secretKey()
|
{
|
String value = System.getProperty(SYSTEM_PROPERTY_KEY);
|
if (value == null || value.trim().length() == 0)
|
{
|
value = System.getenv(ENV_KEY);
|
}
|
if (value == null || value.length() < 32)
|
{
|
throw new ServiceException(ENV_KEY + " 必须配置且长度不能少于32位");
|
}
|
return new SecretKeySpec(Arrays.copyOf(DigestUtils.sha256(value), 16), "AES");
|
}
|
}
|