Java编码算法和摘要算法
编码算法
- 编码算法是将一种形式转换成等价的另外一种形式。主要是为了方便某种特定场景的处理。
- 字母如何在计算机中表示呢?
- 用ASCII编码
- 那中文字符如何在计算机中表示呢?
- 用Unicode编码
- 如何同时兼容字母和中文呢?
- 用UTF-8编码
- 我浏览器想给服务器发送数据,有没有什么编码方式呢?
- 用URL编码
- 一般规则
- A-Z, a-z, 0-9, -_.* 保持不变
- 其他字符以%XX表示(如,中:%E4%B8%AD (UTF8:E4B8AD))
- 发邮件的时候二进制附件怎么发送呢?
- 用Base64编码
- 把二进制数据用文本表示的编码算法,二进制6位6位的通过映射表进行映射。
- 比如 : 中编码之后是 "5Lit",过程如下
-
- 点评
- 适用于文本协议,但长度会增加1/3,如果数组长度不是3的整数倍,末尾会增加一个或两个0x00(对应的是一个或两个==)
- 点评
摘要算法(哈希算法)
- 目的是验证原始数据有没有被篡改
- 一些基本原则
- 输入长度不定,输出长度固定
- 相同的输入就有相同的输出
- 不同的输入尽量得到不同的输出
- 会有什么问题:有可能会发生碰撞。
- 一个好的摘要算法需要具备的安全性
- 碰撞率低
- 不能猜测输出
- 输入的任意一个bit的变化都会造成输出的完全的不同
- 很难从输出反推输入
- 常用的摘要算法有哪些
-
- MD5
- 可以用于文件验证,存储口令,登录验证。
- 用于存储口令的时候需要注意什么问题?
- MD5
-
- 需要预防彩虹表攻击:采用一些简单的字符md5加密。
- 办法是:md5.update(salt+inputPassward) (salt是一些额外的随机数)
-
- SHA-1/SHA-256/SHA-512(Secure Hash Algorithm)
- 可以看成MD5的加强版,输出由128位变为160/256/512位。
- 但是相应的:加解密速度比MD5要慢。
- SHA-1/SHA-256/SHA-512(Secure Hash Algorithm)
-
- RipeMD 160
- 第三方提供,非JDK自带,使用时需要先引入对应cprov-jdk15on-160.jar包
- RipeMD 160
-
- Hmac(Hash-based Message Authentication Code)
- 更安全的消息摘要算法,基于秘钥
- 加密思想类似 md5(salt+input),咱Hmac中salt是64位
- 可以用HmacMD5/HmacSHA1/HmacSHA256/HmacSHA512几种
- Hmac(Hash-based Message Authentication Code)
编码算法和摘要算法的代码如下
package TestDemo; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.net.URLEncoder; import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Security; import java.util.Base64; import javax.crypto.KeyGenerator; import javax.crypto.Mac; import javax.crypto.SecretKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; public class Test { public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException { //URL编码 String urlBeforeEncode = "http://www.cnblogs.com/darrenqiao/"; //支持的编码格式 :US-ASCII, ISO-8859-1, UTF-8, UTF-16BE, UTF-16LE, UTF-16 String urlAfterEncode = URLEncoder.encode(urlBeforeEncode, "UTF-8"); System.out.println("url进行URL编码的链接为: " + urlBeforeEncode); System.out.println("url进行URL编码的链接为: " + urlAfterEncode); byte[] input = new String("darrenqiao").getBytes(); //Base64编码 String urlAfterBase64Encode = Base64.getUrlEncoder().encodeToString(urlBeforeEncode.getBytes()); System.out.println("url进行Base64编码之后的文本: " + urlAfterBase64Encode); System.out.println("Base64编码前的六进制码流: " + String.format("%032x", new BigInteger(input))); String base64Output = Base64.getEncoder().encodeToString(input); System.out.println("Base64编码后的文本: " + base64Output); //MD5加密 MessageDigest md5 = MessageDigest.getInstance("MD5"); System.out.println("加密前的十六进制码流: " + String.format("%032x", new BigInteger(input))); md5.update(input); byte[] md5Output = md5.digest(); System.out.println("md5加密后的十六进制码流: " + String.format("%032x", new BigInteger(md5Output))); //SHA-1加密 MessageDigest sha1 = MessageDigest.getInstance("SHA-1"); sha1.update(input); byte[] sha1Output = sha1.digest(); System.out.println("SHA-1加密后的十六进制码流: " + String.format("%032x", new BigInteger(sha1Output))); //SHA-256加密 MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); sha256.update(input); byte[] sha256Output = sha256.digest(); System.out.println("SHA-256加密后的十六进制码流: " + String.format("%032x", new BigInteger(sha256Output))); //SHA-512加密 MessageDigest sha512 = MessageDigest.getInstance("SHA-512"); sha512.update(input); byte[] sha512Output = sha512.digest(); System.out.println("SHA-512加密后的十六进制码流: " + String.format("%032x", new BigInteger(sha512Output))); //RipeMD-160加密 Security.addProvider(new BouncyCastleProvider()); MessageDigest ripeMD160 = MessageDigest.getInstance("RipeMD160"); ripeMD160.update(input); byte[] ripeMD160Output = ripeMD160.digest(); System.out.println("RipeMD-160加密后的十六进制码流: " + String.format("%032x", new BigInteger(ripeMD160Output))); //HmacMD5加密,HmacSHA1/HmacSHA256/HmacSHA512这几种只要替换参数就可以 KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5"); SecretKey secretKey = keyGenerator.generateKey(); Mac mac = Mac.getInstance("HmacMD5"); mac.init(secretKey); mac.update(input); byte[] hmacMD5Output = mac.doFinal(); System.out.println("HmacMD5加密后的十六进制码流: " + String.format("%032x", new BigInteger(hmacMD5Output))); } }
运行结果如下