慕课网学习笔记
参考:Java加密算法
消息摘要算法加密
- 消息摘要算法主要分为3类:MD(Message Digest)、SHA(Secure Hash Algorithm)、MAC(Message Authentication Code),以上3类算法的主要作用是验证数据的完整性——是数字签名的核心算法。
消息摘要算法——MD
- MD算法家族有3类MD2、MD4、MD5,MD家族生成的都是128位的信息摘要。
算法 | 摘要长度 | 实现方 |
---|---|---|
MD2 | 128 | JDK |
MD4 | 128 | Bouncy |
MD5 | 128 | JDK |
- 信息摘要算法由于使用的是一种单向函数,所以理论上是不可破解的(山东大学的王晓云教授已经破解了MD5和SHA,所以消息摘要是可以伪造的,只不过难度比较大)。所有MD算法进行摘要的结果都是128为位(32位16进制的数字,因为1位16进制数代表4位二进制数)
以下是Java中实现的各种MD加密:
package md;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.MD2Digest;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class JavaMD {
private static String src = "object-oriented"; // 需要加密的原始字符串
public static void main(String[] args) throws NoSuchAlgorithmException {
System.out.println("原始字符串:" + src + "\n");
jdkMD5();
bouncyCastleMD5();
commonsCodecMD5();
System.out.println();
jdkMD2();
bouncyCastleMD2();
commonsCodecMD2();
System.out.println();
bouncyCastleMD4();
}
/** jdk实现MD5加密 */
public static void jdkMD5() throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] md5Bytes = md.digest(src.getBytes());
System.out.println("JDK MD5:" + Hex.encodeHexString(md5Bytes));//利用第三方包将byte数组转化为16进制字符串
}
/** jdk实现MD2加密 */
public static void jdkMD2() throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("md2");
byte[] md5Bytes = md.digest(src.getBytes());
System.out.println("JDK MD2:" + Hex.encodeHexString(md5Bytes));
}
/** Bouncy Castle实现MD4加密 */
public static void bouncyCastleMD4() throws NoSuchAlgorithmException{
/*通过这种方式给JDK动态添加一个provider,就可以通过这种方式获得JDK本身不支持的MD4了*/
Security.addProvider(new BouncyCastleProvider());
MessageDigest md = MessageDigest.getInstance("md4");
byte[] md4Bytes = md.digest(src.getBytes());
System.out.println("bc MD4:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md4Bytes));
}
/** Bouncy Castle实现MD5加密 */
public static void bouncyCastleMD5(){
Digest digest = new MD5Digest();
digest.update(src.getBytes(), 0, src.getBytes().length);
byte[]md5Bytes = new byte[digest.getDigestSize()];
digest.doFinal(md5Bytes, 0);
System.out.println("bc MD5:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md5Bytes));
}
/** Bouncy Castle实现MD2加密 */
public static void bouncyCastleMD2(){
Digest digest = new MD2Digest();
digest.update(src.getBytes(), 0, src.getBytes().length);
byte[]md2Bytes = new byte[digest.getDigestSize()];
digest.doFinal(md2Bytes, 0);
System.out.println("bc MD2:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md2Bytes));
}
/** Commons Codec 实现MD5加密*/
public static void commonsCodecMD5() {
System.out.println("cc MD5:\t" + DigestUtils.md5Hex(src.getBytes()));
}
/** Commons Codec 实现MD2加密*/
public static void commonsCodecMD2() {
System.out.println("cc MD2:\t" + DigestUtils.md2Hex(src.getBytes()));
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
以上程序的运行结果:
- JDK本身提供了MD2和MD5的实现,apache的Commons Codec在JDK的基础上进行了改良,使用Commons Codec提供接口进行MD2和MD5加密将会简单很多。JDK本省并没有提供MD4算法的实现,但是我们可以通过动态添加provider的方式让jdk支持MD4,见以下代码:
/* 通过这种方式给JDK动态添加一个provider,就可以通过这种方式获得JDK本身不支持的MD4了 */
Security.addProvider(new BouncyCastleProvider());
MessageDigest md = MessageDigest.getInstance("md4");
byte[] md4Bytes = md.digest(src.getBytes());
System.out.println("bc MD4:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md4Bytes));
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- Bouncy Castle提供了MD2、MD4和MD5的实现,对消息摘要算法的支持比较完善,但是API还是没有Apache的Commons Codec友善。因此,如果我们要进行MD2和MD4实现,最好选用Commons Codec。
MD算法的应用
-
注册时:
应用程序服务器将用户提交的密码进行MD5即:数据库中存放的用户名是明文,而密码是密文(16进制字符串)摘要算法,得到32位的16进制字符串(密文)。把用户名(明文)和密码(密文)进行信息持久化存储到数据库中,返回注册结果。 -
登录时:
应用程序服务器同样对密码进行MD5摘要,然后将用户提交的用户名和密码的摘要信息和数据库中存储的信息进行比对,返回登录结果。
消息摘要算法——SHA
安全散列算法,固定长度的摘要信息。被认为是MD5的继承者。是一个系列,包括SHA-1、SHA-2(SHA-224、SHA-256、SHA-384、SHA-512),也就是除了SHA-1,其他的4种都被称为是SHA-2。每种算法的摘要长度和实现方如下:
- SHA算法的实现和MD算法的实现大同小异,也是JDK提供了默认的几种实现,apache的Commons Codec在JDK的基础上进行了优化,使其更好用,而Bouncy Castle是JDK的拓展,提供了JDK和Commons Codec没有的SHA-224的实现。
package sha;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA224Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
public class JavaSHA {
private static String src = "object-oriente"; // 需要加密的原始字符串
public static void main(String[] args) throws NoSuchAlgorithmException {
System.out.println("原始字符串:" + src);
jdkSHA1();
bouncyCastleSHA1();
commonsCodecSAH1();
System.out.println();
bouncyCastleSHA224();
System.out.println();
jdkSHA256();
bouncyCastleSHA256();
}
/** JDK实现sha-1 */
public static void jdkSHA1() throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("sha");// sha1算法传入参数为sha
byte[] sha1Bytes = md.digest(src.getBytes());
System.out.println("JDK SHA-1:\t" + Hex.encodeHexString(sha1Bytes));
}
/** JDK实现sha-256 */
public static void jdkSHA256() throws NoSuchAlgorithmException{
MessageDigest md = MessageDigest.getInstance("sha-256");
md.update(src.getBytes());
System.out.println("JDK SHA-256:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md.digest()));
}
/** Bouncy Castle实现sha-1 */
public static void bouncyCastleSHA1(){
Digest digest = new SHA1Digest();
digest.update(src.getBytes(), 0, src.getBytes().length);
byte[]sha1Bytes = new byte[digest.getDigestSize()];
digest.doFinal(sha1Bytes, 0);
System.out.println("bc SHA-1:\t" + org.bouncycastle.util.encoders.Hex.toHexString(sha1Bytes));
}
/** Bouncy Castle实现sha-224 */
public static void bouncyCastleSHA224(){
Digest digest = new SHA224Digest();
digest.update(src.getBytes(), 0, src.getBytes().length);
byte[]sha224Bytes = new byte[digest.getDigestSize()];
digest.doFinal(sha224Bytes, 0);
System.out.println("bc SHA-224:\t" + org.bouncycastle.util.encoders.Hex.toHexString(sha224Bytes));
}
/** Bouncy Castle实现sha-256 */
public static void bouncyCastleSHA256() {
Digest digest = new SHA256Digest();
digest.update(src.getBytes(), 0, src.getBytes().length);
byte[] sha256Bytes = new byte[digest.getDigestSize()];
digest.doFinal(sha256Bytes, 0);
System.out.println("bc SHA-256:\t" + org.bouncycastle.util.encoders.Hex.toHexString(sha256Bytes));
}
/** Commons Codec实现sha-1 */
public static void commonsCodecSAH1(){
System.out.println("cc SHA-1:\t" + DigestUtils.sha1Hex(src.getBytes()));
/* 采用下面的方式更加方便 */
// System.out.println("cc SHA-1:\t" + DigestUtils.sha1Hex(src));
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
运行结果:
SHA算法的应用
在浏览器的证书管理器中证书:WEB证书一般采用SHA算法。
消息摘要算法是为了防止消息在传输过程中的篡改。
我们在很多网站上都可以用QQ账号一键登录,通常腾讯会给每一个接入方一个key,可能会约定一个消息传送的格式(例如:http://**?msg=12Hsad74mj&×tamp=1309488734),其中msg=摘要信息+key+时间戳。
消息摘要算法——MAC
MAC(Message Authentication Code),兼容了MD和SHA的特性,并且在它们的基础上加入了密钥。因此MAC也称为HMAC(keyed-Hash Message Authentication Code)含有密钥的散列函数算法。
- MD系列:HmacMD2、HmacMD4、HmacMD5
- SHA系列:HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384、HmacSHA512
例如:常用的Linux客户端SecurityCRT。MAC的算法的提供者如下:
Commons Codec中并没有提供Hmac算法的实现。
下面的程序以JDK本身和Bouncy Castle实现了HmacMD5,如果需要实现其他的加密只需要改变相关的参数即可:
package hmac;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
public class JavaHmac {
private static String src = "object-oriente"; // 需要加密的原始字符串
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException, DecoderException {
System.out.println("原始字符串:" + src + "\n");
jdkHmacMD5();
bouncyCastleHmacMD5();
}
public static void jdkHmacMD5() throws NoSuchAlgorithmException, InvalidKeyException, DecoderException{
//1.得到密钥
KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5");
SecretKey secretKey = keyGenerator.generateKey();//生成密钥
// byte[] key = secretKey.getEncoded();//获得密钥
byte[] key = Hex.decodeHex("aabbccddee".toCharArray());
//2.还原密钥
SecretKey restoreSecretKey = new SecretKeySpec(key, "hmacMD5");
//3.信息摘要
Mac mac = Mac.getInstance(restoreSecretKey.getAlgorithm());//实例化mac
mac.init(restoreSecretKey);//初始化mac
byte[] hmacMD5Bytes = mac.doFinal(src.getBytes());//执行摘要
System.out.println("jdkHmacMD5:\t" + Hex.encodeHexString(hmacMD5Bytes));
}
public static void bouncyCastleHmacMD5() {
HMac hmac = new HMac(new MD5Digest());
//生成密钥的时候以aabbccddee为基准
hmac.init(new KeyParameter(org.bouncycastle.util.encoders.Hex.decode("aabbccddee")));
hmac.update(src.getBytes(), 0, src.getBytes().length);
// 执行摘要
byte[]hmacMDdBytes = new byte[hmac.getMacSize()];
hmac.doFinal(hmacMDdBytes, 0);
System.out.println("bcHmacMD5:\t"+org.bouncycastle.util.encoders.Hex.toHexString(hmacMDdBytes));
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
运行结果:
HMAC算法的应用: