黑马程序员技术交流社区
标题:
关于加密
[打印本页]
作者:
低调的奢华
时间:
2013-11-16 18:45
标题:
关于加密
本帖最后由 低调的奢华 于 2013-11-16 18:45 编辑
常见加密算法简介
本文介绍常见的算法(MD5/SHA,DSA,RSA,DES)的应用场景,以及在java上的使用方法.
1) MD5/SHA
MessageDigest是一个数据的数字指纹.即对一个任意长度的数据进行计算,产生一个唯一指纹号.
MessageDigest的特性:
A) 两个不同的数据,难以生成相同的指纹号
B) 对于指定的指纹号,难以逆向计算出原始数据
代表:MD5/SHA
Java实现:
MD5:
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(Constant.DATA.getBytes());
byte[] result = md.digest();
复制代码
SHA:
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(Constant.DATA.getBytes());
byte[] result = md.digest();
复制代码
2) DES
单密钥算法,是信息的发送方采用密钥A进行数据加密,信息的接收方采用同一个密钥A进行数据解密.
单密钥算法是一个对称算法.
缺点:由于采用同一个密钥进行加密解密,在多用户的情况下,密钥保管的安全性是一个问题.
代表:DES
Java实现:
首先,需要生成一个密钥,这边的做法,是把生成的密钥,保存到某个文件中.
KeyGenerator gen = KeyGenerator.getInstance("DES");
Key key = gen.generateKey();
File keyFile = new File(Constant.CRYPT_KEY_FILE);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(keyFile));
out.writeObject(key);
out.close();
复制代码
在生成key的时候,可以通过SecureRandom产生一个可信任的随机数源
KeyGenerator gen = KeyGenerator.getInstance("DES");
gen.init(new SecureRandom(seed));
Key key = gen.generateKey();
复制代码
加密:
Key key = gen.getKey(Constant.CRYPT_KEY_FILE);//从文件中得到密钥
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, key); //指定是加密模式
cipher.update(Constant.DATA.getBytes());
byte[] result = cipher.doFinal();
复制代码
解密:
由于DES是一个对称算法,所以解密代码跟加密代码几乎一致
key = gen.getKey(Constant.CRYPT_KEY_FILE);
cipher.init(Cipher.DECRYPT_MODE, key); //指定是解密模式
cipher.update(result);
byte[] data = cipher.doFinal();
复制代码
由于采用了同一个密钥(key),所以两端代码中
Constant.DATA.getBytes()和 data 的值是一致的.
3) DSA
所谓数字签名是指发送方从发送报文中抽取特征数据(称为数字指纹或摘要),然后用发送方的私钥对数字指纹使用加密算法进行算法操作,接受方使用发送方已经公开的公钥解密并验证报文.
数字签名用户验证发送方身份或者发送方信息的完整性
代表:DSA
Java实现:
同样,首先需要生成一个公钥和私钥,我们也把它保存到相应的文件中
KeyPairGenerator gen = KeyPairGenerator.getInstance(“DSA”);
//以指定的长度初始化KeyPairGenerator对象,如果没有初始化系统以1024长度默认设置
//参数:keysize 算法位长.其范围必须在 512 到 1024 之间,且必须为 64 的倍数
gen.initialize(1024);
KeyPair pair = gen.generateKeyPair();
File pubkeyFile = new File(Constant.PUB_KEY_FILE);
File prikeyFile = new File(Constant.PRI_KEY_FILE);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(pubkeyFile));
out.writeObject(pair.getPublic());
out.close();
out = new ObjectOutputStream(new FileOutputStream(prikeyFile));
out.writeObject(pair.getPrivate());
out.close();
复制代码
签名:
PrivateKey prikey = (PrivateKey) gen.getKey(Constant.PRI_KEY_FILE); //从文件得到私钥
// 用私钥对数据签名
Signature signature = Signature.getInstance("DSA");
signature.initSign(prikey);
signature.update(Constant.DATA.getBytes());
byte[] bytes = signature.sign();
复制代码
把原始数据和签名发送给接收方
验证:
用公钥对原始数据和签名进行验证
PublicKey pubkey = (PublicKey) gen.getKey(Constant.PUB_KEY_FILE);//从文件得到公钥
Signature check = Signature.getInstance("DSA");
check.initVerify(pubkey);
check.update(Constant.DATA.getBytes());
//验证数据的完整性
if (check.verify(bytes)) {
System.out.println("OK");
} else {
System.out.println("ERROR");
}
复制代码
4) RSA
公钥密码体制:为了解决单密钥保管安全性的问题,提供了公钥密码体制的概念.在公钥体制中,加密密钥不同于解密密钥,加密密钥公之于众,谁都可以使用;解密密钥只有解密人自己知道。它们分别称为公开密钥(Public key)和秘密密钥(Private key)。
代表:RSA
Java实现:
同样,需要生成公钥和私钥,并且保存到相应的文件中
KeyPairGenerator gen = KeyPairGenerator.getInstance(“RSA”);
//以指定的长度初始化KeyPairGenerator对象,如果没有初始化系统以1024长度默认设置
//参数:keysize 算法位长.其范围必须在 512 到 1024 之间,且必须为 64 的倍数
gen.initialize(1024);
KeyPair pair = gen.generateKeyPair();
File pubkeyFile = new File(Constant.PUB_KEY_FILE);
File prikeyFile = new File(Constant.PRI_KEY_FILE);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(pubkeyFile));
out.writeObject(pair.getPublic());
out.close();
out = new ObjectOutputStream(new FileOutputStream(prikeyFile));
out.writeObject(pair.getPrivate());
out.close();
复制代码
加密:
采用公钥进行加密:
PublicKey pubkey = (PublicKey) gen.getKey(Constant.PUB_KEY_FILE);//从文件中得到公钥
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubkey);//指定加密模式
byte[] bytes = cipher.doFinal(Constant.DATA.getBytes());
复制代码
解密:
采用私钥进行解密:
PrivateKey prikey = (PrivateKey) gen.getKey(Constant.PRI_KEY_FILE);//从文件中得到私钥
Cipher c = Cipher.getInstance("RSA");
c.init(Cipher.DECRYPT_MODE, prikey);//指定解密模式
byte[] data = c.doFinal(bytes);
复制代码
两段代码中, Constant.DATA.getBytes()和data的值是一致的.
以上,对常见的算法,对了简单的介绍.一般情况下,可以满足我们日常的需求了.
另附3个著名加密算法(MD5、RSA、DES)的解析
地址:http://www.iplaysoft.com/encrypt-arithmetic.html
作者:
低调的奢华
时间:
2013-11-16 18:45
本帖最后由 低调的奢华 于 2013-11-16 18:35 编辑
MD5加密生成的密钥是固定的32位,而Base64加密和DES加密,生成的密钥不是固定。
现在假如要将用户登录的密码进行加密并存入数据库,MD5加密与DES加密相结合的方式是不错的选择。因为DES加密可逆,但是较之MD5难破解些,一般银行卡账户使用的就是这种算法;另外MD5生成固定的32位密钥,便于在数据库中存储,字段长度不变,不会浪费空间。
下面贴上测试代码:
1.MD5加密工具类
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* MD5加密工具类
*
*/
public class Md5Util {
/**
* 根据输入的字符串生成固定的32位MD5码
*
* @param str
* 输入的字符串
* @return MD5码
*/
public final static String getMd5(String str) {
MessageDigest mdInst = null;
try {
mdInst = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
mdInst.update(str.getBytes());// 使用指定的字节更新摘要
byte[] md = mdInst.digest();// 获得密文
return StrConvertUtil.byteArrToHexStr(md);
}
}
复制代码
2.DES加密工具类
import java.security.Key;
import java.security.Security;
import javax.crypto.Cipher;
/**
* DES加密工具类
*/
public class DesUtil {
private static final String ENCRYPT_TYPE = "DES";
private static String defaultKey = "";// 字符串默认键值
private Cipher encryptCipher = null;// 加密工具
private Cipher decryptCipher = null;// 解密工具
public DesUtil() throws Exception {
this(defaultKey);
}
/**
* 指定密钥构造方法
*
* @param strKey
* 指定的密钥
* @throws Exception
*/
public DesUtil(String strKey) throws Exception {
Security.addProvider(new com.sun.crypto.provider.SunJCE());
Key key = getKey(strKey.getBytes());
encryptCipher = Cipher.getInstance(ENCRYPT_TYPE);
encryptCipher.init(Cipher.ENCRYPT_MODE, key);
decryptCipher = Cipher.getInstance(ENCRYPT_TYPE);
decryptCipher.init(Cipher.DECRYPT_MODE, key);
}
/**
* 加密字节数组
*
* @param arr
* 需加密的字节数组
* @return 加密后的字节数组
* @throws Exception
*/
private byte[] encryptStr(byte[] arr) throws Exception {
return encryptCipher.doFinal(arr);
}
/**
* 加密字符串
*
* @param strIn
* 需加密的字符串
* @return 加密后的字符串
* @throws Exception
*/
public String encrypt(String strIn) throws Exception {
return StrConvertUtil.byteArrToHexStr(encryptStr(strIn.getBytes()));
}
/**
* 解密字节数组
*
* @param arr
* 需解密的字节数组
* @return 解密后的字节数组
* @throws Exception
*/
private byte[] decryptStr(byte[] arr) throws Exception {
return decryptCipher.doFinal(arr);
}
/**
* 解密字符串
*
* @param strIn
* 需解密的字符串
* @return 解密后的字符串
* @throws Exception
*/
public String decrypt(String strIn) throws Exception {
return new String(decryptStr(StrConvertUtil.hexStrToByteArr(strIn)));
}
/**
* 从指定字符串生成密钥,密钥所需的字节数组长度为8位。不足8位时后面补0,超出8位只取前8位
*
* @param arrBTmp
* 构成该字符串的字节数组
* @return 生成的密钥
*/
private Key getKey(byte[] arrBTmp) {
byte[] arrB = new byte[8];// 创建一个空的8位字节数组(默认值为0)
// 将原始字节数组转换为8位
for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
arrB<i> = arrBTmp<i>;
</i></i> }
Key key = new javax.crypto.spec.SecretKeySpec(arrB, ENCRYPT_TYPE);// 生成密钥
return key;
}
}<i><i>
</i></i>
复制代码
3.字符串转换工具类
/**
* 字符串转换工具类
*
*/
public class StrConvertUtil {
/**
* 将byte数组转换为表示16进制值的字符串,如:byte[]{8,18}转换为:0813, 和public static byte[]
* hexStrToByteArr(String strIn) 互为可逆的转换过程
*
* @param arrB
* 需要转换的byte数组
* @return 转换后的字符串
*/
public static String byteArrToHexStr(byte[] arrB) {
int iLen = arrB.length;
// 每个byte(8位)用两个(16进制)字符才能表示,所以字符串的长度是数组长度的两倍
StringBuffer sb = new StringBuffer(iLen * 2);
for (int i = 0; i < iLen; i++) {
int intTmp = arrB;
while (intTmp < 0) {// 把负数转换为正数
intTmp = intTmp + 256;
}
if (intTmp < 16) {// 小于0F的数需要在前面补0
sb.append("0");
}
sb.append(Integer.toString(intTmp, 16));
}
return sb.toString();
}
/**
* 将表示16进制值的字符串转换为byte数组,和public static String byteArrToHexStr(byte[] arrB)
* 互为可逆的转换过程
*
* @param strIn
* 需要转换的字符串
* @return 转换后的byte数组
*/
public static byte[] hexStrToByteArr(String strIn) {
byte[] arrB = strIn.getBytes();
int iLen = arrB.length;
// 两个(16进制)字符表示一个字节(8位),所以字节数组长度是字符串长度除以2
byte[] arrOut = new byte[iLen / 2];
for (int i = 0; i < iLen; i = i + 2) {
String strTmp = new String(arrB, i, 2);
arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
}
return arrOut;
}
}
复制代码
作者:
低调的奢华
时间:
2013-11-16 18:45
本帖最后由 低调的奢华 于 2013-11-16 18:36 编辑
4.测试类
public class Test {
public static void main(String[] args) {
try {
DesUtil des = new DesUtil("Java");// 自定义密钥
String src = "需要进行加密的字符串";
String src1 = des.encrypt(src);
String src2 = des.decrypt(src1);
String src3 = Md5Util.getMd5(src1);
System.out.println("DES加密前的字符:" + src + ",长度:" + src.length());
System.out.println("DES加密后的字符:" + src1 + ",长度:" + src1.length());
System.out.println("DES解密后的字符:" + src2 + ",长度:" + src2.length());
System.out.println("MD5加密后的字符:" + src3 + ",长度:" + src3.length());
} catch (Exception e) {
e.printStackTrace();
}
}
}
复制代码
5.测试结果输出
测试结果.jpg
(24.48 KB, 下载次数: 45)
下载附件
2013-11-16 18:32 上传
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2