Java实现AES的128、256位密钥加解密算法并解决
Illegalkeysizeord。。。
Android开发中为了代码在传输过程中的安全,会对代码进⾏⼀些加密,Android中常⽤的加密⽅式,细数有⼀下⼏种:
1、DSA加密
2、RSA加密
3、DES加密
4、AES加密
5、MD5算法
6、Base64加密算法
7、异或加密算法
AES、DES为对称加密,RSA、DSA为⾮对称加密。今天只详细讲解AES,其他的后期再补充。今天主要是实现AES的128、256位密钥加解密 并 解决Illegal key size or default parameters问题。在AES之前,DES加密⽐较流⾏,其密钥较短、加密处理简单,加密速度快,但后来有⼈通过⽹络联合运算的⽅式短时间之内破解了DES的加密数据,使之成为了⼀种不安全的加密⽅式,新版本的DES的加密效率有太低;相对来说AES使⽤的密钥更长(分128、192、256位),内部有更简洁精确的数学算法。
⼀、128位密钥的加解密算法
因cipher.doFinal(byteContent)加密后的数据是个byte[]类型的数组,⽽有些时候我们需要的是个String类型的字符创,所以对于加密后的结果进⾏处理时,⽤了两种⽅式做了处理:⼀种是将加密结果转化为⼗六进制的数据再做处理;⼀种是⽤Base64做完转换功能再做处理。那么有⼈会问了,为什么不直接将byte[]直接转换为String呢,请接着往下看,代码注释中和最后总结中都有答案。
在这⼉,先做⼀下前期准备:
1、如果想了解所谓的:“加密服务提供者”——即:Provider,“所请求算法的名称”——即:algorithm,“转换名称”——即:
transformation(如:AES/ECB/PKCS7Padding)等这样的字眼字眼的详细内容,!
2、如果对加密后的数据进⾏转码处理时选择了⽤Base64加密(这个下⽂会说的更详细⼀些),需要导⼊个jar包(如果使⽤Eclipse
开发,需要下载并导⼊jar包,如果是Android Studio开发,则添加依赖就⾏):
其下载地址为:
(⽅法⼀:将加密结果转化为⼗六进制的数据再做处理)
加解密的代码⾥⾯需要⽤到⼏个类(接⼝),我已尽可能做了详细的注释,如果想进⼀步了解其内容,可以看已下API:
⽤到的重要API地址:
1、加密:
/**
* 加密
*
* @param content 要加密的内容
* @param key ⽤来⽣成128位密钥的密码
* @return
*/
public static String encrypt(String content, String key) {
try {
/**
* KeyGenerator : 是个类,此类提供(对称)密钥⽣成器的功能。在⽣成密钥后,可以重复使⽤同⼀个 KeyGenerator 对象来⽣成更多的密钥。
* 使⽤其中的getInstance(String algorithm)⽅法进⾏构造对象;
* algorithm :所请求密钥算法的标准名称。
*/
KeyGenerator kgen = Instance("AES");
/**
* Random : 此类的实例⽤于⽣成伪随机数流。
* SecureRandom : 是Random的直接⼦类。此类提供强加密随机数⽣成器 (RNG)。还必须⽣成⾮确定性输出(⽽)。
* SecureRandom(byte[] seed) : 构造⼀个实现默认随机数算法的安全随机数⽣成器 (RNG)。使⽤指定的种⼦字节设置种⼦。
* init(int keysize, SecureRandom random) : 使⽤⽤户提供的随机源初始化此密钥⽣成器,使其具有确定的密钥⼤⼩。
* keysize : 密钥⼤⼩。这是特定于算法的⼀种规格,是以位数为单位指定的。
* random : 此密钥⽣成器的随机源
*/
kgen.init(128, new Bytes()));
/**
* java.security包中有接⼝ Key,SecretKey是Key的⼦接⼝,SecretKeySpec是SecretKey的实现类。
* Key : Key 是所有密钥的顶层接⼝。它定义了供所有密钥对象共享的功能。
* SecretKey : 此接⼝不包含⽅法或常量。其唯⼀⽬的是分组秘密密钥(并为其提供类型安全)。
* SecretKeySpec : 可以使⽤此类来根据⼀个字节数组构造⼀个 SecretKey
*
* generateKey() : ⽣成⼀个密钥。
*/
SecretKey secretKey = ateKey();
/**
* getEncoded() : 是Key接⼝中的⽅法;返回基本编码格式的密钥,如果此密钥不⽀持编码,则返回 null。
*/
byte[] enCodeFormat = Encoded();
/**
* SecretKeySpec(byte[] key, String algorithm) : SecretKeySpec的构造⽅法之⼀,根据给定的字节数组构造⼀个密钥。
* key : 密钥的密钥内容。复制该数组的内容来防⽌后续修改。
* algorithm : 与给定的密钥内容相关联的密钥算法的名称。
*/
SecretKeySpec keySpec = new SecretKeySpec(enCodeFormat, "AES");
/**
* Cipher : 该类为加密和解密提供加密密码功能。
* getInstance(String transformation) : 通过指定转换模式的⽅式获得实例化对象。
* transformation : 转换的名称,例如:AES 或者 DES/CBC/PKCS5Padding。转换始终包括加密算法的名称(例如,DES),后⾯可能跟有⼀个反馈模式和填充 */
Cipher cipher = Instance("AES");
byte[] byteContent = Bytes("utf-8");
/**
* init(int opmode, Key key) : ⽤密钥初始化此 cipher。为以下 4 种操作之⼀初始化该 cipher:加密、解密、密钥包装或密钥打开,这取决于 opmode 的值。
* opmode : 此 cipher 的操作模式(其为如下之⼀:ENCRYPT_MODE、DECRYPT_MODE、WRAP_MODE 或 UNWRAP_MODE)
* key : 密钥
*/
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
/**
* doFinal(byte[] input) : 按单部分操作加密或解密数据,或者结束⼀个多部分操作。数据将被加密或解密(具体取决于此 Cipher 的初始化模式)。
* input : 输⼊的数组,即:要加密或解密的内容
*/
byte[] result = cipher.doFinal(byteContent);
/**
* parseByte2HexStr(String result) : ⾃定义的⼀套将⼆进制数据转换为⼗六进制的数据的⽅法;
*
* !注:在这⼉,加密后的byte数组是不能强制转换成字符串的(即:new String(result)); 换⾔之,字符串和byte数组在这种情况下不是互逆的。
* 处理⽅式有两种:
* 1.将result转化为⼗六进制的数据再做处理(需要⾃⼰写⼀个转换⽅法);
* 2.将result进⾏Base64(也可以⽤ Base64)再次加密在进⾏强制转换(不需要⾃⼰写⽅法,省事⼉)。
*/
return parseByte2HexStr(result);
// return new de(result));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
2、解密
其中⽤到的类和⽅法与加密的都⼀样,可以参考加密的注释。
/**
* 解密
* @param content 要解密的内容
* @param key ⽤来⽣成128位密钥的密码
* @return
*/
public static String decrypt(String content, String key) {
try {
KeyGenerator kgen = Instance("AES");
kgen.init(128, new Bytes()));
SecretKey secretKey = ateKey();
byte[] enCodeFormat = Encoded();
SecretKeySpec keySpec = new SecretKeySpec(enCodeFormat, "AES"); Cipher cipher = Instance("AES");// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, keySpec);// 初始化
byte[] result = cipher.doFinal(parseHexStr2Byte(content));
// byte[] result = cipher.doFinal(Base64.Bytes()));
return new String(result);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
3、字符串/字节数组 ——> ⼗六进制数字
* 将⼆进制数组 ——> ⼗六进制数字
* @param buf 要转换的数组
* @return
*/
private static String parseByte2HexStr(byte buf[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
/**
* Integer : 该类在对象中包装了⼀个基本类型 int 的值(即:Integer是int的包装类)。该类提供了多个⽅法,能在 int 类型和 String 类型之间互相转换,还提供 * toHexString(int i) : 以⼗六进制的⽆符号整数形式返回⼀个整数参数的字符串表⽰形式。
* i : 要转换成字符串的整数。
* buf[i] & 0xFF : 将字节数组中每个字节拆解成2位16进制整数(原因是:每个字节(即:byte)占8位(即:bit),16进制的基数是由4位组成)
*/
String hex = HexString(buf[i] & 0xFF);
if (hex.length() == 1) {
/**
* 因为toHexString(int i)将需要转换的i值转换为⼗六进制(基数 16)的⽆前导 0 的 ASCII 数字字符串,所以要重新加上
*/
hex = '0' + hex;
}
/**
* toUpperCase() : 使⽤默认语⾔环境的规则将此 String 中的所有字符都转换为⼤写。
*/
sb.UpperCase());
}
String();
}
4、⼗六进制数字 ——> 字符串/字节数组
* 将⼗六进制数字 ——> ⼆进制数组
* @param hexStr 要转换的数组
* @return
java源代码加密*/
public static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1)
return null;
byte[] result = new byte[hexStr.length()/2];
/**
* hexStr.length()/2 : 将每2位16进制整数组装成⼀个字节(原因是:每个字节(即:byte)占8位(即:bit),16进制的基数是由4位组成)
*/
for (int i = 0;i< hexStr.length()/2; i++) {
/**
* parseInt(String s, int radix) : 使⽤第⼆个参数指定的基数,将字符串参数解析为有符号的整数。
* s : 包含要分析的整数表⽰形式的 String。
* radix : 分析 s 时使⽤的基数。
* 如果发⽣以下任意⼀种情况,则抛出⼀个 NumberFormatException 类型的异常:
* 1、第⼀个参数为 null 或⼀个长度为零的字符串。
* 2、基数⼩于 Character.MIN_RADIX 或者⼤于 Character.MAX_RADIX。
* 3、假如字符串的长度超过 1,那么除了第⼀个字符可以是减号 '-' ('u002D’) 外,字符串中的任何字符都不是指定基数的数字(即:第⼆个参数radix)。
* 4、字符串表⽰的值不是 int 类型的值。
*/
int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
/**
* String : 该类代表字符串。Java 程序中的所有字符串字⾯值(如 "abc" )都作为此类的实例来实现。
* substring(int beginIndex, int endIndex) : 返回⼀个新字符串,它是此字符串的⼀个⼦字符串。该⼦字符串从指定的 beginIndex 处开始,⼀直到索引 endIn * beginIndex : 开始处的索引(包括)。
* endIndex : 结束处的索引(不包括)。
*/
int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
5、测试结果:
public static void main(String[] args) {
// 需要加密的内容
String content = "请叫我dafeige";
// ⽣成密钥需要的密码值
String key = "dafeige";
System.out.println("content: " + content + "\nkey: " + key);
// 内容加密后的值
String encode = encrypt(content, key);
/
/ 被加密的内容解密后的值
String decode = decrypt(encode, key);
System.out.println("encode: " + encode + "\ndecode: " + decode);
}
输出的结果:
content: 请叫我dafeige
key: dafeige
encode: B49019AC97E24981989A03CFC4B3DF4B2B16B197404F3EA7FC92286E69D4CAE2
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论