赞
踩
代码量过大,这里只展示了主要的逻辑,源代码已经放在github上
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Decrypt {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Encrypt {
}
@Slf4j @RestControllerAdvice public class EncryptResponseBodyAdvice implements ResponseBodyAdvice<Object> { private boolean encrypt; private final SecretProperties secretProperties; private final ThreadLocal<String> publicKey = new ThreadLocal<>(); private final ThreadLocal<String> privateKey = new ThreadLocal<>(); public EncryptResponseBodyAdvice(SecretProperties secretProperties) { this.secretProperties = secretProperties; LocalKeysInitFactory.initLocalKeys(secretProperties, this.publicKey, this.privateKey); } private static final ThreadLocal<Boolean> ENCRYPT_LOCAL = new ThreadLocal<>(); @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { encrypt = Objects.requireNonNull(returnType.getMethod()).isAnnotationPresent(Encrypt.class) && secretProperties.getEnable(); return encrypt; } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { Boolean status = ENCRYPT_LOCAL.get(); if (null != status && !status) { ENCRYPT_LOCAL.remove(); return body; } if (encrypt) { try { // bug fix key is null LocalKeysInitFactory.initLocalKeys(secretProperties, this.publicKey, this.privateKey); String content = new SerializationStrategy().serialize(body); if (!StringUtils.hasText(publicKey.get())) { throw new NullPointerException("Please configure secure.transmit.encrypt.publicKey parameter!"); } String result = SecureTransmitDigest.getInstance(secretProperties).encrypt(publicKey.get(), content); if (secretProperties.getIsShowLog()) { log.info("Pre-encrypted data:{},After encryption:{}", content, result); } return result; } catch (Exception e) { log.error("Encrypted data exception {}", e.getMessage(), e); throw new SecurityException("Encrypted data exception"); } finally { cleanUp(); } } return body; } /** * 清除当前的 缓存key */ private void cleanUp() { privateKey.remove(); publicKey.remove(); } }
@Slf4j @ControllerAdvice public class DecryptRequestBodyAdvice implements RequestBodyAdvice { /** * 是否开启加密 {@link SecretProperties#getEnable()} */ private boolean encrypt; /** * 安全信息配置 {@link SecretProperties} */ private final SecretProperties secretProperties; /** * 密钥和机密算法的配置 */ private final ThreadLocal<String> publicKey = new ThreadLocal<>(); private final ThreadLocal<String> privateKey = new ThreadLocal<>(); public DecryptRequestBodyAdvice(SecretProperties secretProperties) { this.secretProperties = secretProperties; LocalKeysInitFactory.initLocalKeys(secretProperties, this.publicKey, this.privateKey); } @Override public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { if (Objects.requireNonNull(methodParameter.getMethod()).isAnnotationPresent(Decrypt.class) && secretProperties.getEnable()) { encrypt = true; } return encrypt; } @Override public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { return body; } @Override public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { if (encrypt) { try { LocalKeysInitFactory.initLocalKeys(secretProperties, this.publicKey, this.privateKey); return new DecryptHttpInputMessage(inputMessage, privateKey.get(), secretProperties, secretProperties.getIsShowLog()); } catch (Exception e) { log.error("Decryption failed {}", e.getMessage(), e); throw new SecretException("DecryptRequestBodyAdvice.class error "); } finally { cleanUp(); } } return inputMessage; } @Override public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { return body; } /** * 清除当前的 缓存key */ private void cleanUp() { privateKey.remove(); publicKey.remove(); } }
@Slf4j public class RsaEncryption implements SecureTransmitTemplate { /** * RSA最大加密明文大小 */ private static final int MAX_ENCRYPT_BLOCK = 117; /** * RSA最大解密密文大小 */ private static final int MAX_DECRYPT_BLOCK = 128; /** * 使用给定的公钥加密给定的字符串。 * * @param key 给定的公钥。 * @param plaintext 字符串。 * @return 给定字符串的密文。 */ @Override public String encrypt(String key, String plaintext) { if (key == null || plaintext == null) { return null; } byte[] data = plaintext.getBytes(); try { PublicKey publicKey = DataKeyGenerator.RSA.getPublicKey(key); byte[] enData = encrypt(publicKey, data); return Base64.encodeBase64String(enData); } catch (Exception ex) { log.error("encryptString error {}", ex.getMessage()); } return null; } /** * 使用指定的公钥加密数据。 * * @param key 给定的公钥。 * @param data 要加密的数据。 * @return 加密后的数据。 */ private byte[] encrypt(Key key, byte[] data) throws Exception { Cipher ci = Cipher.getInstance(EncryptConstant.ALGORITHM); ci.init(Cipher.ENCRYPT_MODE, key); return getEnDeData(data, ci, MAX_ENCRYPT_BLOCK); } /** * 使用给定的公钥解密给定的字符串。 * * @param key 给定的公钥 * @param data 密文 * @return 原文字符串。 */ @Override public String decrypt(String key, String data) { if (key == null || isBlank(data)) { return null; } try { PrivateKey privateKey = DataKeyGenerator.RSA.getPrivateKey(key); byte[] enData = Base64.decodeBase64(data); return new String(decrypt(privateKey, enData)); } catch (Exception ex) { log.error(" Decryption failed. Cause: {} , error {}", data, ex.getCause().getMessage()); } return null; } /** * 使用指定的公钥解密数据。 * * @param key 指定的公钥 * @param data 要解密的数据 * @return 原数据 */ private static byte[] decrypt(Key key, byte[] data) throws Exception { Cipher ci = Cipher.getInstance(EncryptConstant.ALGORITHM); ci.init(Cipher.DECRYPT_MODE, key); return getEnDeData(data, ci, MAX_DECRYPT_BLOCK); } /** * 数据加解密 */ private static byte[] getEnDeData(byte[] data, Cipher ci, int maxBlock) throws Exception { int inputLen = data.length; byte[] edData; try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { int offSet = 0; byte[] cache; int i = 0; // 对数据分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > maxBlock) { cache = ci.doFinal(data, offSet, maxBlock); } else { cache = ci.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * maxBlock; } edData = out.toByteArray(); } return edData; } /** * 判断非空字符串 * * @param cs 待判断的CharSequence序列 * @return 是否非空 */ private static boolean isBlank(final CharSequence cs) { int strLen; if (cs == null || (strLen = cs.length()) == 0) { return true; } for (int i = 0; i < strLen; i++) { if (!Character.isWhitespace(cs.charAt(i))) { return false; } } return true; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。