package com.cyksj.common.util; import org.bouncycastle.jce.provider.BouncyCastleProvider; import javax.crypto.Cipher; import javax.crypto.Mac; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.io.InputStream; import java.security.*; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; /** * @author valor. * @date 2019/9/20 16:47 */ public class Codec { private Codec() { } // Base64 // Cipher // Hmac // Signature // MessageDigest public static class Hexs { private Hexs() { } /** * Used to build output as Hex */ private static final char[] DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; public static String encodeToString(final byte[] data) { return new String(encode(data)); } private static char[] encode(final byte[] data) { final int l = data.length; final char[] out = new char[l << 1]; // two characters form the hex value. for (int i = 0, j = 0; i < l; i++) { out[j++] = DIGITS[(0xF0 & data[i]) >>> 4]; out[j++] = DIGITS[0x0F & data[i]]; } return out; } public static byte[] decode(final char[] data) { final int len = data.length; if ((len & 0x01) != 0) { throw new RuntimeException("Odd number of characters."); } final byte[] out = new byte[len >> 1]; // two characters form the hex value. for (int i = 0, j = 0; j < len; i++) { int f = toDigit(data[j], j) << 4; j++; f = f | toDigit(data[j], j); j++; out[i] = (byte) (f & 0xFF); } return out; } private static int toDigit(final char ch, final int index) { final int digit = Character.digit(ch, 16); if (digit == -1) { throw new RuntimeException("Illegal hexadecimal character " + ch + " at index " + index); } return digit; } } /** * package {@link Base64} */ private static class Base64s { private Base64s() { } /* ----- encode ----- */ private static byte[] encode(byte[] var) { return Base64.getEncoder().encode(var); } /* ----- decode ----- */ private static byte[] decode(byte[] var) { return Base64.getDecoder().decode(var); } } /** * package {@link Cipher} */ private static class Ciphers { private Ciphers() { } /** * Cipher算法 * * @param mode 模式 加密/解密 * @param trans 算法填充 * @param content 待加密/解密的byte[] * @param keyByte 加密/解密密钥 * @param ivByte 算法向量 (AES CBC类型 需要填充iv偏移量) * @return 输出的byte[] * @throws Exception 抛出异常 */ private static byte[] doCipher(int mode, DoCipher.Trans trans, byte[] content, byte[] keyByte, byte[] ivByte) throws Exception { String algorithm = trans.getTransformation(); Cipher cipher = Cipher.getInstance(algorithm); Key sKeySpec = new SecretKeySpec(keyByte, algorithm); if (null != ivByte && 0 != ivByte.length) { // AES CBC类型 需要填充iv偏移量 AlgorithmParameterSpec iv = new IvParameterSpec(ivByte); cipher.init(mode, sKeySpec, iv); } else { cipher.init(mode, sKeySpec); } return cipher.doFinal(content); } } /** * package {@link Mac} */ private static class Hmacs { private Hmacs() { } private static byte[] doHmac(DoHmac.Algorithm algorithm, byte[] content, byte[] keyByte) throws Exception { String hmacAlgorithm = algorithm.getValue(); Mac mac = Mac.getInstance(hmacAlgorithm); Key sKeySpec = new SecretKeySpec(keyByte, hmacAlgorithm); mac.init(sKeySpec); return mac.doFinal(content); } } /** * package {@link Signature} */ private static class Signatures { private Signatures() { } private static byte[] sign(DoSign.SignAlgorithm algorithm, byte[] content, PrivateKey privateKey) throws Exception { Signature signature = Signature.getInstance(algorithm.getValue()); signature.initSign(privateKey); signature.update(content); return signature.sign(); } private static boolean check(DoSign.SignAlgorithm algorithm, byte[] content, byte[] sign, PublicKey publicKey) throws Exception { Signature signature = Signature.getInstance(algorithm.getValue()); signature.initVerify(publicKey); signature.update(content); return signature.verify(sign); } private static PublicKey getPublicKeyFromX509(DoSign.KeyAlgorithm algorithm, byte[] publicKeyBytes) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance(algorithm.getValue()); byte[] key = Base64s.decode(publicKeyBytes); return keyFactory.generatePublic(new X509EncodedKeySpec(key)); } private static PrivateKey getPrivateKeyFromPKCS8(DoSign.KeyAlgorithm algorithm, byte[] privateKeyBytes) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance(algorithm.getValue()); byte[] key = Base64s.decode(privateKeyBytes); return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(key)); } } private static class Digests { private Digests() { } private static byte[] doDigest(DoDigest.Algorithm algorithm, byte[] content) throws Exception { MessageDigest digest = MessageDigest.getInstance(algorithm.getValue()); return digest.digest(content); } private static byte[] doDigest(DoDigest.Algorithm algorithm, InputStream in) throws Exception { MessageDigest digest = MessageDigest.getInstance(algorithm.getValue()); byte[] buffer = new byte[1024]; int offset; while (true) { offset = in.read(buffer); if (offset < 0) { break; } digest.update(buffer, 0, offset); } // close IoKit.close(in); return digest.digest(); } } public static class DoDigest { public enum Algorithm { MD2("MD2"), MD5("MD5"), SHA1("SHA-1"), SHA224("SHA-224"), SHA256("SHA-256"), SHA384("SHA-384"), SHA512("SHA-512"), SHA3224("SHA3-224"), SHA3256("SHA3-256"), SHA3384("SHA3-384"), SHA3512("SHA3-512"); private String value; Algorithm(String algorithm) { this.value = algorithm; } public String getValue() { return this.value; } } private Algorithm algorithm; private byte[] data; private DoDigest() { } public static DoDigest custom() { return new DoDigest(); } public DoDigest setAlgorithm(Algorithm algorithm) { this.algorithm = algorithm; return this; } public DoDigest setData(byte[] data) { this.data = data; return this; } public DoDigest setBase64Data(String data, IoKit.Charsets charset) { this.data = DoBase64.custom().setData(data, charset).decode(); return this; } public DoDigest setBase64Data(String data) { return this.setBase64Data(data, IoKit.Charsets.UTF_8); } public DoDigest setStringData(String data, IoKit.Charsets charset) { this.data = data.getBytes(charset.getCharset()); return this; } public DoDigest setStringData(String data) { return this.setStringData(data, IoKit.Charsets.UTF_8); } public byte[] toBytes() throws Exception { return Digests.doDigest(this.algorithm, this.data); } public String toHexString() throws Exception { return Hexs.encodeToString(this.toBytes()); } public String toBase64String(IoKit.Charsets charset) throws Exception { return DoBase64.custom().setData(this.toBytes()).encodeAsText(charset); } public String toBase64String() throws Exception { return this.toBase64String(IoKit.Charsets.UTF_8); } public String toText(IoKit.Charsets charset) throws Exception { return new String(this.toBytes(), charset.getCharset()); } public String toText() throws Exception { return this.toText(IoKit.Charsets.UTF_8); } } public static class DoSign { public enum KeyAlgorithm { RSA("RSA"), DSA("DSA"), EC("EC"); private String value; KeyAlgorithm(String algorithm) { this.value = algorithm; } public String getValue() { return this.value; } } public enum SignAlgorithm { NONEwithRSA("NONEwithRSA"), MD2withRSA("MD2withRSA"), MD5withRSA("MD5withRSA"), SHA1withRSA("SHA1withRSA"), SHA224withRSA("SHA224withRSA"), SHA256withRSA("SHA256withRSA"), SHA384withRSA("SHA384withRSA"), SHA512withRSA("SHA512withRSA"), NONEwithDSA("NONEwithDSA"), SHA1withDSA("SHA1withDSA"), SHA224withDSA("SHA224withDSA"), SHA256withDSA("SHA256withDSA"), NONEwithECDSA("NONEwithECDSA"), SHA1withECDSA("SHA1withECDSA"), SHA224withECDSA("SHA224withECDSA"), SHA256withECDSA("SHA256withECDSA"), SHA384withECDSA("SHA384withECDSA"), SHA512withECDSA("SHA512withECDSA"); private String value; SignAlgorithm(String algorithm) { this.value = algorithm; } public String getValue() { return this.value; } } private KeyAlgorithm keyAlgorithm; private SignAlgorithm signAlgorithm; private byte[] data; private byte[] key; private byte[] signature; private DoSign() { } public static DoSign custom() { return new DoSign(); } public DoSign setKeyAlgorithm(KeyAlgorithm keyAlgorithm) { this.keyAlgorithm = keyAlgorithm; return this; } public DoSign setSignAlgorithm(SignAlgorithm signAlgorithm) { this.signAlgorithm = signAlgorithm; return this; } public DoSign setData(byte[] data) { this.data = data; return this; } public DoSign setBase64Data(String data, IoKit.Charsets charset) { this.data = DoBase64.custom().setData(data, charset).decode(); return this; } public DoSign setBase64Data(String data) { return this.setBase64Data(data, IoKit.Charsets.UTF_8); } public DoSign setStringData(String data, IoKit.Charsets charset) { this.data = data.getBytes(charset.getCharset()); return this; } public DoSign setStringData(String data) { return this.setStringData(data, IoKit.Charsets.UTF_8); } public DoSign setKey(byte[] key) { this.key = key; return this; } public DoSign setBase64Key(String key, IoKit.Charsets charset) { this.key = DoBase64.custom().setData(key, charset).decode(); return this; } public DoSign setBase64Key(String key) { return this.setBase64Key(key, IoKit.Charsets.UTF_8); } public DoSign setStringKey(String key, IoKit.Charsets charset) { this.key = key.getBytes(charset.getCharset()); return this; } public DoSign setStringKey(String key) { return this.setStringKey(key, IoKit.Charsets.UTF_8); } public DoSign setSignature(byte[] signature) { this.signature = signature; return this; } public DoSign setBase64Signature(String signature, IoKit.Charsets charset) { this.signature = DoBase64.custom().setData(signature, charset).decode(); return this; } public DoSign setBase64Signature(String signature) { return this.setBase64Signature(signature, IoKit.Charsets.UTF_8); } public DoSign setStringSignature(String signature, IoKit.Charsets charset) { this.signature = signature.getBytes(charset.getCharset()); return this; } public DoSign setStringSignature(String signature) { return this.setStringSignature(signature, IoKit.Charsets.UTF_8); } public byte[] sign() throws Exception { PrivateKey privateKey = Signatures.getPrivateKeyFromPKCS8(this.keyAlgorithm, this.key); return Signatures.sign(this.signAlgorithm, this.data, privateKey); } public String toHexString() throws Exception { return Hexs.encodeToString(this.sign()); } public String toBase64String(IoKit.Charsets charset) throws Exception { return DoBase64.custom().setData(this.sign()).encodeAsText(charset); } public String toBase64String() throws Exception { return this.toBase64String(IoKit.Charsets.UTF_8); } public String toText(IoKit.Charsets charset) throws Exception { return new String(this.sign(), charset.getCharset()); } public String toText() throws Exception { return this.toText(IoKit.Charsets.UTF_8); } public boolean check() throws Exception { PublicKey publicKey = Signatures.getPublicKeyFromX509(this.keyAlgorithm, this.key); return Signatures.check(this.signAlgorithm, this.data, this.signature, publicKey); } } public static class DoHmac { public enum Algorithm { HmacMD5("HmacMD5"), HmacSHA1("HmacSHA1"), HmacSHA224("HmacSHA224"), HmacSHA256("HmacSHA256"), HmacSHA384("HmacSHA384"), HmacSHA512("HmacSHA512"); private String value; Algorithm(String algorithm) { this.value = algorithm; } public String getValue() { return this.value; } } private Algorithm algorithm; private byte[] data; private byte[] key; private DoHmac() { } public static DoHmac custom() { return new DoHmac(); } public DoHmac setAlgorithm(Algorithm algorithm) { this.algorithm = algorithm; return this; } public DoHmac setData(byte[] data) { this.data = data; return this; } public DoHmac setBase64Data(String data, IoKit.Charsets charset) { this.data = DoBase64.custom().setData(data, charset).decode(); return this; } public DoHmac setBase64Data(String data) { return this.setBase64Data(data, IoKit.Charsets.UTF_8); } public DoHmac setStringData(String data, IoKit.Charsets charset) { this.data = data.getBytes(charset.getCharset()); return this; } public DoHmac setStringData(String data) { return this.setStringData(data, IoKit.Charsets.UTF_8); } public DoHmac setKey(byte[] key) { this.key = key; return this; } public DoHmac setBase64Key(String key, IoKit.Charsets charset) { this.key = DoBase64.custom().setData(key, charset).decode(); return this; } public DoHmac setBase64Key(String key) { return this.setBase64Key(key, IoKit.Charsets.UTF_8); } public DoHmac setStringKey(String key, IoKit.Charsets charset) { this.key = key.getBytes(charset.getCharset()); return this; } public DoHmac setStringKey(String key) { return this.setStringKey(key, IoKit.Charsets.UTF_8); } public byte[] toBytes() throws Exception { return Hmacs.doHmac(this.algorithm, this.data, this.key); } public String toHexString() throws Exception { return Hexs.encodeToString(this.toBytes()); } public String toBase64String(IoKit.Charsets charset) throws Exception { return DoBase64.custom().setData(this.toBytes()).encodeAsText(charset); } public String toBase64String() throws Exception { return this.toBase64String(IoKit.Charsets.UTF_8); } public String toText(IoKit.Charsets charset) throws Exception { return new String(this.toBytes(), charset.getCharset()); } public String toText() throws Exception { return this.toText(IoKit.Charsets.UTF_8); } } public static class DoCipher { static { // for Cipher PKCS7Padding Security.addProvider(new BouncyCastleProvider()); } public enum Trans { AES_CBC_NoPadding("AES/CBC/NoPadding", "128"), AES_CBC_PKCS5Padding("AES/CBC/PKCS5Padding", "128"), AES_CBC_PKCS7Padding("AES/CBC/PKCS7Padding", "128"), AES_ECB_NoPadding("AES/ECB/NoPadding", "128"), AES_ECB_PKCS5Padding("AES/ECB/PKCS5Padding", "128"), AES_ECB_PKCS7Padding("AES/ECB/PKCS7Padding", "128"), DES_CBC_NoPadding("DES/CBC/NoPadding", "56"), DES_CBC_PKCS5Padding("DES/CBC/PKCS5Padding", "56"), DES_ECB_NoPadding("DES/ECB/NoPadding", "56"), DES_ECB_PKCS5Padding("DES/ECB/PKCS5Padding", "56"), DESede_CBC_NoPadding("DESede/CBC/NoPadding", "168"), DESede_CBC_PKCS5Padding("DESede/CBC/PKCS5Padding", "168"), DESede_ECB_NoPadding("DESede/ECB/NoPadding", "168"), DESede_ECB_PKCS5Padding("DESede/ECB/PKCS5Padding", "168"), RSA_ECB_PKCS1Padding("RSA/ECB/PKCS1Padding", "1024, 2048"), RSA_ECB_OAEPWithSHA1AndMGF1Padding("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", "1024, 2048"), RSA_ECB_OAEPWithSHA256AndMGF1Padding("RSA/ECB/OAEPWithSHA-256AndMGF1Padding", "1024, 2048"); private String transformation; Trans(String transformation, String bits) { this.transformation = transformation; } public String getTransformation() { return this.transformation; } } private Trans algorithm; private byte[] data; private byte[] key; private byte[] iv; private int mode; private DoCipher() { } public static DoCipher custom() { return new DoCipher(); } public DoCipher setAlgorithm(Trans algorithm) { this.algorithm = algorithm; return this; } public DoCipher setData(byte[] data) { this.data = data; return this; } public DoCipher setBase64Data(String data, IoKit.Charsets charset) { this.data = DoBase64.custom().setData(data, charset).decode(); return this; } public DoCipher setBase64Data(String data) { return this.setBase64Data(data, IoKit.Charsets.UTF_8); } public DoCipher setStringData(String data, IoKit.Charsets charset) { this.data = data.getBytes(charset.getCharset()); return this; } public DoCipher setStringData(String data) { return this.setStringData(data, IoKit.Charsets.UTF_8); } public DoCipher setKey(byte[] key) { this.key = key; return this; } public DoCipher setBase64Key(String key, IoKit.Charsets charset) { this.key = DoBase64.custom().setData(key, charset).decode(); return this; } public DoCipher setBase64Key(String key) { return this.setBase64Key(key, IoKit.Charsets.UTF_8); } public DoCipher setStringKey(String key, IoKit.Charsets charset) { this.key = key.getBytes(charset.getCharset()); return this; } public DoCipher setStringKey(String key) { return this.setStringKey(key, IoKit.Charsets.UTF_8); } public DoCipher setIv(byte[] iv) { this.iv = iv; return this; } public DoCipher setBase64Iv(String iv, IoKit.Charsets charset) { this.iv = DoBase64.custom().setData(iv, charset).decode(); return this; } public DoCipher setBase64Iv(String iv) { return this.setBase64Iv(iv, IoKit.Charsets.UTF_8); } public DoCipher setStringIv(String iv, IoKit.Charsets charset) { this.iv = iv.getBytes(charset.getCharset()); return this; } public DoCipher setStringIv(String iv) { return this.setStringIv(iv, IoKit.Charsets.UTF_8); } public DoCipher ofDecrypt() { this.mode = Cipher.DECRYPT_MODE; return this; } public DoCipher ofEncrypt() { this.mode = Cipher.ENCRYPT_MODE; return this; } public byte[] toBytes() throws Exception { return Ciphers.doCipher(this.mode, this.algorithm, this.data, this.key, this.iv); } public String toHexString() throws Exception { return Hexs.encodeToString(this.toBytes()); } public String toBase64String(IoKit.Charsets charset) throws Exception { return DoBase64.custom().setData(this.toBytes()).encodeAsText(charset); } public String toBase64String() throws Exception { return this.toBase64String(IoKit.Charsets.UTF_8); } public String toText(IoKit.Charsets charset) throws Exception { return new String(this.toBytes(), charset.getCharset()); } public String toText() throws Exception { return this.toText(IoKit.Charsets.UTF_8); } } public static class DoBase64 { private byte[] var; private DoBase64() { } public static DoBase64 custom() { return new DoBase64(); } public DoBase64 setData(byte[] data) { this.var = data; return this; } public DoBase64 setData(String data) { return this.setData(data, IoKit.Charsets.UTF_8); } public DoBase64 setData(String data, IoKit.Charsets charset) { this.var = data.getBytes(charset.getCharset()); return this; } public byte[] encode() { return Base64s.encode(this.var); } public byte[] decode() { return Base64s.decode(this.var); } public String encodeAsText(IoKit.Charsets charset) { return new String(this.encode(), charset.getCharset()); } public String decodeAsText(IoKit.Charsets charset) { return new String(this.decode(), charset.getCharset()); } public String encodeAsText() { return this.encodeAsText(IoKit.Charsets.UTF_8); } public String decodeAsText() { return this.decodeAsText(IoKit.Charsets.UTF_8); } } }