All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.siashan.toolkit.crypt.symmetric.SymmetricCrypt Maven / Gradle / Ivy

package com.siashan.toolkit.crypt.symmetric;

import com.siashan.toolkit.crypt.CryptException;
import com.siashan.toolkit.crypt.DecoderException;
import com.siashan.toolkit.crypt.KeyUtil;
import com.siashan.toolkit.crypt.SecureUtil;
import com.siashan.toolkit.crypt.binary.Base64;
import com.siashan.toolkit.crypt.binary.Hex;
import com.siashan.toolkit.crypt.util.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * 对称加密算法
* 在对称加密算法中,数据发信方将明文(原始数据)和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。
* 收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。
* 在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。
* * @author siashan * @since 1.0.7 */ public abstract class SymmetricCrypt implements Serializable { private static final long serialVersionUID = 1L; private static final Charset UTF_8 = StandardCharsets.UTF_8; /** * Cipher负责完成加密或解密工作 */ private Cipher cipher; /** * 是否0填充 */ private boolean zeroPadding; public SymmetricCrypt() { } /** * 构建加密对象 * * @param algorithm 算法 {@link SymmetricAlgorithm } * @param mode 加密模式 * @param padding 填充模式 * @return 加密对象 */ public SymmetricCrypt(SymmetricAlgorithm algorithm, Mode mode, Padding padding) { String fmtAlgorithm = SecureUtil.fmtAlgorithm(algorithm, mode, padding); if (fmtAlgorithm.contains(Padding.ZeroPadding.name())) { fmtAlgorithm = fmtAlgorithm.replace(Padding.ZeroPadding.name(), Padding.NoPadding.name()); this.zeroPadding = true; } this.cipher = SecureUtil.createCipher(fmtAlgorithm); } public abstract SymmetricAlgorithm getAlgorithm(); // -------------------------------------------------- Encrypt ----------------------------------------------------// /** * 加密 * * @param data 被加密的bytes * @param key 秘钥,支持三种密钥长度:128、192、256位 * @param iv 加密盐/加密向量 * @return 加密后的bytes */ private byte[] encrypt(byte[] data, SecretKey key, IvParameterSpec iv) { try { if (null == iv) { cipher.init(Cipher.ENCRYPT_MODE, key); } else { cipher.init(Cipher.ENCRYPT_MODE, key, iv); } return cipher.doFinal(paddingDataWithZero(data, cipher.getBlockSize(), zeroPadding)); } catch (Exception e) { throw new CryptException(e); } } /** * 加密 * * @param data 被加密的bytes * @param key 秘钥,支持三种密钥长度:128、192、256位 * @return 加密后的bytes */ public byte[] encrypt(byte[] data, byte[] key) { return encrypt(data, KeyUtil.genKey(getAlgorithm().name(), key), null); } /** * 加密 * * @param data 数据 * @param key 秘钥 * @return 加密后的Hex */ public String encryptHex(byte[] data, byte[] key) { return Hex.encodeHexString(encrypt(data, key)); } /** * 加密 * * @param data 数据 * @param key 秘钥 * @return 加密后的Base64 */ public String encryptBase64(byte[] data, byte[] key) { return Base64.encodeBase64String(encrypt(data, key)); } /** * 加密 * * @param data 被加密的bytes * @param key 秘钥,支持三种密钥长度:128、192、256位 * @return 加密后的bytes */ public byte[] encrypt(byte[] data, String key) { return encrypt(data, key.getBytes()); } /** * 加密 * * @param data 被加密的bytes * @param key 秘钥,支持三种密钥长度:128、192、256位 * @return 加密后的Hex */ public String encryptHex(byte[] data, String key) { return Hex.encodeHexString(encrypt(data, key)); } /** * 加密 * * @param data 数据 * @param key 秘钥 * @return 加密后的Base64 */ public String encryptBase64(byte[] data, String key) { return Base64.encodeBase64String(encrypt(data, key)); } /** * 加密 * * @param data 被加密的字符串 * @param key 秘钥,支持三种密钥长度:128、192、256位 * @return 加密后的bytes */ public byte[] encrypt(String data, byte[] key) { return encrypt(data.getBytes(UTF_8), key); } /** * 加密 * * @param data 被加密的字符串 * @param key 秘钥,支持三种密钥长度:128、192、256位 * @return 加密后的Hex */ public String encryptHex(String data, byte[] key) { return Hex.encodeHexString(encrypt(data, key)); } /** * 加密 * * @param data 被加密的字符串 * @param key 秘钥,支持三种密钥长度:128、192、256位 * @return 加密后的Hex */ public String encryptBase64(String data, byte[] key) { return Base64.encodeBase64String(encrypt(data, key)); } /** * 加密 * * @param data 被加密的字符串 * @param key 秘钥,支持三种密钥长度:128、192、256位 * @return 加密后的bytes */ public byte[] encrypt(String data, String key) { return encrypt(data.getBytes(UTF_8), key.getBytes(UTF_8)); } /** * 加密 * * @param data 被加密的字符串 * @param key 秘钥,支持三种密钥长度:128、192、256位 * @return 加密后的Hex */ public String encryptHex(String data, String key) { return Hex.encodeHexString(encrypt(data, key)); } /** * 加密 * * @param data 被加密的字符串 * @param key 秘钥,支持三种密钥长度:128、192、256位 * @return 加密后的Hex */ public String encryptBase64(String data, String key) { return Base64.encodeBase64String(encrypt(data, key)); } /** * 加密 * * @param data 被加密的bytes * @param key 秘钥,支持三种密钥长度:128、192、256位 * @param iv 加密盐/加密向量 * @return 加密后的bytes */ public byte[] encrypt(byte[] data, byte[] key, byte[] iv) { return encrypt(data, KeyUtil.genKey(cipher.getAlgorithm(), key), new IvParameterSpec(iv)); } /** * 加密 * * @param data 被加密的bytes * @param key 秘钥,支持三种密钥长度:128、192、256位 * @param iv 加密盐/加密向量 * @return 加密后的Hex */ public String encryptHex(byte[] data, byte[] key, byte[] iv) { return Hex.encodeHexString(encrypt(data, key, iv)); } /** * 加密 * * @param data 被加密的bytes * @param key 秘钥,支持三种密钥长度:128、192、256位 * @param iv 加密盐/加密向量 * @return 加密后的Base64字符串 */ public String encryptBase64(byte[] data, byte[] key, byte[] iv) { return Base64.encodeBase64String(encrypt(data, key, iv)); } /** * 加密 * * @param data 被加密的bytes * @param key 秘钥,支持三种密钥长度:128、192、256位 * @param iv 加密盐/加密向量 * @return 加密后的bytes */ public byte[] encrypt(String data, String key, String iv) { return encrypt(data.getBytes(UTF_8), key.getBytes(UTF_8), iv.getBytes(UTF_8)); } /** * 加密 * * @param data 被加密的明文字符串 * @param key 秘钥,支持三种密钥长度:128、192、256位 * @param iv 加密盐/加密向量 * @return 加密后的Hex */ public String encryptHex(String data, String key, String iv) { return Hex.encodeHexString(encrypt(data, key, iv)); } /** * 加密 * * @param data 被加密的明文字符串 * @param key 秘钥,支持三种密钥长度:128、192、256位 * @param iv 加密盐/加密向量 * @return 加密后的Base64字符串 */ public String encryptBase64(String data, String key, String iv) { return Base64.encodeBase64String(encrypt(data, key, iv)); } // -------------------------------------------- Decrypt ----------------------------------------------------------// /** * 解密 * * @param data 被加密的bytes * @param key 秘钥,支持三种密钥长度:128、192、256位 * @param iv 加密盐/加密向量 * @return 解密后的bytes */ private byte[] decrypt(byte[] data, SecretKey key, IvParameterSpec iv) { final int blockSize; final byte[] decryptData; try { if (null == iv) { cipher.init(Cipher.DECRYPT_MODE, key); } else { cipher.init(Cipher.DECRYPT_MODE, key, iv); } blockSize = cipher.getBlockSize(); decryptData = cipher.doFinal(data); } catch (Exception e) { throw new CryptException(e); } return removePadding(decryptData, blockSize); } /** * 解密 * * @param data 被加密的bytes * @param key 秘钥,支持三种密钥长度:128、192、256位 * @return 解密后的bytes */ public byte[] decrypt(byte[] data, byte[] key) { return decrypt(data, KeyUtil.genKey(getAlgorithm().name(), key), null); } /** * 解密为字符串 * * @param bytes 被解密的bytes * @param key 秘钥 * @return 解密后的String */ public String decryptStr(byte[] bytes, byte[] key) { return StringUtils.newStringUtf8(decrypt(bytes, key)); } /** * 解密 * * @param data 被加密的bytes * @param key 秘钥,支持三种密钥长度:128、192、256位 * @param iv 加密向量 * @return 解密后的bytes */ public byte[] decrypt(byte[] data, byte[] key, byte[] iv) { return decrypt(data, KeyUtil.genKey(getAlgorithm().name(), key), new IvParameterSpec(iv)); } /** * 解密 * * @param data 被加密的bytes * @param key 秘钥,支持三种密钥长度:128、192、256位 * @param iv 加密向量 * @return 解密后的bytes */ public String decryptToStr(byte[] data, byte[] key, byte[] iv) { return StringUtils.newStringUtf8(decrypt(data, key, iv)); } /** * 解密Hex(16进制)表示的字符串 * * @param data 被解密的String,必须为16进制字符串 * @return 解密后的bytes */ public byte[] decryptHex(String data, byte[] key) throws DecoderException { return decrypt(Hex.decodeHex(data), key); } /** * 解密Hex(16进制)表示的字符串 * * @param data 被解密的String,必须为16进制字符串 * @param key 秘钥 * @param iv 加密向量 * @return 解密后的bytes */ public byte[] decryptHex(String data, byte[] key, byte[] iv) throws DecoderException { return decrypt(Hex.decodeHex(data), key, iv); } /** * 解密Hex(16进制)表示的字符串 * * @param data 被解密的String,必须为16进制字符串 * @param key 秘钥 * @return 解密后的字符串 */ public String decryptHexToStr(String data, byte[] key) throws DecoderException { return StringUtils.newStringUtf8(decrypt(Hex.decodeHex(data), key)); } /** * 解密Hex(16进制)表示的字符串 * * @param data 被解密的String,必须为16进制字符串 * @param key 秘钥 * @param iv 加密向量 * @return 解密后的字符串 */ public String decryptHexToStr(String data, byte[] key, byte[] iv) throws DecoderException { return StringUtils.newStringUtf8(decrypt(Hex.decodeHex(data), key, iv)); } /** * 解密Base64表示的字符串 * * @param data 被解密的String,必须Base64字符串 * @return 解密后的bytes */ public byte[] decryptBase64(String data, byte[] key) { return decrypt(Base64.decodeBase64(data), key); } /** * 解密Base64表示的字符串 * * @param data 被解密的String,必须Base64字符串 * @param key 秘钥 * @param iv 加密向量 * @return 解密后的bytes */ public byte[] decryptBase64(String data, byte[] key, byte[] iv) { return decrypt(Base64.decodeBase64(data), key, iv); } /** * 解密Base64表示的字符串 * * @param data 被解密的String,必须Base64字符串 * @return 解密后的字符串 */ public String decryptBase64ToStr(String data, byte[] key) { return StringUtils.newStringUtf8(decrypt(Base64.decodeBase64(data), key)); } /** * 解密Base64表示的字符串 * * @param data 被解密的String,必须Base64字符串 * @param key 秘钥 * @param iv 加密向量 * @return 解密后的字符串 */ public String decryptBase64ToStr(String data, byte[] key, byte[] iv) { return StringUtils.newStringUtf8(decrypt(Base64.decodeBase64(data), key, iv)); } // --------------------------------------------------------------------------------- Private method start /** * 数据按照blockSize的整数倍长度填充填充0 * *

* 在{@link Padding#ZeroPadding} 模式下,且数据长度不是blockSize的整数倍才有效,否则返回原数据 * *

* 见:https://blog.csdn.net/OrangeJack/article/details/82913804 * * @param data 数据 * @param blockSize 块大小 * @param isZeroPadding 是否0填充 * @return 填充后的数据,如果isZeroPadding为false或长度刚好,返回原数据 */ private byte[] paddingDataWithZero(byte[] data, int blockSize, boolean isZeroPadding) { if (isZeroPadding) { final int length = data.length; // 按照块拆分后的数据中多余的数据 final int remainLength = length % blockSize; if (remainLength > 0) { // 新长度为blockSize的整数倍,多余部分填充0 return SecureUtil.resize(data, length + blockSize - remainLength); } } return data; } /** * 数据按照blockSize去除填充部分,用于解密 * *

* 在{@link Padding#ZeroPadding} 模式下,且数据长度不是blockSize的整数倍才有效,否则返回原数据 * * @param data 数据 * @param blockSize 块大小 * @return 去除填充后的数据,如果isZeroPadding为false或长度刚好,返回原数据 */ private byte[] removePadding(byte[] data, int blockSize) { if (this.isZeroPadding()) { final int length = data.length; final int remainLength = length % blockSize; if (remainLength == 0) { // 解码后的数据正好是块大小的整数倍,说明可能存在补0的情况,去掉末尾所有的0 int i = length - 1; while (i >= 0 && 0 == data[i]) { i--; } return SecureUtil.resize(data, i + 1); } } return data; } // --------------------------------------------------------------------------------- Private method end // --------------------------------------- getter/setter --------------------------------------------------------// public Cipher getCipher() { return cipher; } public void setCipher(Cipher cipher) { this.cipher = cipher; } public boolean isZeroPadding() { return zeroPadding; } public void setZeroPadding(boolean zeroPadding) { this.zeroPadding = zeroPadding; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy