彻底告别加解密模块代码拷贝(6)

加密模式下,Cipher只能用于加密,主要由init方法中的opmode决定。举个例子:

public String encryptByAes(String content, String password) throws Exception { //这里指定了算法为AES_128,工作模式为EBC,填充模式为NoPadding Cipher cipher = Cipher.getInstance("AES_128/ECB/NoPadding"); KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); //因为AES要求密钥的长度为128,我们需要固定的密码,因此随机源的种子需要设置为我们的密码数组 keyGenerator.init(128, new SecureRandom(password.getBytes())); SecretKey secretKey = keyGenerator.generateKey(); SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), "AES"); //基于加密模式和密钥初始化Cipher cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); //单部分加密结束,重置Cipher byte[] bytes = cipher.doFinal(content.getBytes()); //加密后的密文由二进制序列转化为十六进制序列,依赖apache-codec包 return Hex.encodeHexString(bytes); }

其实整个过程Cipher的使用都很简单,比较复杂的反而是密钥生成的过程。上面的例子需要注意,因为使用了填充模式为NoPadding,输入的需要加密的报文长度必须是16(128bit)的倍数。

解密模式

解密模式的使用大致和加密模式是相同的,把处理过程逆转过来就行:

public String decryptByAes(String content, String password) throws Exception { //这里要把十六进制的序列转化回二进制的序列,依赖apache-codec包 byte[] bytes = Hex.decodeHex(content); //这里指定了算法为AES_128,工作模式为EBC,填充模式为NoPadding Cipher cipher = Cipher.getInstance("AES_128/ECB/NoPadding"); KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); //因为AES要求密钥的长度为128,我们需要固定的密码,因此随机源的种子需要设置为我们的密码数组 keyGenerator.init(128, new SecureRandom(password.getBytes())); SecretKey secretKey = keyGenerator.generateKey(); SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), "AES"); //基于解密模式和密钥初始化Cipher cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); //单部分加密结束,重置Cipher byte[] result = cipher.doFinal(bytes); return new String(result); }

上面的例子需要注意,因为使用了填充模式为NoPadding,输入的需要加密的报文长度必须是16(128bit)的倍数。

包装密钥模式和解包装密钥模式

密钥的包装和解包装模式是一对互逆的操作,主要作用是通过算法对密钥进行加解密,从而提高密钥泄漏的难度。

public enum EncryptUtils { /** * 单例 */ SINGLETON; private static final String SECRECT = "passwrod"; public String wrap(String keyString) throws Exception { KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); //初始化密钥生成器,指定密钥长度为128,指定随机源的种子为指定的密钥(这里是"passward") keyGenerator.init(128, new SecureRandom(SECRECT.getBytes())); SecretKey secretKey = keyGenerator.generateKey(); SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.WRAP_MODE, secretKeySpec); SecretKeySpec key = new SecretKeySpec(keyString.getBytes(), "AES"); byte[] bytes = cipher.wrap(key); return Hex.encodeHexString(bytes); } public String unwrap(String keyString) throws Exception { byte[] rawKey = Hex.decodeHex(keyString); KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); //初始化密钥生成器,指定密钥长度为128,指定随机源的种子为指定的密钥(这里是"passward") keyGenerator.init(128, new SecureRandom(SECRECT.getBytes())); SecretKey secretKey = keyGenerator.generateKey(); SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.UNWRAP_MODE, secretKeySpec); SecretKey key = (SecretKey) cipher.unwrap(rawKey, "AES", Cipher.SECRET_KEY); return new String(key.getEncoded()); } public static void main(String[] args) throws Exception { String wrapKey = EncryptUtils.SINGLETON.wrap("doge"); System.out.println(wrapKey); System.out.println(EncryptUtils.SINGLETON.unwrap(wrapKey)); } } 分组(部分)加密和分组解密

当一个需要加密的报文十分长的时候,我们可以考虑把报文切割成多个小段,然后针对每个小段进行加密,这就是分组加密。分组解密的过程类同,可以看作是分组加密的逆向过程。下面还是用AES算法为例举个例子:

import org.apache.commons.codec.binary.Hex; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.security.SecureRandom; /** * @author throwable * @version v1.0 * @description * @since 2018/8/15 1:06 */ public enum Part { /** * SINGLETON */ SINGLETON; private static final String PASSWORD = "throwable"; private Cipher createCipher() throws Exception { return Cipher.getInstance("AES"); } public String encrypt(String content) throws Exception { Cipher cipher = createCipher(); KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); //因为AES要求密钥的长度为128,我们需要固定的密码,因此随机源的种子需要设置为我们的密码数组 keyGenerator.init(128, new SecureRandom(PASSWORD.getBytes())); SecretKey secretKey = keyGenerator.generateKey(); SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), "AES"); //基于加密模式和密钥初始化Cipher cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); byte[] raw = content.getBytes(); StringBuilder builder = new StringBuilder(); //[0,9] byte[] first = cipher.update(raw, 0, 10); builder.append(Hex.encodeHexString(first)); //[10,19] byte[] second = cipher.update(raw, 10, 10); builder.append(Hex.encodeHexString(second)); //[20,25] byte[] third = cipher.update(raw, 20, 6); builder.append(Hex.encodeHexString(third)); //多部分加密结束,得到最后一段加密的结果,重置Cipher byte[] bytes = cipher.doFinal(); String last = Hex.encodeHexString(bytes); builder.append(last); return builder.toString(); } public String decrypt(String content) throws Exception { byte[] raw = Hex.decodeHex(content); Cipher cipher = createCipher(); KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); //因为AES要求密钥的长度为128,我们需要固定的密码,因此随机源的种子需要设置为我们的密码数组 keyGenerator.init(128, new SecureRandom(PASSWORD.getBytes())); SecretKey secretKey = keyGenerator.generateKey(); SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), "AES"); //基于解密模式和密钥初始化Cipher cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); StringBuilder builder = new StringBuilder(); //[0,14] byte[] first = cipher.update(raw, 0, 15); builder.append(new String(first)); //[15,29] byte[] second = cipher.update(raw, 15, 15); builder.append(new String(second)); //[30,31] byte[] third = cipher.update(raw, 30, 2); builder.append(new String(third)); //多部分解密结束,得到最后一段解密的结果,重置Cipher byte[] bytes = cipher.doFinal(); builder.append(new String(bytes)); return builder.toString(); } public static void main(String[] args) throws Exception{ String raw = "abcdefghijklmnopqrstyuwxyz"; String e = Part.SINGLETON.encrypt(raw); System.out.println(e); System.out.println(Part.SINGLETON.decrypt(e)); } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/b5e4d8f6f0ddf4f7771d5bbfc73289c8.html