团队冲刺DAY4
DES算法
算法概要
在DES.java当中创立两个方法分别用作加密和解密
通过
`public static byte[] encrypt(byte[] data, String sKey)
创建方法进行加密
通过
public static byte[] decrypt(byte[] src, String sKey) throws Exception
创建方法来进行解密。
加密过程中首先通过将一个String类型的字符串中包含的字符转换成byte类型并且用
keyinit 命令为每个用户建立一个 skey 客户并存入一个byte[]数组中
即: byte[] key = sKey.getBytes();
来初始化数组。
通过类IvParameterSpec
指定了个初始化向量,将Key带入新建立的IvParameterSpec
对象当中。再通过DESKeySpec
指定des键
即
IvParameterSpec iv = new IvParameterSpec(key);
DESKeySpec desKey = new DESKeySpec(key);
创建一个keyFactory,然后把DESKeySpec转换成securekey
SecretKeyFactory keyFactory=SecretKeyFactory.getInstance("DES");
SecretKey securekey=keyFactory.generateSecret(desKey);
Cipher对象通过参数DESede/CBC/PKCS5Padding
实现DES的实际对称加密操作。
参数也可以用DESede
代替,它与DESede/ECB/PKCS5Padding
等价。
这个参数分为三段。第一段是加密算法的名称 ,第二段是分组加密的模式,第三段是指最后一个分组的填充方式。
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
补充一点,虽然DES的有效密钥长度是56位,但要求密钥长度是64位(8字节)。3DES则要求24字节。
用密匙初始化Cipher对象,获取数据并加密,正式执行加密操作。Cipher类为加密和解密提供密码功能,它需要通过getInstance()工厂方法来实例化对象,之前已经将对象实例化完成此时只需要获取数据并加密。
cipher.init(Cipher.ENCRYPT_MODE, securekey, iv);
return cipher.doFinal(data);
如果系统出现错误通过e.printStackTrace()
命令行打印异常信息在程序中出错的位置及原因
这就是DES加密部分的算法概要。
加密代码
public static byte[] encrypt(byte[] data, String sKey) {
try {
byte[] key = sKey.getBytes();
// 初始化向量
IvParameterSpec iv = new IvParameterSpec(key);
DESKeySpec desKey = new DESKeySpec(key);
// 创建一个密匙工厂,然后用它把DESKeySpec转换成securekey
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey securekey = keyFactory.generateSecret(desKey);
// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
// 用密匙初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, securekey, iv);
// 现在,获取数据并加密
// 正式执行加密操作
return cipher.doFinal(data);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
解密与加密在结构上大体相同便不再做过多赘述。
解密代码:
public static byte[] decrypt(byte[] src, String sKey) throws Exception {
byte[] key = sKey.getBytes();
// 初始化向量
IvParameterSpec iv = new IvParameterSpec(key);
// 创建一个DESKeySpec对象
DESKeySpec desKey = new DESKeySpec(key);
// 创建一个密匙工厂
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
// 将DESKeySpec对象转换成SecretKey对象
SecretKey securekey = keyFactory.generateSecret(desKey);
// Cipher对象实际完成解密操作
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
// 用密匙初始化Cipher对象
cipher.init(Cipher.DECRYPT_MODE, securekey, iv);
// 真正开始解密操作
return cipher.doFinal(src);
}
在DES加解密过程当中需要进行十六轮迭代置换操作,初始置换过程前需要将二进制转换成16进制
关键代码解析:
首先StringBuffer sb = new StringBuffer();
初始化一个新的StringBuffer对象
之后通过for循环进行转换
String hex = Integer.toHexString(buf[i] & 0xFF);
这里b[ i ] & 0xFF将一个byte和 0xFF进行了与运算,然后使用Integer.toHexString取得了十六进制字符串
补充:如果直接 Integer.toHexString(b[ i ]);,
将byte强转为int可以吗?
答案是不行
因为
1.byte的大小为8bits而int的大小为32bits
2.java的二进制采用的是补码形式
转换代码:
public static String parseByte2HexStr(byte buf[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
将十六进制转换成二进制:
关键代码解析:
int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
result[i] = (byte) (high * 16 + low);
很常见的转二进制代码
转换代码:
public static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1) return null;
byte[] result = new byte[hexStr.length() / 2];
for (int i = 0; i < hexStr.length() / 2; i++) {
int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
}
总代码链接:
DEStest.java
Destest是用来测试Des加密算法的程序。
通过将待加密内容加解密来进行测试
代码:
import java.nio.charset.Charset;
public class Destest {
private static final String SKEY = "abcdefgh";
private static final Charset CHARSET = Charset.forName("gb2312");
public static void main(String[] args) {
// 待加密内容
String str = "nihao";
String encryptResult = DesUtil.encrypt(str, CHARSET, SKEY);
System.out.println(encryptResult);
// 直接将如上内容解密
String decryResult = "";
try {
decryResult = DesUtil.decrypt(encryptResult, CHARSET, SKEY);
} catch (Exception e1) {
e1.printStackTrace();
}
System.out.println(decryResult);
}
}
娄老师在他的博客之中引用过林语堂先生在《 深入浅出MFC 2e(电子版)》的一句话
只用一样东西,不明白它的道理,实在不高明
本次我们团队项目的题目是客户端-服务器安全信息传递系统在这之中我们的基本要求中需要对所有通信内容用分组密码进行加密。在之前密码学的课上袁甄老师给我们讲了关于DES算法的计算原理,但是却没有正真在代码上实现它,这次项目让我们在实践中学习了密码学的加密算法。