关于AES(16字节)加密解密算法的java实现
根据指定的字符串来实现AES加密和解密,密匙可参数化配置,加密后数据的前两个字节是数据包的长度,加密算法选用AES/ECB /PKCS5Padding。即采用标准AES算法,把全报文按照每块16字节分块进行加解密,对于不足16字节的数据块按照PKCS5方式补充,缺少N 个字节则把缺少的N个字节都以N来填充,最后一个数据块刚好16字节,则增加一个全部字节都填充为16的数据块。
=====================================
AesHandler.java
=====================================
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.SecretKeySpec;
import org.dom4j.Document;
import org.dom4j.io.SAXReader;
import org.dom4j.DocumentException;
import org.dom4j.Element;
public class AesHandler {
private String plainTextFile = "src/encode.txt";// 明文文件
private String cipherTextFile = "src/aesDecode.txt";// 密文文件
private String keyFile = "src/aesKey.xml";// 加密密匙文件
/**
*
* @param keyName
* 加密密匙名
* @return
*/
public SecretKeySpec createKey(String keyName) {
SAXReader reader = new SAXReader();
Document doc;
SecretKeySpec skeySpec = null;
byte[] raw;
File keyXmlFile = new File(keyFile);
try {
doc = reader.read(keyXmlFile);
Element root = doc.getRootElement();
List items = root.elements("key16");
for(int i = 0; i < items.size(); i++){
Element node = (Element)items.get(i);
if(keyName.equalsIgnoreCase(node.attributeValue("name"))){
raw = node.attributeValue("value").getBytes("ASCII");
skeySpec = new SecretKeySpec(raw, "AES");
return skeySpec;
}
}
} catch (DocumentException e) {
e.printStackTrace();
// throw new HiException(HiMessageCode.ERR_PARSE_FAILURE, _fmtFile,
// e);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return skeySpec;
}
/**
*
* @param code
* 选择加密或解密操作码
* @param keyFileStr
* 加密密匙文件
* @param plainFile 明文文件
* @param cipherFile 密文文件
* @param keyName 密匙名
*/
public void run(String code, String keyName) {
int mode = Cipher.ENCRYPT_MODE;
InputStream in = null;
OutputStream out = null;
try {
SecretKeySpec skeySpec = createKey(keyName);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
if ("DECODE".equals(code)) {
mode = Cipher.DECRYPT_MODE;
in = new FileInputStream(cipherTextFile);
out = new FileOutputStream(plainTextFile);
cipher.init(mode, skeySpec);
decrypt(in, out, cipher);// 解密
} else {
in = new FileInputStream(plainTextFile);
out = new FileOutputStream(cipherTextFile);
cipher.init(mode, skeySpec);
encrypt(in, out, cipher);// 加密
}
in.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static byte[] shortToByteArray(int valor) {
byte[] result = new byte[2];
for (int i = 0; i < result.length; i++) {
result[1 - i] = (byte) (valor & 0xFF);
valor = valor >> 8;
}
return result;
}
/**
* 加密算法
*
* @param in
* 明文数据流
* @param out
* 密文数据流
* @param cipher
* @throws IOException
* @throws ShortBufferException
* @throws GeneralSecurityException
*/
public static void encrypt(InputStream in, OutputStream out, Cipher cipher)
throws IOException, ShortBufferException, GeneralSecurityException {
int blockSize = cipher.getBlockSize();
int outputSize = cipher.getOutputSize(blockSize);
byte[] inBytes = new byte[blockSize];
byte[] outBytes = new byte[outputSize];
byte[] appendAllBytes = new byte[blockSize];
byte[] appendBytes = new byte[blockSize];
int inLength = 0;
int length1 = in.available();
boolean more = true;
int yushu = length1 % 16;
if (yushu == 0) {
for (int i = 0; i < 16; i++) {
appendAllBytes[i] = new Integer(16).byteValue();
}
out.write(shortToByteArray(length1 + blockSize));
} else {
int N = blockSize - yushu;
out.write(shortToByteArray(length1 + N));
}
while (more) {
inLength = in.read(inBytes);
if (inLength == blockSize) {
int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
out.write(outBytes, 0, outLength);
} else
more = false;
}
if (inLength > 0 && inLength < blockSize) {// 不足16字节的数据块按照PKCS5方式补充,缺少N个字节则把缺少的N个字节都以N来填充
int N = blockSize - inLength;
for (int M = inLength; M < blockSize; M++) {
inBytes[M] = new Integer(N).byteValue();
}
outBytes = cipher.doFinal(inBytes, 0, inLength);
out.write(outBytes);
} else if (inLength == 0) {// 如果正好是16位,则增加一个全部字节都填充为16的数据块
int outLength = cipher.doFinal(appendBytes, 0, blockSize, outBytes);
out.write(outBytes, 0, outLength);
}
out.flush();
}
/**
* 解密算法
*
* @param in
* 密文数据流
* @param out
* 明文数据流
* @param cipher
* @throws IOException
* @throws ShortBufferException
* @throws GeneralSecurityException
*/
public static void decrypt(InputStream in, OutputStream out, Cipher cipher)
throws IOException, ShortBufferException, GeneralSecurityException {
int blockSize = cipher.getBlockSize();
int outputSize = cipher.getOutputSize(blockSize);
byte[] inBytes = new byte[blockSize];
byte[] outBytes = new byte[outputSize];
byte[] dataLength = new byte[2];
int inLength = 0;
boolean more = true;
in.read(dataLength);// 将数据包的长度读入到byte数组中
while (more) {
inLength = in.read(inBytes);
if (inLength == blockSize) {
int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
out.write(outBytes, 0, outLength);
} else
more = false;
}
if (inLength > 0) {
outBytes = cipher.doFinal(inBytes, 0, inLength);
} else {
outBytes = cipher.doFinal();
}
out.write(outBytes);
out.flush();
}
public String getPlainTextFile() {
return plainTextFile;
}
public void setPlainTextFile(String plainTextFile) {
this.plainTextFile = plainTextFile;
}
public String getCipherTextFile() {
return cipherTextFile;
}
public void setCipherTextFile(String cipherTextFile) {
this.cipherTextFile = cipherTextFile;
}
public String getKeyFile() {
return keyFile;
}
public void setKeyFile(String keyFile) {
this.keyFile = keyFile;
}
}
=======================================================================
aesKey.xml文件
=============================
<?xml version="1.0" encoding="GB2312"?>
<KEY>
<key16 name="test" value="16BAESBocHK2Mcis"></key16>
</KEY>
=======================================================================
测试:
加密密钥: 16BAESBocHK2Mcis
明文: ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%!&*()_+-=:;'?,./
密文为:
=========================From 001 Lines to 016============================
Debug: -1--2--3--4--5--6--7--8--9-HEX-1--2--3--4--5--6 ---ASCII Value--
00001: 00 40 0e 49 32 64 f8 07 c0 fd 22 80 49 6f 80 32 .@.I2d..例".Io.2
00002: 50 c5 97 73 f4 55 83 fb 59 6d 85 3c 82 1c 30 a3 P艞s.U凔Ym.<..0.
00003: d8 49 45 fc e2 83 3d 39 a2 d2 6e 06 4f a6 94 1c .IE .=9⒁n.O .
00004: 19 2d 38 6d 81 e7 34 3b f7 5d 2b ff 83 a6 14 c2 .-8m佺4;.]+?..
00005: 2d 0e >-.
====================================end================================