| | |
| | | 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; |
| | |
| | | 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) { |
| | |
| | | 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 "v1:" + Base64.getUrlEncoder().withoutPadding().encodeToString(payload); |
| | | 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, "敏感信息解密失败"); |
| | | } |
| | | } |
| | | } |