MD5 与 Base64一起使用 加密,计算原理

  • Post author:
  • Post category:其他





加密效果(MD5 + Base64)




加密原文:


1234



加密后的结果:


gdyb21LQTcIANtvYMT7QVQ==

22位(不包括等于号)


123456


4QrcOUm6Wau+VuBX8g+IPg==


■如何计算



1.使用MD5,取得信息摘要

1234对应的信息摘要如下

[-127, -36, -101, -37, 82, -48, 77, -62, 0, 54, -37, -40, 49, 62, -48, 85]

一共 16 byte

16*8=128

128%6=2

21余2



2.使用Base64再次处理


1.将每三个字节分成一组,一共24个二进制位:3*8=24


2.将这24个二进制位分成4组,每组有6个二进制位:24/4=6


3.在每组前加两00,扩展成32个二进制位,即4个字节:4*(6+2)=32


4.根据下面的编码表,得到扩展后每个字节的对应符号,就是Base64的编码值



注意:


1.因为转换后的每个字符的最高两位都是0,所以实际有效位数是6位,


也就是26=64个字符就可以覆盖所有的编码。


2.如果剩下的字符不足3个字节,则用0填充,输出字符使用”=”,


因此编码后输出的文本末尾可能会出现1或2个”=”。


3.因为Base64将3个字节转化成4个字节,因此Base64编码后的文本,


会比原文本大出三分之一左右。


补=的规律:


(如果N*8%6后余2个二进制位,就补2个=,余4个二进制位就补一个=,整除不补)


剩余两位 ,2*8=16 % 6 结果为(余数为) 4


剩余一位,1*8=8   %6  结果为(余数为) 2


前三位对应的二进制


(正数的补码)

-127

10000001

-36

11011100

-101

10011011


转化为四个字符


(3*8bit=4*6bit)


100000 ⇒32 ⇒g

011101 ⇒29 ⇒d

110010 ⇒50 ⇒y

011011 ⇒27 ⇒b


补充说明


MD5是一种信息摘要算法,并不是加密算法


相关知识



1.负数二进制表示


正数对应的反码

反码加1,取得补码

补码就是负数的二进制表示



2.base64编码表



索引

对应字符

索引

对应字符

索引

对应字符

索引

对应字符
0

A
17

R
34

i
51

z
1

B
18

S
35

j
52

0
2

C
19

T
36

k
53

1
3

D
20

U
37

l
54

2
4

E
21

V
38

m
55

3
5

F
22

W
39

n
56

4
6

G
23

X
40

o
57

5
7

H
24

Y
41

p
58

6
8

I
25

Z
42

q
59

7
9

J
26

a
43

r
60

8
10

K
27

b
44

s
61

9
11

L
28

c
45

t
62

+
12

M
29

d
46

u
63

/
13

N
30

e
47

v
14

O
31

f
48

w
15

P
32

g
49

x
16

Q
33

h
50

y





加密代码 MD5




+ Base64


package com.ams.lms.util;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import sun.misc.BASE64Encoder;

@SuppressWarnings("restriction")
public class MD5Util {

	/**
	 * 利用MD5进行加密
	 * 
	 * @param str
	 *            待加密的字符串
	 * @return 加密后的字符串
	 * @throws NoSuchAlgorithmException
	 * @throws UnsupportedEncodingException
	 */
	public static String EncoderByMd5(String str) {
		if (str == null) {
			return null;
		}
		try {
			// 确定计算方法
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			BASE64Encoder base64en = new BASE64Encoder();
			// 加密后的字符串
			return base64en.encode(md5.digest(str.getBytes("utf-8")));
		} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
			return null;
		}
	}
}



2021/09/06  追记1 問題 :MD5不是16进制文本

为什么要先MD5,再用Base64进行加密

使用Java生成的MD5的值,和我们期待的不太一样,并不是十六进制组成的文本。

有特殊字符,造成无法正常的网络传输。



===


追记1问题   (2022/05/06)解决 :可以转换为16进制文本

package com.sxz.common.utils;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class GetMD5Info {
	
	public static void main (String[] args) {
		
		System.out.println(EncoderByMd5("123"));		
		
	}
	
	public static String EncoderByMd5(String str) {
		if (str == null) {
			return null;
		}
		
		String strMD5 = "";
		
		
		try {
			// 确定计算方法
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			// 加密后的字符串
			byte[] bytes = md5.digest(str.getBytes("utf-8"));
			
			strMD5 = String.format("%032x", new BigInteger(1, bytes));
			
		} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
			return null;
		}

		
		return strMD5;
	}
	
}

得到的结果是

202cb962ac59075b964b07152d234b70




计算文件哈希值的的代码 (自定义)

===

import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.FileInputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;

@Slf4j
public class SHA1 {

    protected static char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E','F' };

    /**
     * @Description: 计算SHA1码
     * @Param file
     * @Return java.lang.String
     * @Author Menglong.Cao
     * @Date 2022/3/1 16:43
     */
    public static String generate(File file){
        try{
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
            FileInputStream in = new FileInputStream(file);
            FileChannel ch = in.getChannel();
            MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY,0,file.length());
            messageDigest.update(byteBuffer);
            return bufferToHex(messageDigest.digest());
        }catch (Exception e){
            log.warn("generate-hash-fail:errorMessage={},{}",e.getMessage(),e);
        }
        return null;

    }

    private static String bufferToHex(byte bytes[]){
        return bufferToHex(bytes,0,bytes.length);
    }

    private static String bufferToHex(byte bytes[],int m,int n){
        StringBuffer stringBuffer = new StringBuffer(2*n);
        int k = m + n;
        for(int l = m; l < k; l++){
            appendHexPair(bytes[l],stringBuffer);
        }
        return stringBuffer.toString();
    }

    private static void appendHexPair(byte bt, StringBuffer stringBuffer){
        char c0 = hexDigits[(bt & 0xf0) >> 4];
        char c1 = hexDigits[bt & 0xf];
        stringBuffer.append(c0);
        stringBuffer.append(c1);
    }

    //测试
    public static void main(String[] args) throws Exception{
        System.out.println("begin...");
        long begin = System.currentTimeMillis();
        File file2 = new File("D:\\计算hash.txt");
        String sha1 = SHA1.generate(file2);
        System.out.println("文件hash:"+sha1);// 82C189E0D231901FFC0597401F75CB54F44331A8
        System.out.println("耗时:"+(System.currentTimeMillis()-begin)+"ms");
        System.out.println("end...");
    }

}

—-

■生成文件的MD5值 (代码完全正确)

代码 (使用ERMaster的Jar作为示例)

package com.sxz.study.algorithm;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class TestMD5File {

	public static void main(String[] args) {
		
		
		String md5str = getMD5Three("C:\\eclipse\\下载的plugin\\ERMaster\\org.insightech.er_1.0.0.v20150619-0219.jar");
		System.out.println(md5str);

	}
	
	public static String getMD5Three(String path) {
	     BigInteger bi = null;
	      try {
	          byte[] buffer = new byte[8192];
	          int len = 0;
	          MessageDigest md = MessageDigest.getInstance("MD5");
	          File f = new File(path);
	          FileInputStream fis = new FileInputStream(f);
	          while ((len = fis.read(buffer)) != -1) {
	             md.update(buffer, 0, len);
	          }
	             fis.close();
	             byte[] b = md.digest();
	             bi = new BigInteger(1, b);
	      } catch (NoSuchAlgorithmException e) {
	            e.printStackTrace();
	      } catch (IOException e) {
	             e.printStackTrace();
	         }
	         

            // 下面代码有BUG,当MD5的Hash值,第一位是0是,第一位会被省略。
            // return bi.toString(16);

            // 使用下面代码解决bug (MD5的值,是一个32位长度的字符串)
            String md5Str = bi.toString(16);
            String md5StrFormat = md5Str.format("%32s", mdtStr); // 不足32位,前面补空格
            String result= md5StrFormat.replace(" ", "0"); // 把空格替换成0

            String result.toUpperCase();
            
	     }
	

}

代码运行结果

PowerShell生成的MD5  (完全相同)

Get-FileHash -Algorithm MD5 .\org.insightech.er_1.0.0.v20150619-0219.jar | Format-list

==



版权声明:本文为sxzlc原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。