■
加密效果(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
==