package com.talentcard.server.common;
|
|
import java.nio.charset.StandardCharsets;
|
import java.security.MessageDigest;
|
import java.security.SecureRandom;
|
import java.util.Arrays;
|
import java.util.Base64;
|
|
import javax.crypto.Cipher;
|
import javax.crypto.spec.GCMParameterSpec;
|
import javax.crypto.spec.SecretKeySpec;
|
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Component;
|
|
@Component
|
public class SensitiveDataCrypto {
|
|
private static final SecureRandom RANDOM = new SecureRandom();
|
private static final String VERSION_PREFIX = "v1:";
|
private final byte[] key;
|
|
public SensitiveDataCrypto(@Value("${app.privacy.encryption-key}") String encryptionKey) {
|
try {
|
this.key = MessageDigest.getInstance("SHA-256").digest(encryptionKey.getBytes(StandardCharsets.UTF_8));
|
} catch (Exception exception) {
|
throw new IllegalStateException("Unable to initialize sensitive-data encryption", exception);
|
}
|
}
|
|
public String encrypt(String plainText) {
|
if (plainText == null || plainText.isBlank()) return "";
|
try {
|
byte[] iv = new byte[12];
|
RANDOM.nextBytes(iv);
|
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, iv));
|
byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
|
byte[] payload = new byte[iv.length + encrypted.length];
|
System.arraycopy(iv, 0, payload, 0, iv.length);
|
System.arraycopy(encrypted, 0, payload, iv.length, encrypted.length);
|
return VERSION_PREFIX + Base64.getUrlEncoder().withoutPadding().encodeToString(payload);
|
} catch (Exception exception) {
|
throw new BusinessException(ErrorCode.INTERNAL_ERROR, "敏感信息加密失败");
|
}
|
}
|
|
public String decrypt(String cipherText) {
|
if (cipherText == null || cipherText.isBlank()) return "";
|
if (!cipherText.startsWith(VERSION_PREFIX)) return cipherText;
|
try {
|
byte[] payload = Base64.getUrlDecoder().decode(cipherText.substring(VERSION_PREFIX.length()));
|
if (payload.length <= 12) {
|
throw new IllegalArgumentException("Invalid encrypted payload");
|
}
|
byte[] iv = 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, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, iv));
|
return new String(cipher.doFinal(encrypted), StandardCharsets.UTF_8);
|
} catch (Exception exception) {
|
throw new BusinessException(ErrorCode.INTERNAL_ERROR, "敏感信息解密失败");
|
}
|
}
|
}
|