最近我编程真的是走火入魔. 更是对加密痴迷. 最近整了个 AES-CBC 的加密算法, 然后用它做了个 GUI 的加密界面. 我不晒 GUI, 但是加密算法还是要说的~
AES 的 CBC 模式, 总是比没有偏移量的 ECB 模式安全得多. 实现方式并不难, 只是多了个偏移量.
注意! 这里需要外部包 org.apache.commons.codec.binary.Base64 库, 请去百度上搜索并下载!
话不多说, 进入标题.
首先, 为了能更好地运用模块, 我们下面来了解一下:
- // 需要的库:
- import javax.crypto.*
- import javax.crypto.spec.*// 以上两个是 java 原生的加密库
- import org.apache.commons.codec.binary.Base64 //Base64 加密库
- ----------------
- SecretKeySpec(byte[] 密钥 key, "AES") // 是密钥的一个类
- IvParameterSpec(byte[] 偏移量 IV) // 是偏移量的一个类
- Cipher() // 加密原生类.
- Cipher.getInstance("AES/CBC/PKCS5Padding") // 获取 Cipher 的对象, 与 new 一样. 参数格式为: 加密算法 / 加密模式 / 填码格式
- Cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec 密钥 Key, IvParameterSpec 偏移量 IV) // 对 Cipher 对象做初始化. DECRYPT_MODE 为解密模式, ENCRYPT_MODE 为加密模式.
- Cipher.doFinal(byte[] 要加密或解密的字符串) // 结束对 Cipher 对象的参数控制, 加密或解密字符串并返回密文.(byte[])
- Base64().encodeToString(byte[] 要加密的字符串) // 返回 Base64 加密的 String 字符串.
- Base64().decode(byte[] 要解密的字符串) // 返回 Base64 解密后的 byte[]字符串.
如果密钥是空的, 密钥不够长怎么办? 那只好抛出错误. 我自定义了错误类还写了一大堆 throw, 真是小题大做啊......
下面是一个错误类的参考:
- public class NullKeyException extends Exception{ // 几乎我自定义的三个类格式一模一样, 只是名字和构造方法变了
- /**
- * 构建一个不带信息的异常.
- */
- public NullKeyException() {
- }
- /**
- * 构建一个带信息的异常.
- * @param msg 消息
- */
- public NullKeyException(String msg) {
- super(msg);
- }
- }
- // 调用下列方法即可抛出错误:
- throw new NullKeyException();
有了妥妥的参考, 说不定就可以无师自通了. 唯一的难点就是返回的字符串类型 byte[]和 String 容易混淆. 他们是不可互通的.
咱们把参数串起来, 写一个 Class.
- public class CBC {
- private static String str = null, key = null, iv = null;
- /**
- * 构建一个新的 AES-CBC 加密对象.
- * @param STR 解密或加密的字符串
- * @param KEY 秘钥
- * @param IV 偏移量
- */
- public CBC(String STR, String KEY, String IV){
- str = STR;
- key = KEY;
- iv = IV;
- }
- /**
- * 随机获取一个秘钥.
- * @return 秘钥
- */
- public static final String GetKey(){// 至于解决方法可以去百度一下的.
- String chars = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890";
- StringBuffer value = new StringBuffer();
- for(int i = 0; i < 16; i++){
- value.append(chars.charAt((int) (Math.random()* 62)));
- }
- return value.toString();
- }
- /**
- * 随机获取一个偏移量.
- * @return 秘钥
- */
- public static final String GetIV(){// 至于解决方法可以去百度一下的.
- String chars = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890";
- StringBuffer value = new StringBuffer();
- for(int i = 0; i < 16; i++){
- value.append(chars.charAt((int) (Math.random()* 62)));
- }
- return value.toString();
- }
- /**
- * 加密字符串.
- * @return 正常则返回加密后的数据, 秘钥, 偏移量错误或其他错误均会被抛出.
- * @throws Exception 其他错误
- * @throws NullKeyException 秘钥为空
- * @throws NullIvException 偏移量为空
- * @throws KeyIvNotLengthyException 秘钥或偏移量的长度不够 16 位
- */
- public static String Encrypt() throws Exception,
- NullKeyException,
- NullIvException,
- KeyIvNotLengthyException{
- if(key == null) throw new NullKeyException();
- if(key.length() != 16) throw new KeyIvNotLengthyException("秘钥的长度不够 16 位");
- if(iv == null) throw new NullIvException();
- if(iv.length() != 16) throw new KeyIvNotLengthyException("偏移量 (IV) 的长度不够 16 位");
- byte[] raw = key.getBytes("utf-8");
- SecretKeySpec key_spec = new SecretKeySpec(raw, "AES");
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- IvParameterSpec IV = new IvParameterSpec(iv.getBytes());
- cipher.init(Cipher.ENCRYPT_MODE, key_spec, IV);
- byte[] encrypted = cipher.doFinal(str.getBytes());
- return new Base64().encodeToString(encrypted);
- }
- /**
- * 解密字符串.
- * @return 正常则返回解密后的数据, 秘钥, 偏移量错误或其他错误均会被抛出.
- * @throws Exception 其他错误
- * @throws NullKeyException 秘钥为空
- * @throws NullIvException 偏移量为空
- * @throws KeyIvNotLengthyException 秘钥或偏移量的长度不够 16 位
- */
- public static String Decrypt() throws Exception,
- NullKeyException,
- NullIvException,
- KeyIvNotLengthyException{
- if(key == null) throw new NullKeyException();
- if(key.length() != 16) throw new KeyIvNotLengthyException("秘钥的长度不够 16 位");
- if(iv == null) throw new NullIvException();
- if(iv.length() != 16) throw new KeyIvNotLengthyException("偏移量 (IV) 的长度不够 16 位");
- SecretKeySpec key_spec = new SecretKeySpec(key.getBytes("utf-8"), "AES");
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- IvParameterSpec IV = new IvParameterSpec(iv.getBytes("utf-8"));
- cipher.init(Cipher.DECRYPT_MODE, key_spec, IV);
- byte[] encryptding = new Base64().decode(str);
- return new String(cipher.doFinal(encryptding));
- }
- }
如果还是不理解的话, 去我 GitHub 上翻就可以了~
我告诉你, 你可别轻易转载!
来源: http://www.jianshu.com/p/381f9085dc9c