0


常见的编码及哈希算法

一、常见的编码

ASCII码:ASCII码中只存储英文字符,有127个字符,占一个字节

Unicode码:可以存储中文,占两个字节

UTF-8:实际上是从Unicode码中推算出来的一种编码方式

URL编码:是浏览器发送数据时的一种编码,通常附加在URL的参数部分。之所以需要,是因为很多服务器只能识别ASCII字符,对字符进行编码,URL它独有一套自己的编码规则。在java的类库中提供了URLEncoder类,来对任意字符串进行URL编码。

如果服务器收到URL编码,会对它自动进行解码

示例代码:

    String url = "http://www.baidu.com/s?wd=";
        String value = "杨玉环";
        
        //对URL中的中文进行编码
        String result = URLEncoder.encode(value,"utf-8");
        
        System.out.println(result);
        System.out.println(url + result);
        
        //对URL中的中文进行解码
        String param = "https://www.baidu.com/s?wd=%E6%88%91%E6%9C%AC%E5%B0%86%E5%BF%83%E5%90%91%E6%98%8E%E6%9C%88";
        String content = URLDecoder.decode(param, "utf-8");
        System.out.println(content);

Base64编码:对二进制数据进行编码,转换成文本格式,这样在很多文本中就可以处理进制数据。
Base64编明是种编码算法。不是加密算法。

    
        //读取图片(字节数组)
        byte[] imageByteArray = Files.readAllBytes(Paths.get("d:\\test\\aaayx.jpg"));
        
        //将字节数组进行Base64编码,转换成字符串格式
        String imageDataStr = Base64.getEncoder().encodeToString(imageByteArray);
        //System.out.println(imageDataStr);
        
        //Base64解码
        byte[] imageResultByteArray = Base64.getDecoder().decode(imageDataStr);
        Files.write(Paths.get("d:\\test\\img\\yx.jpg"), imageResultByteArray);
        

二、哈希算法

1、什么是哈希算法

    哈希算法( Hash )又称摘要算法( Digest ),它的作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。哈希算法的目的:为了验证原始数据是否被篡改。

哈希算法最重要的特点就是:
(1)相同的输入-定得到相同的输出;
(2)不同的输入大概率得到不同的输出。

2、常用的哈希算法

3、哈希算法的用途

校验下载文件

存储用户密码

4、MD5:加密后的结果为128位==16个字节

    使用MessageDigest,初始化一个实例化对象,调用getInstance()方法,传入要进行加密的算法,然后反复调用update()方法,更新原始数据,调用digest()方法进行加密,然后将加密后的内容存储到一个字节数组,利用forerach循环,将字节数组转换成16进制来表示。

示例代码:

String password = "***********";
        
        //根据当前算法,获取加密工具对象(摘要)
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            
            //更新原始数据
            digest.update(password.getBytes());
            
            //加密后的字节数组转换为字符串
            byte[] resultByteArray = digest.digest();
            
            //加密后的结果为128位==16个字节
            System.out.println(resultByteArray.length);
            
            StringBuilder result = new StringBuilder();
            
            for(byte bite : resultByteArray) {
                result.append(String.format("%02x", bite));
            }
            
            System.out.println(result);
            System.out.println(result.length());
            
            
        } catch (NoSuchAlgorithmException e) {
            
            e.printStackTrace();
        }

5、SHA-1算法:加密结果为160位==20个字节

为了避免数据被彩虹表攻击,在进行算法加密时,我们可以给数据“加盐”,即对数据添加额外的随机数。

使用SHA-1算法是,步骤大致与MD5算法一致,唯一不同的是在传入的MessageDigest参数里面,将“MD5”修改成“SHA-1”。

示例代码:

    String password = "*******";
        String salt = UUID.randomUUID().toString().substring(0,4);
        System.out.println(salt);
        
        try {
            //获取SHA-1算法工具对象
            MessageDigest digest  = MessageDigest.getInstance("SHA-1");
            digest.update(password.getBytes());
            digest.update(salt.getBytes());
            
            byte[] resultByteArray = digest.digest();
            System.out.println(Arrays.toString(resultByteArray));
            System.out.println(resultByteArray.length);
            
            StringBuilder result = new StringBuilder();
            for(byte b : resultByteArray) {
                result.append(String.format("%02x", b));
            }
            
        System.out.println(result);
        System.out.println(result.length());
        
        } catch (NoSuchAlgorithmException e) {
            
            e.printStackTrace();
        }
        

6、Hmac算法

   Hmac算法就是一种基于密钥的消息认证码算法是一种更安全的消息摘要算法,Hmac算法总是和某种哈希算法配合起来用的。例如,我们使用MD5算法,对应的就是Hmac MD5 算法,因此,HmacMD5 可以看作带有一一个安全的key的MD5。使用HmacMD5而不是用MD5加salt,有如下好处:

HmacMD5使用的key长度是64字节,更安全;
Hmac是标准算法,同样适用于SHA-1 等其他哈希算法;
Hmac输出和原有的哈希算法长度一致。

Hmac的加密步骤:

1.使用KeyGenerator (秘钥生成器),获取实例,传入要使用的算法名称

2.通过SecretKey ,创建一个秘钥

3.将秘钥编码成字节数组,foreach循环遍历秘钥字节数组,使用StringBuilder进行拼接得到一个字符串类型的秘钥。

4.创建Mac实例化对象,传入要使用的算法。

注意:这里的算法要与生成秘钥的算法一致

5.调用mac对象的init()方法,初始化秘钥

6.反复调用update()方法更新原始内容

7.调用doFinal()方法进行加密,最后将加密后的字节数组,转换成16进制来表示

下面我们以MD5与Hmac来演示:

           String password = "*******";
            //1.生成秘钥
            //秘钥生成器KeyGenerator
            KeyGenerator keyGen = KeyGenerator.getInstance("HmacMD5");
            
            //生成秘钥key
            SecretKey key = keyGen.generateKey();
            
            //获得秘钥key的字节数组(64)位
            byte[] keyByteArray = key.getEncoded();
            
            StringBuilder keyStr = new StringBuilder();
            
            for(byte b : keyByteArray) {
                keyStr.append(String.format("%02x", b));
            }
            
            System.out.println("秘钥内容:" + keyStr);
            
            //2.使用秘钥,进行加密
            //获取算法对象
            Mac mac = Mac.getInstance("HmacMD5");
            
            //初始化秘钥
            mac.init(key);
            
            //更新原始内容
            mac.update(password.getBytes());
            
            //加密
            byte[] resultByteArray = mac.doFinal();
            
            System.out.println("加密结果:" + resultByteArray.length + "字节");
            
            StringBuilder resultStr = new StringBuilder();
            for(byte b : resultByteArray) {
                resultStr.append(String.format("%02x", b));
            }
            
            System.out.println("加密结果:"+ resultStr);
            
        }catch (InvalidKeyException e) {
            
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            
            e.printStackTrace();
        } 

有了秘钥的字节数组和要加密的内容,我们也可以恢复秘钥,然后来进行加密:

String password = "********";
        
        try {
            //通过“秘钥的字节数组”,恢复秘钥
            byte[] keyByteArray = {-65, -120, -61, 25, 78, 116, -87, 20, -127, 67, 60, -26, 66, -103, 30, 79, 122, -20, -60, 60, -13, 8, 99, 5, 112, 105, 107, 116, -73, 42, -16, -123, 100, 104, -85, -12, 22, 12, -37, -67, 50, 36, 17, -121, -21, -17, 94, 56, -7, -50, -59, -6, 8, 77, -12, -4, 46, 10, -7, 96, -103, -91, -2, 76};
            SecretKey key = new SecretKeySpec(keyByteArray, "HmacMD5");
            
            //加密
            Mac mac = Mac.getInstance("HmacMD5");
            //初始化秘钥
            mac.init(key);
            
            mac.update(password.getBytes());
            
            byte[] resultByteArray = mac.doFinal();
            
            StringBuilder resultStr = new StringBuilder();
            for(byte b : resultByteArray) {
                resultStr.append(String.format("%02x", b));
            }
            System.out.println("加密结果:" + resultStr);
            
            
        } catch (InvalidKeyException e) {
            
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            
            e.printStackTrace();
        } catch (IllegalStateException e) {
            
            e.printStackTrace();
        }

7、RipeMD160算法:加密结果为160位==20个字节

    RipeMD160算法在java标准库中并没有提供,如果我们需要使用BouncyCastle提供的第三方开源jar包手动导入。

注意:

Java标准库的java. security包提供了一种标准机制,允许第三方提供商无缝接入。我们要先把BouncyCastle注册一下

加密步骤与MD5、SHA-1步骤大致相似

try {
            //注册BouncyCastle提供的通知类对象BouncyCastleProvider
            Security.addProvider(new BouncyCastleProvider());
            
            //获取RipeMD160算法的“消息摘要对象”
            MessageDigest md = MessageDigest.getInstance("RipeMD160");
            
            //更新原始数据
            md.update("hello".getBytes());
            
            //获取消息摘要(加密)
            byte[] result = md.digest();
            
            //消息摘要的字节长度和内容
            System.out.println(Arrays.toString(result));
            System.out.println(result.length); //160位==20字节
            
            //16进制内容字符串
            String hex = new BigInteger(1,result).toString(16);
            System.out.println(hex.length()); //20字节=40字符
            System.out.println(hex);
            
        } catch (NoSuchAlgorithmException e) {
        
            e.printStackTrace();
        }

本文转载自: https://blog.csdn.net/qq_59616295/article/details/125894972
版权归原作者 记得爱蓝色 所有, 如有侵权,请联系我们删除。

“常见的编码及哈希算法”的评论:

还没有评论