Java---信息安全,摘要算法

1、发展历史

1.1、古典密码学

凯撒密码、滚筒密码

1.2、近代密码学

德国 Enigma 机、被图灵破解

1.3、现代密码学

2、编码算法

不是加密和解密、而是为了在网络间更方便安全的传输数据/本地存储 而产生

2.1、base64

由 A ~ Z、a ~ z、0 ~ 9、+、/ 共 64个字符组成、去掉 i I o O + / 即 Base58

索引 对应字符 索引 对应字符 索引 对应字符 索引 对应字符
0 A 16 Q 32 g 48 w
1 B 17 R 33 h 49 x
2 C 18 S 34 i 50 y
3 D 19 T 35 j 51 z
4 E 20 U 36 k 52 0
5 F 21 V 37 l 53 1
6 G 22 W 38 m 54 2
7 H 23 X 39 n 55 3
8 I 24 Y 40 o 56 4
9 J 25 Z 41 p 57 5
10 K 26 a 42 q 58 6
11 L 27 b 43 r 59 7
12 M 28 c 44 s 60 8
13 N 29 d 45 t 61 9
14 O 30 e 46 u 62 +
15 P 31 f 47 v 63 /
<!-- 用commons-codec 实现base64 -->
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.15</version>
</dependency>
/**
 * 使用 JDK原生来实现Base64
 */
@Test
public void test1() throws UnsupportedEncodingException {
    
    
    String str = "atCloud";
    // 编码 1.8 才提供的
    String encodeStr = Base64.getEncoder().encodeToString(str.getBytes(UTF8));
    System.out.println("encode:" + encodeStr); // YXRDbG91ZA==
    // 解码
    byte[] decode = Base64.getDecoder().decode(encodeStr.getBytes(UTF8));
    System.out.println("decode:" + new String(decode,UTF8));// atCloud
}

/**
 * 使用 commons-codec 来实现base64
 */
@Test
public void test2() throws UnsupportedEncodingException {
    
    
    String str = "atCloud";
    // 编码
    String encodeBase64String = org.apache.commons.codec.binary.Base64.encodeBase64String(str.getBytes(UTF8));
    // YXRDbG91ZA==
    System.out.println("encodeBase64String:" + encodeBase64String);
    // 解码
    byte[] decodeBase64 = org.apache.commons.codec.binary.Base64.decodeBase64(encodeBase64String.getBytes(UTF8));
    // atCloud
    System.out.println("decodeBase64:" + new String(decodeBase64,UTF8));
}
/**
 * 测试 = 补充
 */
@Test
public void test3() throws UnsupportedEncodingException {
    
    
    String str = "武";
    // 编码
    String encodeBase64String = org.apache.commons.codec.binary.Base64.encodeBase64String(str.getBytes("gbk"));
    // zuQ=
    System.out.println("encodeBase64String:" + encodeBase64String);

    String str1 = "abc";
    // 编码
    String encodeBase64String1 = org.apache.commons.codec.binary.Base64.encodeBase64String(str1.getBytes("gbk"));
    // YWJj
    System.out.println("encodeBase64String:" + encodeBase64String1);
}

注意:base64 以三个字节为一组、如果最后一组不足三个字节、则用 = 补充

2.2、URL编码

application/x-www-from-urlencoded
public class UrlTest {
    
    
    private static final String UTF8 = StandardCharsets.UTF_8.name();
    /**
     * URL实现 编码/解码
     */
    @Test
    public void test1() throws Exception{
    
    
        String str = "AtCloud 武";
        // 编码
        String encode = URLEncoder.encode(str, UTF8);
        System.out.println("encode:" + encode);
        // 解码
        String decode = URLDecoder.decode(encode, UTF8);
        System.out.println("decode:" + decode);
    }
}

2.3、十六进制和字节数组互转

/**
 * 把16进制字符串(一定是偶数位、因为converBytes2HexStr已经处理过了、如果是单个位、会自动补零)转为字节数组
 * @param hexStr
 * @return
 */
public static byte[] convertHex2Bytes(String hexStr){
    
    
    // 一个字节可以转为两个16进制字符
    byte[] result = new byte[hexStr.length() / 2];
    for (int i = 0; i < result.length; i++) {
    
    
        // hexStr: abcd
        // Integer.parseInt:把s转为10进制数、redix指定s是什么进制的数
        // 获取每个字节的高四位,hexStr.substring(2,3) => c
        int high4 = Integer.parseInt(hexStr.substring(i * 2,i * 2 + 1), 16);
        // 获取每个字节的低四位,hexStr.substring(3,4) => d
        int low4 = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2));
        result[i] = (byte) (high4 * 16 + low4);
    }
    return result;
}

3、摘要算法

3.1、定义

又叫 Hash 算法、散列函数、数字摘要、消息摘要。它是一种单向算法、用户可以通过 hash 算法对目标信息生成一段特定长度的唯一 hash 值、但不能通过这个 hash 值重新获得目标信息

3.2、应用场景

  • 密码、信息完整性校验、数字签名

3.3、常见算法

  • MD5:Message-Digest Algorithm,结果占128位 ⇒ 16个byte
/**
 * 使用Codec实现MD5
 */
@Test
public void test2() throws Exception{
    
    
    String str = "AtCloud 武";
    System.out.println(DigestUtils.md5Hex(str.getBytes(UTF8)));
}

 /**
  * 使用JDK原生API实现MD5
  */
 @Test
 public void test1() throws Exception{
    
    
     String str = "AtCloud 武";
     // 编码
     String algorithm = "MD5";
     // 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
     String hexStr = MessageDigestUtils.doDigest(str,algorithm);
     System.out.println("hexStr:" + hexStr);
 }
public class HexUtils {
    
    
    /**
     * 把字节数组转为十六进制字符串、如果一个字节转为16进制字符后不足两位、则前面补0
     * @param digest
     * @return
     */
    public static String converBytes2HexStr(byte[] digest) {
    
    
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
    
    
            // 获取 b 的补码的后八位
            String hex = Integer.toHexString(((int)b) & 0xff);
            // 15 --> Integer.toHexString(15 & 0xff) -->f-->0f
            // 16 --> Integer.toHexString(16 & 0xff)
            if (hex.length() == 1){
    
    
                hex = "0" + hex;
            }
            sb.append(hex);
        }
        return sb.toString();
    }
}

/**
 * @author Cloud
 */
public class MessageDigestUtils {
    
    
    private static final String UTF8 = StandardCharsets.UTF_8.name();

    /**
     * 执行消息摘要
     * @param originalContent 原始字符串
     * @param algorithm 算法名字、如MD5
     * @return 摘要内容
     */
    public static String doDigest(String originalContent,String algorithm){
    
    
        try {
    
    
            // 获取消息摘要算法对象
            MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
            // 获取带原始内容的字节数组
            byte[] bytes = originalContent.getBytes(UTF8);
            // 获取到摘要结果
            byte[] digest = messageDigest.digest(bytes);
            // 当 bytes 比较大的时候、循环的进行update()
//        messageDigest.update(bytes);
//        messageDigest.digest();
            // 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
            String hexStr = HexUtils.converBytes2HexStr(digest);
            return hexStr;
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        return null;
    }
}
  • SHA:安全散列算法
    • sha-256
    • 其他如 sha-0、sha-1、sha-512
public class Sha256Test {
    
    
    private static final String UTF8 = StandardCharsets.UTF_8.name();

    /**
     * 使用Codec实现Sha256
     */
    @Test
    public void test2() throws Exception{
    
    
        String str = "AtCloud 武";
        System.out.println(DigestUtils.sha256Hex(str.getBytes(UTF8)));
    }

    /**
     * 使用JDK原生API实现Sha256
     */
    @Test
    public void test1() throws Exception{
    
    
        String str = "AtCloud 武";
        // 编码
        String algorithm = "SHA-256";
        // 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
        String hexStr = MessageDigestUtils.doDigest(str,algorithm);
        System.out.println("hexStr:" + hexStr);
    }
}
public class Sha512Test {
    
    
    private static final String UTF8 = StandardCharsets.UTF_8.name();

    /**
     * 使用Codec实现Sha512
     */
    @Test
    public void test2() throws Exception{
    
    
        String str = "AtCloud 武";
        System.out.println(DigestUtils.sha512Hex(str.getBytes(UTF8)));
    }

    /**
     * 使用JDK原生API实现Sha512
     */
    @Test
    public void test1() throws Exception{
    
    
        String str = "AtCloud 武";
        // 编码
        String algorithm = "SHA-512";
        // 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
        String hexStr = MessageDigestUtils.doDigest(str,algorithm);
        System.out.println("hexStr:" + hexStr);
    }
}
  • MAC(Message Authentication Code):消息认证码、是一种带有密钥的 hash 函数
public class MacTest {
    
    
    private static final String UTF8 = StandardCharsets.UTF_8.name();

    /**
     * 使用Codec实现Mac
     */
    @Test
    public void test2() throws Exception{
    
    
        String str = "AtCloud 武";
        // 指定密钥
        String key = "123";
        String hmacMD5Hex = new HmacUtils(HmacAlgorithms.HMAC_MD5, key.getBytes(UTF8)).hmacHex(str.getBytes(UTF8));
        String HmacSHA256 = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key.getBytes(UTF8)).hmacHex(str.getBytes(UTF8));
        String HmacSHA512 = new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key.getBytes(UTF8)).hmacHex(str.getBytes(UTF8));
    }

    /**
     * 使用JDK原生API实现Mac
     */
    @Test
    public void test1() throws Exception{
    
    
        String str = "AtCloud 武";
        // 指定密钥、Mac摘要算法和digest算法(MD5、Sha) 不同的地方就是加了盐
        String key = "123";
        String algorithm = "HmacMD5";
        // 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
        String HmacMD5 = doMacDigest(str,key,algorithm);
        // 返回32位加密数据
        System.out.println("HmacMD5:" + HmacMD5);

        String algorithm1 = "HmacSHA256";
        // 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
        String HmacSHA256 = doMacDigest(str,key,algorithm1);
        // 返回64位加密数据
        System.out.println("HmacSHA256:" + HmacSHA256);

        String algorithm2 = "HmacSHA512";
        // 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
        String HmacSHA512 = doMacDigest(str,key,algorithm2);
        // 返回128位加密数据
        System.out.println("HmacSHA512:" + HmacSHA512);
    }

    /**
     * 获取Mac消息摘要
     * @param originalContent 原始内容
     * @Param key Mac算法的key
     * @param algorithm 算法名字、如HmacMD5
     * @return
     */
    public static String doMacDigest(String originalContent,String key,String algorithm){
    
    
        try {
    
    
            // 获取消息摘要算法对象
            Mac mac = Mac.getInstance(algorithm);
            // 获取key对象并初始化mac
            SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(UTF8), algorithm);
            mac.init(secretKeySpec);
            // 获取带原始内容的字节数组
            byte[] bytes = originalContent.getBytes(UTF8);
            // 获取到摘要结果
            byte[] macBytes = mac.doFinal(bytes);
            // 把每一个字节转为16进制字符、最终在拼接起来这些16进制字符即可
            String hexStr = HexUtils.converBytes2HexStr(macBytes);
            return hexStr;
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        return null;
    }
}
  • 其他如 MD2、MD4、HAVAL 就暂时不一 一解答了

Guess you like

Origin blog.csdn.net/qq_54177999/article/details/120654165