一、前言:
BASE64和AES一起介绍,有两个工具类,直接使用即可。
gitHub地址:https://gitee.com/luoyanyong/AESDemo/tree/master/app/src/main/java/com/sumansoul/aesdemo
注意:
- 解决AES加密报错:java.security.InvalidKeyException: Unsupported key size: 6 bytes。
原因:
AES秘钥字节就我们传入的解密的秘钥,
这是由于AES的秘钥写错了,规定是16位秘钥,写成了6位的秘钥。
解决:将AES秘钥改成规定的16位即可。
1. 基本使用:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//BASE64使用
initBASE64();
//AES使用
initAES();
//MD5使用
initMD5();
//最简单的AES使用(第二种使用方式)
initAES2();
}
/**
* BASE64使用
*/
private void initBASE64() {
String value = "1992090876";
Log.d("LUO","BASE64原数据============"+value);
String encryptionBASE64 = Base64Utils.getEncryptionBASE64(value);
Log.d("LUO","BASE64加密数据============"+encryptionBASE64);
String decryptFromBASE64 = Base64Utils.getDecryptFromBASE64(encryptionBASE64);
Log.d("LUO","BASE64解密数据============"+decryptFromBASE64);
// LUO: BASE64原数据============1992090876
// LUO: BASE64加密数据============MTk5MjA5MDg3Ng==
// LUO: BASE64解密数据============1992090876
}
/**
* AES使用
*/
private void initAES() {
String aes = "123456789";
//将AES秘钥改成规定的16位即可。
String key = "0123456789123456";
try {
Log.d("LUO","AES原数据============"+aes);
//加密
String encryption= AESEncryptUtils.encryptAES(aes,key);
Log.d("LUO","AES加密后============"+encryption);
//解密
String decrypt = AESEncryptUtils.decryptAES(encryption,key);
Log.d("LUO","AES解密后============"+decrypt);
// LUO: AES原数据============123456789
// LUO: AES加密后============jvTvlQaeDHK77gai7Eb2Gg==
// LUO: AES解密后============123456789
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* MD5使用
* MD5是不可逆,这里的加密解密,你可以看到是对MD5算法先加密后解密,而不是对MD5的解密
*/
private void initMD5() {
String value = "123456";
Log.d("LUO","MD5原数据============"+value);
//加密的MD5
String md5Encode = MD5Utils.MD5Encode(value);
Log.d("LUO","MD5加密后数据============"+md5Encode);
//对解密的MD5,再加密
String md5Encode_kl = MD5Utils.KL(MD5Utils.MD5Encode(value));
Log.d("LUO","MD5_kl加密后数据============"+md5Encode_kl);
//对解密的MD5,解加密
String decrypt = MD5Utils.MD5Decrypt(md5Encode_kl);
Log.d("LUO","MD5_kl解密后数据============"+decrypt);
// LUO: MD5原数据============123456
// LUO: MD5加密后数据============e10adc3949ba59abbe56e057f20f883e
// LUO: MD5_kl加密后数据============�ED���GM@M��AM����AB�DAC�FD�LLG�
// LUO: MD5_kl解密后数据============e10adc3949ba59abbe56e057f20f883e
}
}
/**
* 最简单的AES使用(第二种使用方式)
*/
private void initAES2() {
try {
String value = "123456789";
Log.d("LUO","initAES2原数据============"+value);
String encrypt = AESUtil.encrypt(value);
Log.d("LUO","initAES2加密数据============"+encrypt);
String decrypt = AESUtil.decrypt(encrypt);
Log.d("LUO","initAES2解密数据============"+decrypt);
// LUO: initAES2原数据============123456789
// LUO: initAES2加密数据============OpuRX5DJc8lewuB7qQkpzw==
// LUO: initAES2解密数据============123456789
} catch (Exception e) {
e.printStackTrace();
}
}
2. Base64Utils.java类
package com.sumansoul.aesdemo;
import com.sumansoul.aesdemo.utils.BASE64Decoder;
import com.sumansoul.aesdemo.utils.BASE64Encoder;
/**
* Base64的加密和解密
*/
public class Base64Utils {
/**
* 将 value 进行 BASE64 编码
*
* @param value
* @return
*/
public static String getEncryptionBASE64(String value) {
if (value == null) {
return null;
}
return (new BASE64Encoder()).encode(value.getBytes());
}
/**
* 将 BASE64 编码的字符串 value 进行解码
*
* @param value
* @return
*/
public static String getDecryptFromBASE64(String value) {
if (value == null) {
return null;
}
BASE64Decoder decoder = new BASE64Decoder();
try {
byte[] b = decoder.decodeBuffer(value);
return new String(b);
} catch (Exception e) {
return null;
}
}
}
3. AESEncryptUtils.java类
package com.sumansoul.aesdemo.utils;
import android.text.TextUtils;
import java.math.BigInteger;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* 编码工具类
* 1.将byte[]转为各种进制的字符串
* 2.base 64 encode
* 3.base 64 decode
* 4.获取byte[]的md5值
* 5.获取字符串md5值
* 6.结合base64实现md5加密
* 7.AES加密
* 8.AES加密为base 64 code
* 9.AES解密
* 10.将base 64 code AES解密
*
* @author uikoo9
* @version 0.0.7.20140601
*/
public class AESEncryptUtils {
/**
* 1.电码本模式(Electronic Codebook Book (ECB))不支持;
* 2.密码分组链接模式(Cipher Block Chaining (CBC))默认的加密算法;
* 3.计算器模式(Counter (CTR));
* 4.密码反馈模式(Cipher FeedBack (CFB));
* 5.输出反馈模式(Output FeedBack (OFB))。
*/
// 指定加密的算法、工作模式和填充方式
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
/**
* 偏移量
*/
private static final String IV_STRING = "1234561234567890";
/**
* 将byte[]转为各种进制的字符串
*
* @param bytes byte[]
* @param radix 可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制
* @return 转换后的字符串
*/
public static String binary(byte[] bytes, int radix) {
return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数
}
/**
* base 64 encode
*
* @param bytes 待编码的byte[]
* @return 编码后的base 64 code
*/
public static String base64Encode(byte[] bytes) {
return new BASE64Encoder().encode(bytes);
}
/**
* base 64 decode
*
* @param base64Code 待解码的base 64 code
* @return 解码后的byte[]
* @throws Exception
*/
public static byte[] base64Decode(String base64Code) throws Exception {
return TextUtils.isEmpty(base64Code) ? null : new BASE64Decoder().decodeBuffer(base64Code);
}
/**
* 获取byte[]的md5值
*
* @param bytes byte[]
* @return md5
* @throws Exception
*/
public static byte[] md5(byte[] bytes) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(bytes);
return md.digest();
}
/**
* 获取字符串md5值
*
* @param msg
* @return md5
* @throws Exception
*/
public static byte[] md5(String msg) throws Exception {
return TextUtils.isEmpty(msg) ? null : md5(msg.getBytes());
}
/**
* 结合base64实现md5加密
*
* @param msg 待加密字符串
* @return 获取md5后转为base64
* @throws Exception
*/
public static String md5Encrypt(String msg) throws Exception {
return TextUtils.isEmpty(msg) ? null : base64Encode(md5(msg));
}
/**
* AES加密
*
* @param content 待加密的内容
* @param encryptKey 加密密钥
* @return 加密后的byte[]
* @throws Exception
*/
public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
// KeyGenerator kgen = KeyGenerator.getInstance("AES");
// kgen.init(128, new SecureRandom(encryptKey.getBytes()));
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(encryptKey.getBytes());
kgen.init(128, random);
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));
return cipher.doFinal(content.getBytes("utf-8"));
}
/**
* AES加密为base 64 code
*
* @param content 待加密的内容
* @param encryptKey 加密密钥
* @return 加密后的base 64 code
* @throws Exception
*/
public static String aesEncrypt(String content, String encryptKey) throws Exception {
return base64Encode(aesEncryptToBytes(content, encryptKey));
}
/**
* AES解密
*
* @param encryptBytes 待解密的byte[]
* @param decryptKey 解密密钥
* @return 解密后的String
* @throws Exception
*/
public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws
Exception {
// KeyGenerator kgen = KeyGenerator.getInstance("AES");
// kgen.init(128, new SecureRandom(decryptKey.getBytes()));
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(decryptKey.getBytes());
kgen.init(128, random);
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));
byte[] decryptBytes = cipher.doFinal(encryptBytes);
return new String(decryptBytes);
}
/**
* 将base 64 code AES解密
*
* @param encryptStr 待解密的base 64 code
* @param decryptKey 解密密钥
* @return 解密后的string
*/
public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
return TextUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr),
decryptKey);
}
/**
* @param content
* @param key 将AES秘钥改成规定的16位即可。
* @return
* @throws Exception 加密(使用这个)
*/
public static String encryptAES(String content, String key)
throws Exception {
byte[] byteContent = content.getBytes("UTF-8");
// 注意,为了能与 iOS 统一
// 这里的 key 不可以使用 KeyGenerator、SecureRandom、SecretKey 生成
byte[] enCodeFormat = key.getBytes();
SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
byte[] initParam = IV_STRING.getBytes();
IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
// 指定加密的算法、工作模式和填充方式
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encryptedBytes = cipher.doFinal(byteContent);
// 同样对加密后数据进行 base64 编码
return base64Encode(encryptedBytes);
}
/**
* @param content
* @param key 将AES秘钥改成规定的16位即可。
* @return
* @throws Exception 解密(使用这个)
*/
public static String decryptAES(String content, String key)
throws Exception {
// base64 解码
byte[] encryptedBytes = base64Decode(content);
byte[] enCodeFormat = key.getBytes();
SecretKeySpec secretKey = new SecretKeySpec(enCodeFormat, "AES");
byte[] initParam = IV_STRING.getBytes();
IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
byte[] result = cipher.doFinal(encryptedBytes);
return new String(result, "UTF-8");
}
}
4. MD5Utils.java类
package com.sumansoul.aesdemo.utils;
import java.security.MessageDigest;
/**
* @Author:LUO
* @Description:
* @Date:Created in 9:46 2018/4/13
* Modified By:
*/
public class MD5Utils {
private static final String hexDigIts[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
/**
* MD5加密数据
*/
public static String MD5Encode(String value) {
String resultString = null;
try {
resultString = new String(value);
MessageDigest md = MessageDigest.getInstance("MD5");
resultString = byteArrayToHexString(md.digest(resultString.getBytes("UTF-8")));
} catch (Exception e) {
}
return resultString;
}
/**
* MD5加密后解密(一定要KL()再用KL()解密)
* MD5是不可逆,这里的加密解密,你可以看到是对MD5算法先加密后解密,而不是对MD5的解密
*
* @param value
* @return
*/
public static String MD5Decrypt(String value) {
char[] a = value.toCharArray();
for (int i = 0; i < a.length; i++) {
a[i] = (char) (a[i] ^ 't');
}
String k = new String(a);
return k;
}
// 可逆的加密算法
public static String KL(String inStr) {
// String s = new String(inStr);
char[] a = inStr.toCharArray();
for (int i = 0; i < a.length; i++) {
a[i] = (char) (a[i] ^ 't');
}
String s = new String(a);
return s;
}
public static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++) {
resultSb.append(byteToHexString(b[i]));
}
return resultSb.toString();
}
public static String byteToHexString(byte b) {
int n = b;
if (n < 0) {
n += 256;
}
int d1 = n / 16;
int d2 = n % 16;
return hexDigIts[d1] + hexDigIts[d2];
}
// 测试主函数
// public static void main(String args[]) {
// String s = new String("sa");
// System.out.println("原始:" + s);
// System.out.println("MD5后:" + MD5Encode(s));
// System.out.println("MD5后再加密:" + KL(MD5Encode(s)));
// System.out.println("解密为MD5后的:" + MD5Decrypt(KL(MD5Encode(s))));
// }
}
5. AESUtil.java类
package com.sumansoul.aesdemo.utils;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* AES最简单的加密
*/
public class AESUtil {
//算法
private static final String ALGORITHM = "AES";
/**
* 1.电码本模式(Electronic Codebook Book (ECB))不支持;
* 2.密码分组链接模式(Cipher Block Chaining (CBC))默认的加密算法;
* 3.计算器模式(Counter (CTR));
* 4.密码反馈模式(Cipher FeedBack (CFB));
* 5.输出反馈模式(Output FeedBack (OFB))。
*/
// 指定加密的算法、工作模式和填充方式
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
// 编码
private static final String ENCODING = "UTF-8";
// 密匙
private static final String KEY = "a70648d869329dab";
// 偏移量
private static final String OFFSET = "0102030405060708";
/**
* AES加密
*
* @param data
* @return
* @throws Exception
*/
public static String encrypt(String data) throws Exception {
// 初始化cipher
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
//转化成JAVA的密钥格式
SecretKeySpec skeySpec = new SecretKeySpec(KEY.getBytes("ASCII"), ALGORITHM);
//使用CBC模式,需要一个向量iv,可增加加密算法的强度
IvParameterSpec iv = new IvParameterSpec(OFFSET.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(data.getBytes(ENCODING));
//此处使用BASE64做转码。
String result = new BASE64Encoder().encode(encrypted);
return result;
}
/**
* AES解密
*
* @param data
* @return
* @throws Exception
*/
public static String decrypt(String data) throws Exception {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
SecretKeySpec skeySpec = new SecretKeySpec(KEY.getBytes("ASCII"), ALGORITHM);
//使用CBC模式,需要一个向量iv,可增加加密算法的强度
IvParameterSpec iv = new IvParameterSpec(OFFSET.getBytes());
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] buffer = new BASE64Decoder().decodeBuffer(data);
byte[] encrypted = cipher.doFinal(buffer);
//此处使用BASE64做转码。
String result = new String(encrypted, ENCODING);
return result;
}
}
二、其它基础类
1. BASE64Decoder.java类
package com.sumansoul.aesdemo.utils;
/*
2 * Copyright (c) 1995, 2000, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
import java.io.OutputStream;
import java.io.PushbackInputStream;
import java.io.PrintStream;
/**
* 32 * This class implements a BASE64 Character decoder as specified in RFC1521.
* 33 *
* 34 * This RFC is part of the MIME specification which is published by the
* 35 * Internet Engineering Task Force (IETF). Unlike some other encoding
* 36 * schemes there is nothing in this encoding that tells the decoder
* 37 * where a buffer starts or stops, so to use it you will need to isolate
* 38 * your encoded data into a single chunk and then feed them this decoder.
* 39 * The simplest way to do that is to read all of the encoded data into a
* 40 * string and then use:
* 41 *
* 42 * byte mydata[];
* 43 * BASE64Decoder base64 = new BASE64Decoder();
* 44 *
* 45 * mydata = base64.decodeBuffer(bufferString);
* 46 *
* 47 * This will decode the String in bufferString and give you an array
* 48 * of bytes in the array myData.
* 49 *
* 50 * On errors, this class throws a CEFormatException with the following detail
* 51 * strings:
* 52 *
* 53 * "BASE64Decoder: Not enough bytes for an atom."
* 54 *
* 55 *
* 56 * @author Chuck McManis
* 57 * @see CharacterEncoder
* 58 * @see BASE64Decoder
* 59
*/
public class BASE64Decoder extends CharacterDecoder {
/**
* This class has 4 bytes per atom
*/
protected int bytesPerAtom() {
return (4);
}
/**
* Any multiple of 4 will do, 72 might be common
*/
protected int bytesPerLine() {
return (72);
}
/**
* 74 * This character array provides the character to value map
* 75 * based on RFC1521.
* 76
*/
private final static char pem_array[] = {
// 0 1 2 3 4 5 6 7
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 1
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 2
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 3
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 4
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 5
'w', 'x', 'y', 'z', '0', '1', '2', '3', // 6
'4', '5', '6', '7', '8', '9', '+', '/' // 7
};
private final static byte pem_convert_array[] = new byte[256];
static {
for (int i = 0; i < 255; i++) {
pem_convert_array[i] = -1;
}
for (int i = 0; i < pem_array.length; i++) {
pem_convert_array[pem_array[i]] = (byte) i;
}
}
byte decode_buffer[] = new byte[4];
/**
* 103 * Decode one BASE64 atom into 1, 2, or 3 bytes of data.
* 104
*/
protected void decodeAtom(PushbackInputStream inStream, OutputStream outStream, int rem)
throws java.io.IOException {
int i;
byte a = -1, b = -1, c = -1, d = -1;
if (rem < 2) {
throw new CEFormatException("BASE64Decoder: Not enough bytes for an atom.");
}
do {
i = inStream.read();
if (i == -1) {
throw new CEStreamExhausted();
}
} while (i == '\n' || i == '\r');
decode_buffer[0] = (byte) i;
i = readFully(inStream, decode_buffer, 1, rem - 1);
if (i == -1) {
throw new CEStreamExhausted();
}
if (rem > 3 && decode_buffer[3] == '=') {
rem = 3;
}
if (rem > 2 && decode_buffer[2] == '=') {
rem = 2;
}
switch (rem) {
case 4:
d = pem_convert_array[decode_buffer[3] & 0xff];
// NOBREAK
case 3:
c = pem_convert_array[decode_buffer[2] & 0xff];
// NOBREAK
case 2:
b = pem_convert_array[decode_buffer[1] & 0xff];
a = pem_convert_array[decode_buffer[0] & 0xff];
break;
}
switch (rem) {
case 2:
outStream.write((byte) (((a << 2) & 0xfc) | ((b >>> 4) & 3)));
break;
case 3:
outStream.write((byte) (((a << 2) & 0xfc) | ((b >>> 4) & 3)));
outStream.write((byte) (((b << 4) & 0xf0) | ((c >>> 2) & 0xf)));
break;
case 4:
outStream.write((byte) (((a << 2) & 0xfc) | ((b >>> 4) & 3)));
outStream.write((byte) (((b << 4) & 0xf0) | ((c >>> 2) & 0xf)));
outStream.write((byte) (((c << 6) & 0xc0) | (d & 0x3f)));
break;
}
return;
}
}
2. BASE64Encoder.java类
package com.sumansoul.aesdemo.utils;
/*
2 * Copyright (c) 1995, 1997, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
import java.io.OutputStream;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.IOException;
/**
* This class implements a BASE64 Character encoder as specified in RFC1521.
* This RFC is part of the MIME specification as published by the Internet
* Engineering Task Force (IETF). Unlike some other encoding schemes there is
* nothing in this encoding that indicates where a buffer starts or ends.
*
* This means that the encoded text will simply start with the first line of
* encoded text and end with the last line of encoded text.
*
* @author Chuck McManis
* @see CharacterEncoder
* @see BASE64Decoder
*/
public class BASE64Encoder extends CharacterEncoder {
/**
* this class encodes three bytes per atom.
*/
protected int bytesPerAtom() {
return (3);
}
/**
* this class encodes 57 bytes per line. This results in a maximum of 57/3 *
* 4 or 76 characters per output line. Not counting the line termination.
*/
protected int bytesPerLine() {
return (57);
}
/**
* This array maps the characters to their 6 bit values
*/
private final static char pem_array[] =
{
// 0 1 2 3 4 5 6 7
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 1
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 2
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 3
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 4
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 5
'w', 'x', 'y', 'z', '0', '1', '2', '3', // 6
'4', '5', '6', '7', '8', '9', '+', '/' // 7
};
/**
* encodeAtom - Take three bytes of input and encode it as 4 printable
* characters. Note that if the length in len is less than three is encodes
* either one or two '=' signs to indicate padding characters.
*/
protected void encodeAtom(OutputStream outStream, byte data[], int offset,
int len) throws IOException {
byte a, b, c;
if (len == 1) {
a = data[offset];
b = 0;
c = 0;
outStream.write(pem_array[(a >>> 2) & 0x3F]);
outStream.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
outStream.write('=');
outStream.write('=');
} else if (len == 2) {
a = data[offset];
b = data[offset + 1];
c = 0;
outStream.write(pem_array[(a >>> 2) & 0x3F]);
outStream.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
outStream.write(pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
outStream.write('=');
} else {
a = data[offset];
b = data[offset + 1];
c = data[offset + 2];
outStream.write(pem_array[(a >>> 2) & 0x3F]);
outStream.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]);
outStream.write(pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]);
outStream.write(pem_array[c & 0x3F]);
}
}
}
3. CEFormatException.java类
package com.sumansoul.aesdemo.utils;
import java.io.IOException;
public class CEFormatException extends IOException
{
public CEFormatException(String s)
{
super(s);
}
}
4. CEStreamExhausted.java类
package com.sumansoul.aesdemo.utils;
import java.io.IOException;
public class CEStreamExhausted extends IOException
{
}
5. CharacterDecoder.java类
package com.sumansoul.aesdemo.utils;
/*
2 * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* 37 * This class defines the decoding half of character encoders. 38 * A
* character decoder is an algorithim for transforming 8 bit 39 * binary data
* that has been encoded into text by a character 40 * encoder, back into
* original binary form. 41 * 42 * The character encoders, in general, have been
* structured 43 * around a central theme that binary data can be encoded into
* 44 * text that has the form: 45 * 46 *
*
*
* 47 * [Buffer Prefix]
* 48 * [Line Prefix][encoded data atoms][Line Suffix]
* 49 * [Buffer Suffix]
* 50 *
*
*
* 51 * 52 * Of course in the simplest encoding schemes, the buffer has no 53 *
* distinct prefix of suffix, however all have some fixed relationship 54 *
* between the text in an 'atom' and the binary data itself. 55 * 56 * In the
* CharacterEncoder and CharacterDecoder classes, one complete 57 * chunk of
* data is referred to as a buffer. Encoded buffers 58 * are all text,
* and decoded buffers (sometimes just referred to as 59 * buffers) are binary
* octets. 60 * 61 * To create a custom decoder, you must, at a minimum, overide
* three 62 * abstract methods in this class. 63 *
*
* 64 *
* - bytesPerAtom which tells the decoder how many bytes to 65 * expect from
* decodeAtom 66 *
*
- decodeAtom which decodes the bytes sent to it as text. 67 *
*
- bytesPerLine which tells the encoder the maximum number of 68 * bytes per
* line. 69 *
*
* 70 * 71 * In general, the character decoders return error in the form of a 72
* * CEFormatException. The syntax of the detail string is 73 *
*
*
* 74 * DecoderClassName: Error message.
* 75 *
*
*
* 76 * 77 * Several useful decoders have already been written and are 78 *
* referenced in the See Also list below. 79 * 80 * @author Chuck McManis 81 * @see
* CEFormatException 82 * @see CharacterEncoder 83 * @see UCDecoder 84 * @see
* UUDecoder 85 * @see BASE64Decoder 86
*/
public abstract class CharacterDecoder {
/**
* Return the number of bytes per atom of decoding
*/
abstract protected int bytesPerAtom();
/**
* Return the maximum number of bytes that can be encoded per line
*/
abstract protected int bytesPerLine();
/**
* decode the beginning of the buffer, by default this is a NOP.
*/
protected void decodeBufferPrefix(PushbackInputStream aStream,
OutputStream bStream) throws IOException {
}
/**
* decode the buffer suffix, again by default it is a NOP.
*/
protected void decodeBufferSuffix(PushbackInputStream aStream,
OutputStream bStream) throws IOException {
}
/**
* 103 * This method should return, if it knows, the number of bytes 104 *
* that will be decoded. Many formats such as uuencoding provide 105 * this
* information. By default we return the maximum bytes that 106 * could have
* been encoded on the line. 107
*/
protected int decodeLinePrefix(PushbackInputStream aStream,
OutputStream bStream) throws IOException {
return (bytesPerLine());
}
/**
* 113 * This method post processes the line, if there are error detection
* 114 * or correction codes in a line, they are generally processed by 115
* * this method. The simplest version of this method looks for the 116 *
* (newline) character. 117
*/
protected void decodeLineSuffix(PushbackInputStream aStream,
OutputStream bStream) throws IOException {
}
/**
* 121 * This method does an actual decode. It takes the decoded bytes and
* 122 * writes them to the OutputStream. The integer l tells the 123
* * method how many bytes are required. This is always <= bytesPerAtom().
* 124
*/
protected void decodeAtom(PushbackInputStream aStream,
OutputStream bStream, int l) throws IOException {
throw new CEStreamExhausted();
}
/**
* 130 * This method works around the bizarre semantics of
* BufferedInputStream's 131 * read method. 132
*/
protected int readFully(InputStream in, byte buffer[], int offset, int len)
throws IOException {
for (int i = 0; i < len; i++) {
int q = in.read();
if (q == -1)
return ((i == 0) ? -1 : i);
buffer[i + offset] = (byte) q;
}
return len;
}
/**
* 145 * Decode the text from the InputStream and write the decoded 146 *
* octets to the OutputStream. This method runs until the stream 147 * is
* exhausted. 148 * @exception CEFormatException An error has occured while
* decoding 149 * @exception CEStreamExhausted The input stream is
* unexpectedly out of data 150
*/
public void decodeBuffer(InputStream aStream, OutputStream bStream)
throws IOException {
int i;
int totalBytes = 0;
PushbackInputStream ps = new PushbackInputStream(aStream);
decodeBufferPrefix(ps, bStream);
while (true) {
int length;
try {
length = decodeLinePrefix(ps, bStream);
for (i = 0; (i + bytesPerAtom()) < length; i += bytesPerAtom()) {
decodeAtom(ps, bStream, bytesPerAtom());
totalBytes += bytesPerAtom();
}
if ((i + bytesPerAtom()) == length) {
decodeAtom(ps, bStream, bytesPerAtom());
totalBytes += bytesPerAtom();
} else {
decodeAtom(ps, bStream, length - i);
totalBytes += (length - i);
}
decodeLineSuffix(ps, bStream);
} catch (CEStreamExhausted e) {
break;
}
}
decodeBufferSuffix(ps, bStream);
}
/**
* 182 * Alternate decode interface that takes a String containing the
* encoded 183 * buffer and returns a byte array containing the data. 184 * @exception
* CEFormatException An error has occured while decoding 185
*/
public byte decodeBuffer(String inputString)[]throws IOException {
byte inputBuffer[] = new byte[inputString.length()];
ByteArrayInputStream inStream;
ByteArrayOutputStream outStream;
inputString.getBytes(0, inputString.length(), inputBuffer, 0);
inStream = new ByteArrayInputStream(inputBuffer);
outStream = new ByteArrayOutputStream();
decodeBuffer(inStream, outStream);
return (outStream.toByteArray());
}
/**
* 199 * Decode the contents of the inputstream into a buffer. 200
*/
public byte decodeBuffer(InputStream in)[]throws IOException {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
decodeBuffer(in, outStream);
return (outStream.toByteArray());
}
/**
* 208 * Decode the contents of the String into a ByteBuffer. 209
*/
public ByteBuffer decodeBufferToByteBuffer(String inputString)
throws IOException {
return ByteBuffer.wrap(decodeBuffer(inputString));
}
/**
* 216 * Decode the contents of the inputStream into a ByteBuffer. 217
*/
public ByteBuffer decodeBufferToByteBuffer(InputStream in)
throws IOException {
return ByteBuffer.wrap(decodeBuffer(in));
}
}
6. CharacterEncoder.java类
package com.sumansoul.aesdemo.utils;
/*
2 * Copyright (c) 1995, 2005, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* 38 * This class defines the encoding half of character encoders. 39 * A
* character encoder is an algorithim for transforming 8 bit binary 40 * data
* into text (generally 7 bit ASCII or 8 bit ISO-Latin-1 text) 41 * for
* transmition over text channels such as e-mail and network news. 42 * 43 * The
* character encoders have been structured around a central theme 44 * that, in
* general, the encoded text has the form: 45 * 46 *
*
*
* 47 * [Buffer Prefix]
* 48 * [Line Prefix][encoded data atoms][Line Suffix]
* 49 * [Buffer Suffix]
* 50 *
*
*
* 51 * 52 * In the CharacterEncoder and CharacterDecoder classes, one complete
* 53 * chunk of data is referred to as a buffer. Encoded buffers 54 *
* are all text, and decoded buffers (sometimes just referred to as 55 *
* buffers) are binary octets. 56 * 57 * To create a custom encoder, you must,
* at a minimum, overide three 58 * abstract methods in this class. 59 *
*
* 60 *
* - bytesPerAtom which tells the encoder how many bytes to 61 * send to
* encodeAtom 62 *
*
- encodeAtom which encodes the bytes sent to it as text. 63 *
*
- bytesPerLine which tells the encoder the maximum number of 64 * bytes per
* line. 65 *
*
* 66 * 67 * Several useful encoders have already been written and are 68 *
* referenced in the See Also list below. 69 * 70 * @author Chuck McManis 71 * @see
* CharacterDecoder; 72 * @see UCEncoder 73 * @see UUEncoder 74 * @see
* BASE64Encoder 75
*/
public abstract class CharacterEncoder {
/**
* Stream that understands "printing"
*/
protected PrintStream pStream;
/**
* Return the number of bytes per atom of encoding
*/
abstract protected int bytesPerAtom();
/**
* Return the number of bytes that can be encoded per line
*/
abstract protected int bytesPerLine();
/**
* 88 * Encode the prefix for the entire buffer. By default is simply 89 *
* opens the PrintStream for use by the other functions. 90
*/
protected void encodeBufferPrefix(OutputStream aStream) throws IOException {
pStream = new PrintStream(aStream);
}
/**
* 96 * Encode the suffix for the entire buffer. 97
*/
protected void encodeBufferSuffix(OutputStream aStream) throws IOException {
}
/**
* 102 * Encode the prefix that starts every output line. 103
*/
protected void encodeLinePrefix(OutputStream aStream, int aLength)
throws IOException {
}
/**
* 109 * Encode the suffix that ends every output line. By default 110 *
* this method just prints a into the output stream. 111
*/
protected void encodeLineSuffix(OutputStream aStream) throws IOException {
pStream.println();
}
/**
* Encode one "atom" of information into characters.
*/
abstract protected void encodeAtom(OutputStream aStream, byte someBytes[],
int anOffset, int aLength) throws IOException;
/**
* 121 * This method works around the bizarre semantics of
* BufferedInputStream's 122 * read method. 123
*/
protected int readFully(InputStream in, byte buffer[])
throws IOException {
for (int i = 0; i < buffer.length; i++) {
int q = in.read();
if (q == -1)
return i;
buffer[i] = (byte) q;
}
return buffer.length;
}
/**
* 136 * Encode bytes from the input stream, and write them as text
* characters 137 * to the output stream. This method will run until it
* exhausts the 138 * input stream, but does not print the line suffix for a
* final 139 * line that is shorter than bytesPerLine(). 140
*/
public void encode(InputStream inStream, OutputStream outStream)
throws IOException {
int j;
int numBytes;
byte tmpbuffer[] = new byte[bytesPerLine()];
encodeBufferPrefix(outStream);
while (true) {
numBytes = readFully(inStream, tmpbuffer);
if (numBytes == 0) {
break;
}
encodeLinePrefix(outStream, numBytes);
for (j = 0; j < numBytes; j += bytesPerAtom()) {
if ((j + bytesPerAtom()) <= numBytes) {
encodeAtom(outStream, tmpbuffer, j, bytesPerAtom());
} else {
encodeAtom(outStream, tmpbuffer, j, (numBytes) - j);
}
}
if (numBytes < bytesPerLine()) {
break;
} else {
encodeLineSuffix(outStream);
}
}
encodeBufferSuffix(outStream);
}
/**
* 173 * Encode the buffer in aBuffer and write the encoded 174 *
* result to the OutputStream aStream. 175
*/
public void encode(byte aBuffer[], OutputStream aStream) throws IOException {
ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
encode(inStream, aStream);
}
/**
* 183 * A 'streamless' version of encode that simply takes a buffer of 184
* * bytes and returns a string containing the encoded buffer. 185
*/
public String encode(byte aBuffer[]) {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
String retVal = null;
try {
encode(inStream, outStream);
// explicit ascii->unicode conversion
retVal = outStream.toString("8859_1");
} catch (Exception IOException) {
// This should never happen.
throw new Error("CharacterEncoder.encode internal error");
}
return (retVal);
}
/**
* 202 * Return a byte array from the remaining bytes in this ByteBuffer.
* 203 *
*
* 204 * The ByteBuffer's position will be advanced to ByteBuffer's limit.
* 205 *
*
* 206 * To avoid an extra copy, the implementation will attempt to return
* the 207 * byte array backing the ByteBuffer. If this is not possible, a
* 208 * new byte array will be created. 209
*/
private byte[] getBytes(ByteBuffer bb) {
/*
* This should never return a BufferOverflowException, as we're 213 *
* careful to allocate just the right amount. 214
*/
byte[] buf = null;
/*
* 218 * If it has a usable backing byte buffer, use it. Use only 219 *
* if the array exactly represents the current ByteBuffer. 220
*/
if (bb.hasArray()) {
byte[] tmp = bb.array();
if ((tmp.length == bb.capacity()) && (tmp.length == bb.remaining())) {
buf = tmp;
bb.position(bb.limit());
}
}
if (buf == null) {
/*
* 232 * This class doesn't have a concept of encode(buf, len, off),
* 233 * so if we have a partial buffer, we must reallocate 234 *
* space. 235
*/
buf = new byte[bb.remaining()];
/*
* 239 * position() automatically updated 240
*/
bb.get(buf);
}
return buf;
}
/**
* 248 * Encode the aBuffer ByteBuffer and write the encoded 249 *
* result to the OutputStream aStream. 250 *
*
* 251 * The ByteBuffer's position will be advanced to ByteBuffer's limit.
* 252
*/
public void encode(ByteBuffer aBuffer, OutputStream aStream)
throws IOException {
byte[] buf = getBytes(aBuffer);
encode(buf, aStream);
}
/**
* 260 * A 'streamless' version of encode that simply takes a ByteBuffer 261
* * and returns a string containing the encoded buffer. 262 *
*
* 263 * The ByteBuffer's position will be advanced to ByteBuffer's limit.
* 264
*/
public String encode(ByteBuffer aBuffer) {
byte[] buf = getBytes(aBuffer);
return encode(buf);
}
/**
* 271 * Encode bytes from the input stream, and write them as text
* characters 272 * to the output stream. This method will run until it
* exhausts the 273 * input stream. It differs from encode in that it will
* add the 274 * line at the end of a final line that is shorter than
* bytesPerLine(). 275
*/
public void encodeBuffer(InputStream inStream, OutputStream outStream)
throws IOException {
int j;
int numBytes;
byte tmpbuffer[] = new byte[bytesPerLine()];
encodeBufferPrefix(outStream);
while (true) {
numBytes = readFully(inStream, tmpbuffer);
if (numBytes == 0) {
break;
}
encodeLinePrefix(outStream, numBytes);
for (j = 0; j < numBytes; j += bytesPerAtom()) {
if ((j + bytesPerAtom()) <= numBytes) {
encodeAtom(outStream, tmpbuffer, j, bytesPerAtom());
} else {
encodeAtom(outStream, tmpbuffer, j, (numBytes) - j);
}
}
encodeLineSuffix(outStream);
if (numBytes < bytesPerLine()) {
break;
}
}
encodeBufferSuffix(outStream);
}
/**
* 306 * Encode the buffer in aBuffer and write the encoded 307 *
* result to the OutputStream aStream. 308
*/
public void encodeBuffer(byte aBuffer[], OutputStream aStream)
throws IOException {
ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
encodeBuffer(inStream, aStream);
}
/**
* 316 * A 'streamless' version of encode that simply takes a buffer of 317
* * bytes and returns a string containing the encoded buffer. 318
*/
public String encodeBuffer(byte aBuffer[]) {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer);
try {
encodeBuffer(inStream, outStream);
} catch (Exception IOException) {
// This should never happen.
throw new Error("CharacterEncoder.encodeBuffer internal error");
}
return (outStream.toString());
}
/**
* 332 * Encode the aBuffer ByteBuffer and write the encoded 333 *
* result to the OutputStream aStream. 334 *
*
* 335 * The ByteBuffer's position will be advanced to ByteBuffer's limit.
* 336
*/
public void encodeBuffer(ByteBuffer aBuffer, OutputStream aStream)
throws IOException {
byte[] buf = getBytes(aBuffer);
encodeBuffer(buf, aStream);
}
/**
* 344 * A 'streamless' version of encode that simply takes a ByteBuffer 345
* * and returns a string containing the encoded buffer. 346 *
*
* 347 * The ByteBuffer's position will be advanced to ByteBuffer's limit.
* 348
*/
public String encodeBuffer(ByteBuffer aBuffer) {
byte[] buf = getBytes(aBuffer);
return encodeBuffer(buf);
}
}