最近我编程真的是走火入魔。更是对加密痴迷。最近整了个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上翻就可以了~
我告诉你,你可别轻易转载!
网友评论