加密系列DES加密和解密算法详解代码⽰例
算法简介
对称加密也就是密钥加密。对称加密和解密使⽤同⼀个密钥:
加密时,我们⽤这个密钥初始化密码算法,密码算法对经过它的数据进⾏加密;
解密时,密码算法⽤同⼀个密钥初始化,密码算法对经过它的数据进⾏解密。
加密的强度依赖于密钥的长度。⼀般的对称密钥长度在40-128位之间,有些算法可能更长。
建议使⽤128位以上的对称加密算法,如:DESede(TripleDES)、Blowfish、AES。
对称加密⽐不对称加密(如公钥加密)要快的多,⽐较适合于⼤量数据加/解密的情况下(如⽂件加密)。
算法详解
Cipher cip = Instance(“DES/ECB/NoPadding”);
参数是要使⽤的算法,共分为三段(/分隔)。
第⼀段是算法名字
第⼆段是算法使⽤的模式
模式规定了 Cipher 如何应⽤加密算法。改变模式可以允许⼀个块加密程序变为流加密程序。
分组加密每次加密⼀个数据组,这个组的位数可以是随意的,⼀般是64或128位;
流加密每次可以加密或解密⼀个字节的数据,使其更适合⽹络通信等。
常⽤的模式:
ECB(电码本):最简单的模式,同样的明⽂总是加密成相同的密⽂分组;
CBC(密码分组链接):同样的明⽂分组不⼀定加密成同样的密⽂块;
CFB(密码反馈):⼯作⽅式与CBC类似,但它可执⾏更⼩的数据块,典型的有8位。也需要⼀个IV;
OFB(输出反馈):在传输中能给数据提供更好的保护,防⽌数据丢失,其他与CFB类似。密⽂中⼀位出错,也只造成明⽂中的⼀位出错。其他⽅式会造成整个块丢失。也需要⼀个IV。
CBC使⽤前⼀个分组的信息加密当前的分组,这个⽅法存在的问题是相同的信息仍旧加密成相同的密⽂,因为所有的分组是同时变成密⽂分组。为了解决这个问题需要⼀个IV(初始化向量),IV仅仅是⼀个初始化加密程序的随机数,它⽆需秘密保存,但对每⼀个信息来说它都是不同的。通过这种⽅式,既使有两条相同的信息,只要它们的IV不同,那么它们加密后的密⽂也是不同的。所以⼀个初始化向量就象是⼝令加密中的盐。
第三段是填充符
⼤多数算法⽀持两种填充符:
1. No padding 即没有填充,这就要求加密以⼀个完整的块结束,⽽没有多余的数据;
2. RKCS#5 padding ⼯作⽅式为:⼀个未被填满的字节被赋予⼀个指定的数据,这个数值的⼤⼩就是块未被写满的字节数。
例如,⼀个8字节的块,其中仅有3个字节写满了数据,那么就需要对5个节字填充,⽽这5个字节都被赋予数值’5’,这是因为有5个字节需要填充。如果数据长度正好为8字节的倍数,那么就需要在数据结尾处加⼀个完整的填序块(既8个为’8’的字节)。解密后,这个填充块必须被移除。
代码⽰例
DES/ECB/NoPadding
import java.security.Key;
import java.security.SecureRandom;
pto.Cipher;
pto.SecretKey;
pto.SecretKeyFactory;
pto.spec.DESKeySpec;
import dec.binary.Base64;
/**
* DES加密解密算法
*
* @author peipei3514
* @date 2017-8-11 上午10:12:50
*/
public class DESUtil {
/** 算法名称 */
public static final String KEY_ALGORITHM ="DES";
/** 算法名称/加密模式/填充⽅式 */
public static final String CIPHER_ALGORITHM ="DES/ECB/NoPadding";
/** 字符编码:字符串转字节或字节转字符串时⼀定要加上编码,否则可能出现乱码*/
private final static String ENCODE ="UTF-8";
/**
* 加解密密钥
*
* Creates a DESKeySpec object using the first 8 bytes in key as the key
* material for the DES key. The bytes that constitute the DES key are those
* between key[0] and key[7] inclusive.
*
* 使⽤前8个字节(bytes)作为DES密钥的关键材料,创建⼀个DESKeySpec对象。构成DES密钥的字节是键[0]和键[7]之间的字节。 */
private final static String DEFAULT_KEY ="A1B2C3D4E5F60708";
/** 获取秘钥对象 */
private static SecretKey keyGenerator(String keyStr)throws Exception {
byte input[]=HexStringToBytes(keyStr);
// 从原始密钥数据创建DESKeySpec对象
DESKeySpec desKey =new DESKeySpec(input);
// 创建⼀个密钥⼯⼚,然后⽤它把DESKeySpec转换成SecretKey对象
SecretKeyFactory keyFactory = Instance(KEY_ALGORITHM);
SecretKey securekey = ateSecret(desKey);
return securekey;
}
private static int parse(char c){
if(c >='a')
return(c -'a'+10)&0x0f;
if(c >='A')
return(c -'A'+10)&0x0f;
return(c -'0')&0x0f;
}
/** 从⼗六进制字符串到字节(⼆进制 )数组转换 */
private static byte[]HexStringToBytes(String hexstr){
byte[] results =new byte[hexstr.length()/2];
for(int i =0; i < results.length; i++){
char c0 = hexstr.charAt(i *2+0);
char c1 = hexstr.charAt(i *2+1);
results[i]=(byte)((parse(c0)<<4)|parse(c1));
}
}
return results;
}
/** 加密数据 */
public static String encrypt(String data)throws Exception {
// 获取秘钥对象
Key deskey =keyGenerator(DEFAULT_KEY);
// 实例化Cipher对象,它⽤于完成实际的加密操作
Cipher cipher = Instance(CIPHER_ALGORITHM);
// ⽣成⼀个可信任的随机数源
java源代码加密SecureRandom random =new SecureRandom();
/
/ ⽤密钥初始化Cipher对象,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, deskey, random);
// 执⾏加密操作
byte[] results = cipher.Bytes(ENCODE));
// 执⾏加密操作。加密后的结果通常都会⽤Base64编码进⾏传输
deBase64String(results);
}
/** 解密数据 */
public static String decrypt(String data)throws Exception {
// 获取秘钥对象
Key deskey =keyGenerator(DEFAULT_KEY);
/
/ 实例化Cipher对象,它⽤于完成实际的解密操作
Cipher cipher = Instance(CIPHER_ALGORITHM);
// 初始化Cipher对象,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, deskey);
// Base64解码
byte[] results = Base64.decodeBase64(data);
// 执⾏解密操作
results = cipher.doFinal(results);
// 变成字符串
return new String(results, ENCODE);
}
public static void main(String[] args)throws Exception {
String source ="12345678";
System.out.println("原⽂: "+ source);
String encryptData =encrypt(source);
System.out.println("加密后: "+ encryptData);
String decryptData =decrypt(encryptData);
System.out.println("解密后: "+ decryptData);
}
}
这种加密⽅式有两种限制:
密钥必须是16位的;
待加密内容的长度必须是16的倍数。
如果不是16的倍数,就会出如下异常:
at pto.provider.SunJCE_f.b(DashoA13*..)
at pto.provider.SunJCE_f.b(DashoA13*..)
at pto.ineDoFinal(DashoA13*..) pto.Cipher.doFinal(DashoA13*..)
要解决如上异常,可以通过补全传⼊加密内容等⽅式进⾏避免。
DES/CBC/PKCS5Padding
import java.security.Key;
pto.Cipher;
pto.SecretKey;
pto.SecretKeyFactory;
pto.spec.DESKeySpec;
pto.spec.IvParameterSpec;
import dec.binary.Base64;
/**
* DES加密解密算法
*
* @author peipei3514
* @date 2017-8-11 上午10:12:50
*/
public class DESUtil {
/** 算法名称 */
public static final String KEY_ALGORITHM ="DES";
/** 算法名称/加密模式/填充⽅式 */
public static final String CIPHER_ALGORITHM ="DES/CBC/PKCS5Padding";
/** 字符编码:字符串转字节或字节转字符串时⼀定要加上编码,否则可能出现乱码*/
private final static String ENCODE ="UTF-8";
/**
* 加解密密钥<br/><br/>
*
* Creates a DESKeySpec object using the first 8 bytes in key as the key
* material for the DES key. <br/>The bytes that constitute the DES key are those
* between key[0] and key[7] inclusive.<br/><br/>
*
* 使⽤前8个字节(bytes)作为DES密钥的关键材料,创建⼀个DESKeySpec对象。构成DES密钥的字节是键[0]和键[7]之间的字节。 */
private final static String DEFAULT_KEY ="A1B2C3D4E5F60708";
/** Wrong IV length: must be 8 bytes long */
private static String DES_IV ="JM23456*";
/** 获取秘钥对象 */
private static SecretKey keyGenerator(String keyStr)throws Exception {
byte input[]=HexStringToBytes(keyStr);
// 从原始密钥数据创建DESKeySpec对象
DESKeySpec desKey =new DESKeySpec(input);
// 创建⼀个密钥⼯⼚,然后⽤它把DESKeySpec转换成SecretKey对象
SecretKeyFactory keyFactory = Instance(KEY_ALGORITHM);
SecretKey securekey = ateSecret(desKey);
return securekey;
}
private static int parse(char c){
if(c >='a')
return(c -'a'+10)&0x0f;
if(c >='A')
return(c -'A'+10)&0x0f;
return(c -'0')&0x0f;
}
/** 从⼗六进制字符串到字节(⼆进制 )数组转换 */
private static byte[]HexStringToBytes(String hexstr){
byte[] results =new byte[hexstr.length()/2];
for(int i =0; i < results.length; i++){
char c0 = hexstr.charAt(i *2+0);
char c0 = hexstr.charAt(i *2+0);
char c1 = hexstr.charAt(i *2+1);
results[i]=(byte)((parse(c0)<<4)|parse(c1));
}
return results;
}
/** 加密数据 */
public static String encrypt(String data)throws Exception {
// 获取秘钥对象
Key deskey =keyGenerator(DEFAULT_KEY);
// 实例化Cipher对象,它⽤于完成实际的加密操作
Cipher cipher = Instance(CIPHER_ALGORITHM);
// ⽣成初始化向量
IvParameterSpec iv =new IvParameterSpec(Bytes("UTF-8")); // ⽤密钥初始化Cipher对象,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, deskey, iv);
// 执⾏加密操作
byte[] results = cipher.Bytes(ENCODE));
// 执⾏加密操作。加密后的结果通常都会⽤Base64编码进⾏传输
deBase64String(results);
}
/** 解密数据 */
public static String decrypt(String data)throws Exception {
// 获取秘钥对象
Key deskey =keyGenerator(DEFAULT_KEY);
// 实例化Cipher对象,它⽤于完成实际的解密操作
Cipher cipher = Instance(CIPHER_ALGORITHM);
/
/ ⽣成初始化向量
IvParameterSpec iv =new IvParameterSpec(Bytes("UTF-8")); // 初始化Cipher对象,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, deskey, iv);
// Base64解码
byte[] results = Base64.decodeBase64(data);
// 执⾏解密操作
results = cipher.doFinal(results);
// 变成字符串
return new String(results, ENCODE);
}
public static void main(String[] args)throws Exception {
String source ="123456";
System.out.println("原⽂: "+ source);
String encryptData =encrypt(source);
System.out.println("加密后: "+ encryptData);
String decryptData =decrypt(encryptData);
System.out.println("解密后: "+ decryptData);
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论