目录
对称加密
1 定义
采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。
2 特点
- 加密和解密使用同样的密钥
- 计算速度快,适用于对大量数据加密处理
- 安全性取决于算法,也取决于密钥的管理,一旦密钥泄漏,数据则暴露无遗
3 使用场景
基于上述的特点,在一些需要高效实时传输的加密通讯场景中,比如使用VPN或者代理进行通讯时,可以使用对称加密。另外在同一个系统内部不同模块,比如前后端,从前端输入的敏感信息,可以使用对称加密算法进行加密后将密文传到后端,避免传输过程中明文被截获,因为同系统内部之间密钥管理相对容易,而对于共享密钥有泄漏风险的其他任何场景,则不适合使用对称加密算法进行加密。
4 常用的对称加密算法
- DES(Data Encryption Standard) 数据加密标准,速度较快,适用于加密大量数据
- 3DES(Triple DES) 基于DES,对一块数据用三个不同的密钥进行三次加密,强度更高
- AES(Advanced Encryption Standard) 高级加密标准,速度快,安全级别高,支持128、192、256、512位密钥的加密
- Blowfish 速度快且安全,而且没有专利和商业限制。
5 JDK支持的对称加密算法
JDK8原生算法列表,可参第一篇博文: https://blog.csdn.net/yunyun1886358/article/details/128592503#311_JDK_Provider_63
6 Bouncy Castle 支持的对称加密算法
Bouncy Castle原生算法列表,可参第一篇博文:
https://editor.csdn.net/md/?articleId=128592503#323_Bouncy_Castle_Provider_568
7 算法调用示例
下面的代码将几种常用的对称加密算法用枚枚举类进行了封装,调用encrypt()和decrypt()方法可以实现加密和解。encrypt()和decrypt()的几个重载方法分别支持了不同秘钥生成方式(秘钥字符串,随机种子生成秘钥),是否设置算法参数(AlgorithmParameterSpec)。
程序采用函数式编程的思想,将整个加密解密过程抽象为一个流程,每一步抽象为一个Lambda表达式,可以根据算法的不同传入不同的Lambda表达式。每添加一种新的算法,只需要传入不同的Lambda表达式即可。
各个类的介绍如下:
SymmetricEncryptionAlgorithmTest :测试加密和解密
SymmetricEncryptionAlgorithm:算法枚举类,用来构建不同算法的加解密流程
EncryptorDefinition:加解密流程的定义,描述了加解密流程需要的所有Lambda表达式
EncryptorBuilder:加解密流程构造器,用于构造一个加解密流程
Encryptor:加解密流程抽象,按顺序调用一个加解密流程的所有步骤,并输出结果
AlgorithmSpec:算法规格,用来封装一个算法所需要的定义信息
AlgorithmParam:算法参数,用来封装一个算法所需要的所有参数
Transformation:算法转换式的封装
AlgorithmParameterSpecInfo:算法规定参数的封装
NumberGenerationAlgorithm:数字生成算法枚举,此算法用于随机数生成
packagecom.qupeng.crypto.algorithm.fp;importcom.qupeng.crypto.algorithm.oop.NumberGenerationAlgorithm;importorg.junit.Assert;importorg.junit.Test;importjavax.crypto.BadPaddingException;importjavax.crypto.IllegalBlockSizeException;importjavax.crypto.NoSuchPaddingException;importjava.io.IOException;importjava.lang.reflect.InvocationTargetException;importjava.security.InvalidAlgorithmParameterException;importjava.security.InvalidKeyException;importjava.security.NoSuchAlgorithmException;publicclassSymmetricEncryptionAlgorithmTest{@TestpublicvoidencryptAES()throwsInvalidKeyException,BadPaddingException,IllegalBlockSizeException,IOException,NoSuchMethodException,IllegalAccessException,InvalidAlgorithmParameterException,InstantiationException,InvocationTargetException,NoSuchAlgorithmException,NoSuchPaddingException{String cipherText =SymmetricEncryptionAlgorithm.AES_CBC_NO_PADDING_128.encrypt("a","1234567890123456","1234567890123456");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.AES_CBC_NO_PADDING_128.decrypt(cipherText,"1234567890123456","1234567890123456"));
cipherText =SymmetricEncryptionAlgorithm.AES_CBC_NO_PADDING_128.encrypt("a","12345",NumberGenerationAlgorithm.SHA1_PRNG,"1234567890123456");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.AES_CBC_NO_PADDING_128.decrypt(cipherText,"12345",NumberGenerationAlgorithm.SHA1_PRNG,"1234567890123456"));
cipherText =SymmetricEncryptionAlgorithm.AES_CBC_PKCS5_PADDING_128.encrypt("a","1234567890123456","1234567890123456");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.AES_CBC_PKCS5_PADDING_128.decrypt(cipherText,"1234567890123456","1234567890123456"));
cipherText =SymmetricEncryptionAlgorithm.AES_ECB_NO_PADDING_128.encrypt("a","1234567890123456");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.AES_ECB_NO_PADDING_128.decrypt(cipherText,"1234567890123456"));
cipherText =SymmetricEncryptionAlgorithm.AES_ECB_PKCS5_PADDING_128.encrypt("a","1234567890123456");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.AES_ECB_PKCS5_PADDING_128.decrypt(cipherText,"1234567890123456"));// AES 192 bits secret
cipherText =SymmetricEncryptionAlgorithm.AES_CBC_PKCS5_PADDING_192.encrypt("a","123456789012345678901234","1234567890123456");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.AES_CBC_PKCS5_PADDING_192.decrypt(cipherText,"123456789012345678901234","1234567890123456"));// AES 256 bits secret
cipherText =SymmetricEncryptionAlgorithm.AES_CBC_PKCS5_PADDING_256.encrypt("a","12345678901234567890123456789012","1234567890123456");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.AES_CBC_PKCS5_PADDING_256.decrypt(cipherText,"12345678901234567890123456789012","1234567890123456"));}@TestpublicvoidencryptDES()throwsIllegalAccessException,NoSuchAlgorithmException,InstantiationException,NoSuchMethodException,InvalidKeyException,InvalidAlgorithmParameterException,NoSuchPaddingException,BadPaddingException,InvocationTargetException,IllegalBlockSizeException,IOException{// DES 56 bits secretString cipherText =SymmetricEncryptionAlgorithm.DES_CBC_NO_PADDING_56.encrypt("a","12345678","12345678");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.DES_CBC_NO_PADDING_56.decrypt(cipherText,"12345678","12345678"));
cipherText =SymmetricEncryptionAlgorithm.DES_CBC_PKCS5_PADDING_56.encrypt("a","12345678","12345678");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.DES_CBC_PKCS5_PADDING_56.decrypt(cipherText,"12345678","12345678"));
cipherText =SymmetricEncryptionAlgorithm.DES_ECB_NO_PADDING_56.encrypt("a","12345678");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.DES_ECB_NO_PADDING_56.decrypt(cipherText,"12345678"));
cipherText =SymmetricEncryptionAlgorithm.DES_ECB_PKCS5_PADDING_56.encrypt("a","12345678");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.DES_ECB_PKCS5_PADDING_56.decrypt(cipherText,"12345678"));}@Testpublicvoidencrypt3DES()throwsIllegalAccessException,NoSuchAlgorithmException,InstantiationException,NoSuchMethodException,InvalidKeyException,InvalidAlgorithmParameterException,NoSuchPaddingException,BadPaddingException,InvocationTargetException,IllegalBlockSizeException,IOException{// 3 DES 168 bits secretString cipherText =SymmetricEncryptionAlgorithm.DESEDE_CBC_NO_PADDING_168.encrypt("a","123456789012345678901234","12345678");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.DESEDE_CBC_NO_PADDING_168.decrypt(cipherText,"123456789012345678901234","12345678"));
cipherText =SymmetricEncryptionAlgorithm.DESEDE_CBC_PKCS5_PADDING_168.encrypt("a","123456789012345678901234","12345678");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.DESEDE_CBC_NO_PADDING_168.decrypt(cipherText,"123456789012345678901234","12345678"));
cipherText =SymmetricEncryptionAlgorithm.DESEDE_ECB_NO_PADDING_168.encrypt("a","123456789012345678901234");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.DESEDE_ECB_NO_PADDING_168.decrypt(cipherText,"123456789012345678901234"));
cipherText =SymmetricEncryptionAlgorithm.DESEDE_ECB_PKCS5_PADDING_168.encrypt("a","123456789012345678901234");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.DESEDE_ECB_PKCS5_PADDING_168.decrypt(cipherText,"123456789012345678901234"));}@TestpublicvoidencryptBlowfish()throwsBadPaddingException,InvocationTargetException,InvalidAlgorithmParameterException,IllegalBlockSizeException,InstantiationException,NoSuchMethodException,IllegalAccessException,InvalidKeyException,IOException{// BlowfishString cipherText =SymmetricEncryptionAlgorithm.BLOWFISH_CBC_NO_PADDING_128.encrypt("a","1234567890123456","12345678");Assert.assertEquals("a",SymmetricEncryptionAlgorithm.BLOWFISH_CBC_NO_PADDING_128.decrypt(cipherText,"1234567890123456","12345678"));}}
packagecom.qupeng.crypto.algorithm.fp;importcom.qupeng.crypto.algorithm.oop.NumberGenerationAlgorithm;importjavax.crypto.*;importjavax.crypto.spec.IvParameterSpec;importjavax.crypto.spec.SecretKeySpec;importjava.io.IOException;importjava.lang.reflect.InvocationTargetException;importjava.security.*;importjava.security.spec.AlgorithmParameterSpec;publicenumSymmetricEncryptionAlgorithm{AES_CBC_NO_PADDING_128("AES","CBC","NoPadding",128,16,IvParameterSpec.class,128),AES_CBC_NO_PADDING_192("AES","CBC","NoPadding",192,24,IvParameterSpec.class,128),AES_CBC_NO_PADDING_56("AES","CBC","NoPadding",256,32,IvParameterSpec.class,128),AES_CBC_PKCS5_PADDING_128("AES","CBC","PKCS5Padding",128,16,IvParameterSpec.class,128),AES_CBC_PKCS5_PADDING_192("AES","CBC","PKCS5Padding",192,24,IvParameterSpec.class,128),AES_CBC_PKCS5_PADDING_256("AES","CBC","PKCS5Padding",256,32,IvParameterSpec.class,128),AES_ECB_NO_PADDING_128("AES","ECB","NoPadding",128,16,null,-1),AES_ECB_NO_PADDING_192("AES","ECB","NoPadding",192,24,null,-1),AES_ECB_NO_PADDING_256("AES","ECB","NoPadding",256,32,null,-1),AES_ECB_PKCS5_PADDING_128("AES","ECB","PKCS5Padding",128,16,null,-1),AES_ECB_PKCS5_PADDING_192("AES","ECB","PKCS5Padding",192,24,null,-1),AES_ECB_PKCS5_PADDING_256("AES","ECB","PKCS5Padding",256,32,null,-1),DES_CBC_NO_PADDING_56("DES","CBC","NoPadding",56,8,IvParameterSpec.class,64),DES_CBC_PKCS5_PADDING_56("DES","CBC","PKCS5Padding",56,8,IvParameterSpec.class,64),DES_ECB_NO_PADDING_56("DES","ECB","NoPadding",56,8,null,-1),DES_ECB_PKCS5_PADDING_56("DES","ECB","PKCS5Padding",56,8,null,-1),DESEDE_CBC_NO_PADDING_168("DESede","CBC","NoPadding",168,24,IvParameterSpec.class,64),DESEDE_CBC_PKCS5_PADDING_168("DESede","CBC","PKCS5Padding",168,24,IvParameterSpec.class,64),DESEDE_ECB_NO_PADDING_168("DESede","ECB","NoPadding",168,24,null,-1),DESEDE_ECB_PKCS5_PADDING_168("DESede","ECB","PKCS5Padding",168,24,null,-1),BLOWFISH_CBC_NO_PADDING_128("Blowfish","CBC","NoPadding",128,16,IvParameterSpec.class,64);privateString transformation ="";privateString algorithm ="";privateString mode ="";privateString padding ="";privateint secretKeyStrLength =-1;privateint secretKeyBitLength =-1;privateClass<?extendsAlgorithmParameterSpec> algorithmParameterSpecClass;privateint algorithmParameterBitLength =-1;SymmetricEncryptionAlgorithm(String algorithm,String mode,String padding,int secretKeyBitLength,int secretKeyStrLength,Class<?extendsAlgorithmParameterSpec> algorithmParameterSpecClass,int algorithmParameterBitLength){this.algorithm = algorithm;this.mode = mode;this.padding = padding;this.transformation =String.format("%s/%s/%s", algorithm, mode, padding);this.secretKeyStrLength = secretKeyStrLength;this.secretKeyBitLength = secretKeyBitLength;this.algorithmParameterSpecClass = algorithmParameterSpecClass;this.algorithmParameterBitLength = algorithmParameterBitLength;}// 1 使用秘钥字符串加密,附加向量参数publicStringencrypt(String plainText,String secretKeyStr,String algorithmParameterStr)throwsInvalidKeyException,IllegalBlockSizeException,BadPaddingException,InvocationTargetException,NoSuchMethodException,InvalidAlgorithmParameterException,InstantiationException,IllegalAccessException{Encryptor encryptor =EncryptorBuilder.from(AlgorithmSpec.of().setTransformation(this.algorithm,this.mode,this.padding).setSecretKeyBitLength(this.secretKeyBitLength).setAlgorithmParameterSpecClass(this.algorithmParameterSpecClass).setAlgorithmParameterBitLength(this.algorithmParameterBitLength),AlgorithmParam.of().setPlainText(plainText).setSecretKeyStr(secretKeyStr).setAlgorithmParameterStr(algorithmParameterStr),(algorithmSpec, algorithmParam)->{validateSecretKeyStr(algorithmSpec, algorithmParam);validateParamSpec(algorithmSpec, algorithmParam);}).getCipher(this::getCipher).getSecretKeyByStr((secretKeyStrTmp, algorithmTmp)->newSecretKeySpec(secretKeyStrTmp.getBytes(), algorithmTmp)).padding(this::setPadding).initCipher((cipher, key)->initCipher(cipher,Cipher.ENCRYPT_MODE, key, algorithmParameterStr)).get();return encryptor.encrypt().get();}// 1 使用秘钥字符串解密,附加向量参数publicStringdecrypt(String base64Content,String secretKeyStr,String algorithmParameterStr)throwsInvalidKeyException,BadPaddingException,IllegalBlockSizeException,IOException,InvocationTargetException,NoSuchMethodException,InvalidAlgorithmParameterException,InstantiationException,IllegalAccessException{Encryptor encryptor =EncryptorBuilder.from(AlgorithmSpec.of().setTransformation(this.algorithm,this.mode,this.padding).setSecretKeyBitLength(this.secretKeyBitLength).setAlgorithmParameterSpecClass(this.algorithmParameterSpecClass).setAlgorithmParameterBitLength(this.algorithmParameterBitLength),AlgorithmParam.of().setBase64CipherText(base64Content).setSecretKeyStr(secretKeyStr).setAlgorithmParameterStr(algorithmParameterStr),(algorithmSpec, algorithmParam)->{validateSecretKeyStr(algorithmSpec, algorithmParam);validateParamSpec(algorithmSpec, algorithmParam);}).getCipher(this::getCipher).getSecretKeyByStr((secretKeyStrTmp, algorithmTmp)->newSecretKeySpec(secretKeyStrTmp.getBytes(), algorithmTmp)).initCipher((cipher, key)->initCipher(cipher,Cipher.DECRYPT_MODE, key, algorithmParameterStr)).get();return encryptor.decrypt().get();}// 2 使用秘钥字符串加密publicStringencrypt(String plainText,String secretKeyStr)throwsNoSuchPaddingException,InvalidKeyException,NoSuchAlgorithmException,IllegalBlockSizeException,BadPaddingException,InvalidAlgorithmParameterException,NoSuchMethodException,InstantiationException,IllegalAccessException,InvocationTargetException{Encryptor encryptor =EncryptorBuilder.from(AlgorithmSpec.of().setTransformation(this.algorithm,this.mode,this.padding).setSecretKeyBitLength(this.secretKeyBitLength),AlgorithmParam.of().setPlainText(plainText).setSecretKeyStr(secretKeyStr),(algorithmSpec, algorithmParam)->{validateSecretKeyStr(algorithmSpec, algorithmParam);}).getCipher(this::getCipher).getSecretKeyByStr((secretKeyStrTmp, algorithmTmp)->newSecretKeySpec(secretKeyStrTmp.getBytes(), algorithmTmp)).initCipher((cipher, key)->initCipher(cipher,Cipher.ENCRYPT_MODE, key)).padding(this::setPadding).get();return encryptor.encrypt().get();}// 2 使用秘钥字符串解密publicStringdecrypt(String base64Content,String secretKeyStr)throwsNoSuchPaddingException,NoSuchAlgorithmException,InvalidAlgorithmParameterException,InvalidKeyException,BadPaddingException,IllegalBlockSizeException,NoSuchMethodException,InstantiationException,IllegalAccessException,InvocationTargetException,IOException{Encryptor encryptor =EncryptorBuilder.from(AlgorithmSpec.of().setTransformation(this.algorithm,this.mode,this.padding).setSecretKeyBitLength(this.secretKeyBitLength),AlgorithmParam.of().setBase64CipherText(base64Content).setSecretKeyStr(secretKeyStr),(algorithmSpec, algorithmParam)->{validateSecretKeyStr(algorithmSpec, algorithmParam);}).getCipher(this::getCipher).getSecretKeyByStr((secretKeyStrTmp, algorithmTmp)->newSecretKeySpec(secretKeyStrTmp.getBytes(), algorithmTmp)).initCipher((cipher, key)->initCipher(cipher,Cipher.DECRYPT_MODE, key)).get();return encryptor.decrypt().get();}// 3 使用随机数种子加密,指定随机数算法,附加向量参数publicStringencrypt(String plainText,String randomSeedStr,NumberGenerationAlgorithm ngAlgorithm,String algorithmParameterStr)throwsNoSuchPaddingException,InvalidKeyException,NoSuchAlgorithmException,IllegalBlockSizeException,BadPaddingException,InvalidAlgorithmParameterException,NoSuchMethodException,InstantiationException,IllegalAccessException,InvocationTargetException{Encryptor encryptor =EncryptorBuilder.from(AlgorithmSpec.of().setTransformation(this.algorithm,this.mode,this.padding).setSecretKeyBitLength(this.secretKeyBitLength).setAlgorithmParameterSpecClass(this.algorithmParameterSpecClass).setAlgorithmParameterBitLength(this.algorithmParameterBitLength),AlgorithmParam.of().setPlainText(plainText).setRandomSeedStr(randomSeedStr).setNgAlgorithm(ngAlgorithm).setAlgorithmParameterStr(algorithmParameterStr),(algorithmSpec, algorithmParam)->{validateRandomSeed(algorithmSpec, algorithmParam);validateParamSpec(algorithmSpec, algorithmParam);}).getCipher(this::getCipher).getSecretKeyByRandomSeed(this::getSecretKeyByRandomSeed).initCipher((cipher, key)->initCipher(cipher,Cipher.ENCRYPT_MODE, key, algorithmParameterStr)).padding(this::setPadding).get();return encryptor.encrypt().get();}// 3 使用随机数种子解密,指定随机数算法,附加向量参数publicStringdecrypt(String base64Content,String randomSeedStr,NumberGenerationAlgorithm ngAlgorithm,String algorithmParameterStr)throwsNoSuchPaddingException,NoSuchAlgorithmException,InvalidAlgorithmParameterException,InvalidKeyException,BadPaddingException,IllegalBlockSizeException,NoSuchMethodException,InstantiationException,IllegalAccessException,InvocationTargetException,IOException{Encryptor encryptor =EncryptorBuilder.from(AlgorithmSpec.of().setTransformation(this.algorithm,this.mode,this.padding).setSecretKeyBitLength(this.secretKeyBitLength).setAlgorithmParameterSpecClass(this.algorithmParameterSpecClass).setAlgorithmParameterBitLength(this.algorithmParameterBitLength),AlgorithmParam.of().setBase64CipherText(base64Content).setRandomSeedStr(randomSeedStr).setNgAlgorithm(ngAlgorithm).setAlgorithmParameterStr(algorithmParameterStr),(algorithmSpec, algorithmParam)->{validateRandomSeed(algorithmSpec, algorithmParam);validateParamSpec(algorithmSpec, algorithmParam);}).getCipher(this::getCipher).getSecretKeyByRandomSeed(this::getSecretKeyByRandomSeed).initCipher((cipher, key)->initCipher(cipher,Cipher.DECRYPT_MODE, key, algorithmParameterStr)).get();return encryptor.decrypt().get();}// 4 使用随机数种子加密,指定随机数算法publicStringencrypt(String plainText,String randomSeedStr,NumberGenerationAlgorithm ngAlgorithm)throwsNoSuchPaddingException,InvalidKeyException,NoSuchAlgorithmException,IllegalBlockSizeException,BadPaddingException,InvalidAlgorithmParameterException,NoSuchMethodException,InstantiationException,IllegalAccessException,InvocationTargetException{Encryptor encryptor =EncryptorBuilder.from(AlgorithmSpec.of().setTransformation(this.algorithm,this.mode,this.padding).setSecretKeyBitLength(this.secretKeyBitLength).setAlgorithmParameterSpecClass(this.algorithmParameterSpecClass).setAlgorithmParameterBitLength(this.algorithmParameterBitLength),AlgorithmParam.of().setPlainText(plainText).setRandomSeedStr(randomSeedStr).setNgAlgorithm(ngAlgorithm),this::validateSecretKeyStr).getCipher(this::getCipher).getSecretKeyByRandomSeed(this::getSecretKeyByRandomSeed).padding(this::setPadding).get();return encryptor.encrypt().get();}// 4 使用随机数种子解密,指定随机数算法publicStringdecrypt(String base64Content,String randomSeedStr,NumberGenerationAlgorithm ngAlgorithm)throwsNoSuchPaddingException,NoSuchAlgorithmException,InvalidAlgorithmParameterException,InvalidKeyException,BadPaddingException,IllegalBlockSizeException,NoSuchMethodException,InstantiationException,IllegalAccessException,InvocationTargetException,IOException{Encryptor encryptor =EncryptorBuilder.from(AlgorithmSpec.of().setTransformation(this.algorithm,this.mode,this.padding).setSecretKeyBitLength(this.secretKeyBitLength).setAlgorithmParameterSpecClass(this.algorithmParameterSpecClass).setAlgorithmParameterBitLength(this.algorithmParameterBitLength),AlgorithmParam.of().setBase64CipherText(base64Content).setRandomSeedStr(randomSeedStr).setNgAlgorithm(ngAlgorithm),this::validateSecretKeyStr).getCipher(this::getCipher).getSecretKeyByStr((secretKeyStrTmp, algorithmTmp)->newSecretKeySpec(secretKeyStrTmp.getBytes(), algorithmTmp)).get();return encryptor.decrypt().get();}privatebooleanvalidateSecretKeyStr(AlgorithmSpec algorithmSpec,AlgorithmParam algorithmParam){if(this.secretKeyStrLength != algorithmParam.getSecretKeyStr().get().length()){thrownewRuntimeException("Secret key must be "+ algorithmSpec.getSecretKeyBitLength().getAsInt()+" bits.");}returntrue;}privatebooleanvalidateParamSpec(AlgorithmSpec algorithmSpec,AlgorithmParam algorithmParam){if(algorithmSpec.getAlgorithmParameterBitLength().getAsInt()!= algorithmParam.getAlgorithmParameterStr().get().length()*8){thrownewRuntimeException("Vector key must be "+ algorithmSpec.getAlgorithmParameterBitLength().getAsInt()+" bits.");}returntrue;}privatebooleanvalidateRandomSeed(AlgorithmSpec algorithmSpec,AlgorithmParam algorithmParam){if(!algorithmParam.getRandomSeedStr().isPresent()){thrownewRuntimeException("Secret key must be "+ algorithmSpec.getSecretKeyBitLength().getAsInt()+" bits.");}returntrue;}privateCiphergetCipher(String transformation){try{returnCipher.getInstance(transformation);}catch(NoSuchAlgorithmException|NoSuchPaddingException e){
e.printStackTrace();returnnull;}}privateKeygetSecretKeyByRandomSeed(String seedStr,NumberGenerationAlgorithm ngAlgorithm){try{KeyGenerator keyGenerator =KeyGenerator.getInstance(this.algorithm);SecureRandom random =SecureRandom.getInstance(ngAlgorithm.getAlgorithmName());
random.setSeed(seedStr.getBytes());
keyGenerator.init(this.secretKeyBitLength, random);return keyGenerator.generateKey();}catch(NoSuchAlgorithmException e){
e.printStackTrace();}returnnull;}privatebyte[]setPadding(String plainText,int blockSize){byte[] plainTextBytes = plainText.getBytes();byte[] plainTextBytesNoPadding = plainTextBytes;int length = plainTextBytes.length;//计算需填充长度
length = length +(blockSize -(length % blockSize));
plainTextBytes =newbyte[length];//填充System.arraycopy(plainTextBytesNoPadding,0, plainTextBytes,0, plainTextBytesNoPadding.length);return plainTextBytes;}privatevoidinitCipher(Cipher cipher,int mode,Key key,String algorithmParameterStr){try{AlgorithmParameterSpec algorithmParameterSpec =this.algorithmParameterSpecClass.getConstructor(newClass[]{byte[].class}).newInstance(algorithmParameterStr.getBytes());
cipher.init(mode, key, algorithmParameterSpec);}catch(InstantiationException|IllegalAccessException|InvocationTargetException|NoSuchMethodException e){
e.printStackTrace();}catch(InvalidAlgorithmParameterException|InvalidKeyException e){
e.printStackTrace();}}privatevoidinitCipher(Cipher cipher,int mode,Key key){try{
cipher.init(mode, key);}catch(InvalidKeyException e){
e.printStackTrace();}}}
packagecom.qupeng.crypto.algorithm.fp;importcom.qupeng.crypto.algorithm.oop.NumberGenerationAlgorithm;importjavax.crypto.Cipher;importjava.security.Key;importjava.util.function.BiConsumer;importjava.util.function.BiFunction;importjava.util.function.Function;publicabstractclassEncryptorDefinition<EextendsEncryptorDefinition<E>>{protectedEncryptor encryptor =newEncryptor();publicEgetCipher(Function<String,Cipher> cipherSupplier){
encryptor.setCipherSupplier(cipherSupplier);return(E)this;}publicEgetSecretKeyByStr(BiFunction<String,String,Key> keyGenerator){
encryptor.setKeyGeneratorByStr(keyGenerator);return(E)this;}publicEgetSecretKeyByRandomSeed(BiFunction<String,NumberGenerationAlgorithm,Key> keyGenerator){
encryptor.setKeyGenerator(keyGenerator);return(E)this;}publicEpadding(BiFunction<String,Integer,byte[]> padding){
encryptor.setPadding(padding);return(E)this;}publicEinitCipher(BiConsumer<Cipher,Key> initCipher){
encryptor.setInitCipher(initCipher);return(E)this;}publicEncryptorget(){returnthis.encryptor;}}
packagecom.qupeng.crypto.algorithm.fp;importjava.util.function.BiConsumer;publicclassEncryptorBuilderextendsEncryptorDefinition<EncryptorBuilder>{publicstaticEncryptorBuilderfrom(AlgorithmSpec algorithmSpec,AlgorithmParam algorithmParam,BiConsumer<AlgorithmSpec,AlgorithmParam> paramValidator){EncryptorBuilder encryptorBuilder =newEncryptorBuilder();
paramValidator.accept(algorithmSpec, algorithmParam);Encryptor encryptor = encryptorBuilder.get();
encryptor.setTransformation(algorithmSpec.getTransformation()).setSecretKeyBitLength(algorithmSpec.getSecretKeyBitLength().getAsInt());
algorithmSpec.getAlgorithmParameterSpecClass().ifPresent(clazz -> encryptor.setAlgorithmParameterSpecInfo(algorithmSpec.getAlgorithmParameterSpecInfo()));
algorithmParam.getPlainText().ifPresent(plainText -> encryptor.setPlainText(plainText));
algorithmParam.getBase64CipherText().ifPresent(cipherText -> encryptor.setBase64CipherText(cipherText));
algorithmParam.getSecretKeyStr().ifPresent(secretKeyStr -> encryptor.setSecretKeyStr(secretKeyStr));
algorithmParam.getRandomSeedStr().ifPresent(randomSeedStr -> encryptor.setRandomSeedStr(randomSeedStr));
algorithmParam.getNgAlgorithm().ifPresent(ngAlgorithm -> encryptor.setNgAlgorithm(ngAlgorithm));
algorithmParam.getAlgorithmParameterStr().ifPresent(algorithmParameterStr -> encryptor.setAlgorithmParameterStr(algorithmParameterStr));return encryptorBuilder;}}
packagecom.qupeng.crypto.algorithm.fp;importjava.security.spec.AlgorithmParameterSpec;importjava.util.Optional;importjava.util.OptionalInt;publicclassAlgorithmSpec{privateOptional<String> algorithm =Optional.empty();privateOptional<String> mode =Optional.empty();privateOptional<String> padding =Optional.empty();privateOptionalInt secretKeyBitLength =OptionalInt.empty();privateOptional<Class<?extendsAlgorithmParameterSpec>> algorithmParameterSpecClass =Optional.empty();privateOptionalInt algorithmParameterBitLength =OptionalInt.empty();publicstaticAlgorithmSpecof(){returnnewAlgorithmSpec();}publicAlgorithmSpecsetTransformation(String algotirhm,String mode,String padding){this.algorithm =Optional.of(algotirhm);this.mode =Optional.of(mode);this.padding =Optional.of(padding);returnthis;}publicTransformationgetTransformation(){returnnewTransformation(this.algorithm.get(),this.mode.get(),this.padding.get());}publicOptionalIntgetSecretKeyBitLength(){return secretKeyBitLength;}publicAlgorithmSpecsetSecretKeyBitLength(int secretKeyBitLength){this.secretKeyBitLength =OptionalInt.of(secretKeyBitLength);returnthis;}publicAlgorithmSpecsetAlgorithmParameterSpecClass(Class<?extendsAlgorithmParameterSpec> algorithmParameterSpecClass){this.algorithmParameterSpecClass =Optional.of(algorithmParameterSpecClass);returnthis;}publicAlgorithmSpecsetAlgorithmParameterBitLength(int algorithmParameterBitLength){this.algorithmParameterBitLength =OptionalInt.of(algorithmParameterBitLength);returnthis;}publicOptional<Class<?extendsAlgorithmParameterSpec>>getAlgorithmParameterSpecClass(){return algorithmParameterSpecClass;}publicOptionalIntgetAlgorithmParameterBitLength(){return algorithmParameterBitLength;}publicAlgorithmParameterSpecInfogetAlgorithmParameterSpecInfo(){returnnewAlgorithmParameterSpecInfo(this.algorithmParameterSpecClass.get(),this.algorithmParameterBitLength.getAsInt());}}
packagecom.qupeng.crypto.algorithm.fp;importcom.qupeng.crypto.algorithm.oop.NumberGenerationAlgorithm;importjava.util.Optional;publicclassAlgorithmParam{privateOptional<String> plainText =Optional.empty();privateOptional<String> base64CipherText =Optional.empty();privateOptional<String> secretKeyStr =Optional.empty();privateOptional<String> randomSeedStr =Optional.empty();privateOptional<NumberGenerationAlgorithm> ngAlgorithm =Optional.empty();privateOptional<String> algorithmParameterStr =Optional.empty();publicstaticAlgorithmParamof(){returnnewAlgorithmParam();}publicAlgorithmParamsetPlainText(String plainText){this.plainText =Optional.of(plainText);returnthis;}publicAlgorithmParamsetBase64CipherText(String base64CipherText){this.base64CipherText =Optional.of(base64CipherText);returnthis;}publicAlgorithmParamsetSecretKeyStr(String secretKeyStr){this.secretKeyStr =Optional.of(secretKeyStr);returnthis;}publicAlgorithmParamsetRandomSeedStr(String randomSeedStr){this.randomSeedStr =Optional.of(randomSeedStr);returnthis;}publicAlgorithmParamsetNgAlgorithm(NumberGenerationAlgorithm ngAlgorithm){this.ngAlgorithm =Optional.of(ngAlgorithm);returnthis;}publicAlgorithmParamsetAlgorithmParameterStr(String algorithmParameterStr){this.algorithmParameterStr =Optional.of(algorithmParameterStr);returnthis;}publicOptional<String>getPlainText(){return plainText;}publicOptional<String>getBase64CipherText(){return base64CipherText;}publicOptional<String>getSecretKeyStr(){return secretKeyStr;}publicOptional<String>getRandomSeedStr(){return randomSeedStr;}publicOptional<NumberGenerationAlgorithm>getNgAlgorithm(){return ngAlgorithm;}publicOptional<String>getAlgorithmParameterStr(){return algorithmParameterStr;}}
packagecom.qupeng.crypto.algorithm.fp;importcom.qupeng.crypto.algorithm.oop.NumberGenerationAlgorithm;importsun.misc.BASE64Decoder;importsun.misc.BASE64Encoder;importjavax.crypto.BadPaddingException;importjavax.crypto.Cipher;importjavax.crypto.IllegalBlockSizeException;importjava.io.IOException;importjava.lang.reflect.InvocationTargetException;importjava.security.InvalidAlgorithmParameterException;importjava.security.InvalidKeyException;importjava.security.Key;importjava.util.Optional;importjava.util.OptionalInt;importjava.util.function.BiConsumer;importjava.util.function.BiFunction;importjava.util.function.Function;publicclassEncryptor{privateOptional<Transformation> transformation =Optional.empty();privateOptionalInt secretKeyBitLength =OptionalInt.empty();privateOptional<AlgorithmParameterSpecInfo> algorithmParameterSpecInfo =Optional.empty();privateOptional<String> plainText =Optional.empty();privateOptional<String> base64CipherText =Optional.empty();privateOptional<String> secretKeyStr =Optional.empty();privateOptional<String> randomSeedStr =Optional.empty();privateOptional<NumberGenerationAlgorithm> ngAlgorithm =Optional.empty();privateOptional<String> algorithmParameterStr =Optional.empty();privateOptional<BiFunction<String,String,Key>> keyGeneratorByStr =Optional.empty();privateOptional<BiFunction<String,NumberGenerationAlgorithm,Key>> keyGeneratorByRandomSeed =Optional.empty();privateOptional<Function<String,Cipher>> cipherSupplier =Optional.empty();privateOptional<BiFunction<String,Integer,byte[]>> padding =Optional.empty();privateOptional<BiConsumer<Cipher,Key>> initCipher =Optional.empty();publicOptional<String>encrypt()throwsBadPaddingException,IllegalBlockSizeException,InvalidKeyException,NoSuchMethodException,InvalidAlgorithmParameterException,IllegalAccessException,InstantiationException,InvocationTargetException{// Step1: create a Cipher instanceCipher cipher = cipherSupplier.get().apply(this.transformation.get().toString());// Step2: padding plain text if no-paddingbyte[][] plainTextBytes =newbyte[1][];if("NoPadding".equals(transformation.get().getPadding().get())){
padding.ifPresent(paddingOperator -> plainTextBytes[0]= paddingOperator.apply(plainText.get(), cipher.getBlockSize()));}else{
plainTextBytes[0]= plainText.get().getBytes();}// Step3: generate secret keyKey[] secretKey =generateSecretKey();// Step4: init cipher
initCipher.ifPresent(init -> init.accept(cipher, secretKey[0]));// Step5: encrypt plain textbyte[] encrypted = cipher.doFinal(plainTextBytes[0]);String cipherText =newBASE64Encoder().encode(encrypted);System.out.println(String.format("%s(%d) plain text: %s -> cipher text: %s",this.transformation.get().toString(),this.secretKeyBitLength.getAsInt(), plainText.get(), cipherText));returnOptional.ofNullable(cipherText);}publicOptional<String>decrypt()throwsIOException,BadPaddingException,IllegalBlockSizeException,InvalidKeyException,NoSuchMethodException,InvalidAlgorithmParameterException,IllegalAccessException,InstantiationException,InvocationTargetException{// Step1: create a Cipher instanceCipher cipher = cipherSupplier.get().apply(this.transformation.get().toString());// Step2: generate secret keyKey[] secretKey =generateSecretKey();// Step3: init cipher
initCipher.ifPresent(init -> init.accept(cipher, secretKey[0]));// Step4: decrypt cipher textbyte[] plainBytes = cipher.doFinal(newBASE64Decoder().decodeBuffer(base64CipherText.get()));String plainText =newString(plainBytes).trim();System.out.println(String.format("%s(%d) cipher text: %s -> plain text: %s",this.transformation.get().toString(),this.secretKeyBitLength.getAsInt(), base64CipherText.get(), plainText));returnOptional.of(plainText);}privateKey[]generateSecretKey(){Key secretKey[]=newKey[1];
keyGeneratorByStr.ifPresent(keyGenerator -> secretKey[0]= keyGenerator.apply(secretKeyStr.get(), transformation.get().getAlgorithm().get()));
keyGeneratorByRandomSeed.ifPresent(keyGenerator -> secretKey[0]= keyGenerator.apply(randomSeedStr.get(), ngAlgorithm.get()));return secretKey;}publicEncryptorsetTransformation(Transformation transformation){this.transformation =Optional.of(transformation);returnthis;}publicEncryptorsetSecretKeyBitLength(int secretKeyBitLength){this.secretKeyBitLength =OptionalInt.of(secretKeyBitLength);returnthis;}publicEncryptorsetAlgorithmParameterSpecInfo(AlgorithmParameterSpecInfo algorithmParameterSpecInfo){this.algorithmParameterSpecInfo =Optional.of(algorithmParameterSpecInfo);returnthis;}publicEncryptorsetPlainText(String plainText){this.plainText =Optional.of(plainText);returnthis;}publicEncryptorsetBase64CipherText(String base64CipherText){this.base64CipherText =Optional.of(base64CipherText);returnthis;}publicEncryptorsetSecretKeyStr(String secretKeyStr){this.secretKeyStr =Optional.of(secretKeyStr);returnthis;}publicEncryptorsetRandomSeedStr(String randomSeedStr){this.randomSeedStr =Optional.of(randomSeedStr);returnthis;}publicEncryptorsetNgAlgorithm(NumberGenerationAlgorithm ngAlgorithm){this.ngAlgorithm =Optional.of(ngAlgorithm);returnthis;}publicEncryptorsetAlgorithmParameterStr(String algorithmParameterStr){this.algorithmParameterStr =Optional.of(algorithmParameterStr);returnthis;}publicvoidsetKeyGeneratorByStr(BiFunction<String,String,Key> keyGeneratorByStr){this.keyGeneratorByStr =Optional.of(keyGeneratorByStr);}publicvoidsetKeyGenerator(BiFunction<String,NumberGenerationAlgorithm,Key> keyGeneratorByRandomSeed){this.keyGeneratorByRandomSeed =Optional.of(keyGeneratorByRandomSeed);}publicvoidsetCipherSupplier(Function<String,Cipher> cipherSupplier){this.cipherSupplier =Optional.of(cipherSupplier);}publicvoidsetPadding(BiFunction<String,Integer,byte[]> padding){this.padding =Optional.of(padding);}publicvoidsetInitCipher(BiConsumer<Cipher,Key> initCipher){this.initCipher =Optional.of(initCipher);}}
packagecom.qupeng.crypto.algorithm.fp;importjava.util.Optional;publicclassTransformation{privateOptional<String> algorithm =Optional.empty();privateOptional<String> mode =Optional.empty();privateOptional<String> padding =Optional.empty();publicTransformation(String algorithm,String mode,String padding){this.algorithm =Optional.of(algorithm);this.mode =Optional.of(mode);this.padding =Optional.of(padding);}publicOptional<String>getAlgorithm(){return algorithm;}publicOptional<String>getMode(){return mode;}publicOptional<String>getPadding(){return padding;}@OverridepublicStringtoString(){returnString.format("%s/%s/%s",this.algorithm.get(),this.mode.get(),this.padding.get());}}
packagecom.qupeng.crypto.algorithm.fp;importjava.security.spec.AlgorithmParameterSpec;importjava.util.Optional;importjava.util.OptionalInt;publicclassAlgorithmParameterSpecInfo{privateOptional<Class<?extendsAlgorithmParameterSpec>> algorithmParameterSpecClass;privateOptionalInt algorithmParameterBitLength =OptionalInt.empty();publicAlgorithmParameterSpecInfo(Class<?extendsAlgorithmParameterSpec> algorithmParameterSpecClass,int algorithmParameterBitLength){this.algorithmParameterSpecClass =Optional.of(algorithmParameterSpecClass);this.algorithmParameterBitLength =OptionalInt.of(algorithmParameterBitLength);}publicOptional<Class<?extendsAlgorithmParameterSpec>>getAlgorithmParameterSpecClass(){return algorithmParameterSpecClass;}publicOptionalIntgetAlgorithmParameterBitLength(){return algorithmParameterBitLength;}}
packagecom.qupeng.crypto.algorithm.oop;publicenumNumberGenerationAlgorithm{NATIVE_PRNG("NativePRNG"),NATIVE_PRNG_BLOCKING("NativePRNGBlocking"),NATIVE_PRNG_NON_BLOCKING("NativePRNGNonBlocking"),PKCS11("PKCS11"),SHA1_PRNG("SHA1PRNG"),WINDOWS_PRNG("Windows-PRNG");privateString algorithmName ="";NumberGenerationAlgorithm(String algorithmName){this.algorithmName = algorithmName;}publicStringgetAlgorithmName(){returnthis.algorithmName;}}
版权归原作者 yunyun1886358 所有, 如有侵权,请联系我们删除。