java.security.MessageDigest
MessageDigest的含义
message含义是:消息,信息
digest的含义是
digest
必应词典
n.摘要;文摘;概要;汇编
v.消化;领会;领悟;理解
海词
n. 摘要
vt. 消化;理解
vi. 消化
金山词霸
v.
消化; 理解
n.
摘要; 文摘
有道
v.
理解,领悟;消化
n.
文摘,摘要;分解物,提炼物
所以 MessageDigest 可以理解为 消息消化
额,不是.
应该是 信息摘要 或 数据摘要
它能将很大的信息(数据)(文件)通过某种算法(algorithm),简化为简短的内容, 用于判断大数据是否相同.
动态获取 MessageDigest 所支持的算法名称
java.security.Security.getAlgorithms("MessageDigest");
可获得算法名称的Set<String>集合 , 参数为"MessageDigest",不区分大小写
java.util.Set<String> messageDigest_AlgorithmNames_Set = java.security.Security.getAlgorithms("MessageDigest"); //不区分大小写
java.util.Set<String> messageDigest_AlgorithmNames_Set = java.security.Security.getAlgorithms("messagedigest"); //不区分大小写
示例
public class Try动态获取MessageDigest支持的算法名称列表 {
static Integer numA = 1;
static public void main(String...arguments)throws Exception{
java.util.Set<String> messageDigest_AlgorithmNames_Set = java.security.Security.getAlgorithms("messagedigest");
// java.util.Set<String> messageDigest_AlgorithmNames_Set = java.security.Security.getAlgorithms("MessageDigest");
System.out.println("MessageDigest的算法种类个数为: "+messageDigest_AlgorithmNames_Set.size() + " , 分别为👇");
messageDigest_AlgorithmNames_Set.forEach(算法名称->{
System.out.println(numA+++".\t\t"+算法名称);
});
}
}
控制台输出👇 (JDK17)
MessageDigest的算法种类个数为: 13 , 分别为👇
1. SHA3-512
2. SHA-1
3. SHA-384
4. SHA3-384
5. SHA-224
6. SHA-512/256
7. SHA-256
8. MD2
9. SHA-512/224
10. SHA3-256
11. SHA-512
12. MD5
13. SHA3-224
获取 MessageDigest 的实例
MessageDigest 的实例由 MessageDigest.getInstance(x)
方法获得;
一个MessageDigest实例只能指定一种算法;
MessageDigest md_SHA3512 = MessageDigest.getInstance("SHA3-512");
MessageDigest md_SHA1 = MessageDigest.getInstance("SHA-1");
MessageDigest md_SHA384 = MessageDigest.getInstance("SHA-384");
MessageDigest md_SHA3384 = MessageDigest.getInstance("SHA3-384");
MessageDigest md_SHA224 = MessageDigest.getInstance("SHA-224");
MessageDigest md_SHA512256 = MessageDigest.getInstance("SHA-512/256");
MessageDigest md_SHA256 = MessageDigest.getInstance("SHA-256");
MessageDigest md_MD2 = MessageDigest.getInstance("MD2");
MessageDigest md_SHA512224 = MessageDigest.getInstance("SHA-512/224");
MessageDigest md_SHA3256 = MessageDigest.getInstance("SHA3-256");
MessageDigest md_SHA512 = MessageDigest.getInstance("SHA-512");
MessageDigest md_MD5 = MessageDigest.getInstance("MD5");
MessageDigest md_SHA3224 = MessageDigest.getInstance("SHA3-224");
将byte数组计算为Hash
MessageDigest 通过 update
和 digest
方法, 将一个或多个byte[]数组计算为Hash摘要
digest(byte[] input)
是一步到位的方法, 直接计算出input数组的Hash, 但是有一个问题, 数组索引是int, int<=Integer.MAX; 大概2G多, 所以对很大的文件无能为力.
digest(byte[] input) 的源码👇
public byte[] digest(byte[] input) {
update(input);
return digest();
}
可看出也是分为两步, 第一步是update(input), 将数组放入MessageDigest,
让后再digest()计算.
实际上update方法可以多次调用,
所以可以将大文件用缓存数组buffer拆分成多段用update放入
而且update有个现成的重载:update(byte[] input, int offset, int len)
示例
FileInputStream is = new FileInputStream(pathStr);
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] bf = new byte[10240];
int numRead;
do {
numRead = is.read(bf);
if (numRead > 0) {
digest.update(bf, 0, numRead);
}
} while (numRead != -1);
is.close();
byte[] resultByteArray = digest.digest();
得到的结果还是byte数组, 可将其转为16进制
将digest的结果数组转为16进制
假设已得到结果: resultByteArray
将其转为16进制的办法
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(String.format("%02x", bytes[i]));
}
return sb.toString();
}
String resultHex = bytesToHex(resultByteArray)
小写
public static String hexLowerCaseFromByteArray(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789abcdef";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt((b&0xff)>>>4)).append(simple.charAt(b<<28>>>28));
}
return sb.toString();
}
String resultHex = bytesToHex(resultByteArray)
大写
public static String hexUpperCaseFromByteArray(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789ABCDEF";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt((b&0xff)>>>4)).append(simple.charAt(b<<28>>>28));
}
return sb.toString();
}
String resultHex = bytesToHex(resultByteArray)
public static String hexLowerCaseFromByteArray2(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789abcdef";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt((b&0xff)/16)).append(simple.charAt((b&0xff)%16));
}
return sb.toString();
}
public static String hexUpperCaseFromByteArray2(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789ABCDEF";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt((b&0xff)/16)).append(simple.charAt((b&0xff)%16));
}
return sb.toString();
}
public static String hexLowerCaseFromByteArray3(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789abcdef";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt((b&255)/16)).append(simple.charAt((b&255)%16));
}
return sb.toString();
}
public static String hexUpperCaseFromByteArray3(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789ABCDEF";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt((b&255)/16)).append(simple.charAt((b&255)%16));
}
return sb.toString();
}
public static String hexLowerCaseFromByteArray4(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789abcdef";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
int i=b>=0?b:b+256;
sb.append(simple.charAt(i/16)).append(simple.charAt(i%16));
}
return sb.toString();
}
public static String hexUpperCaseFromByteArray4(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789ABCDEF";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
int i=b>=0?b:b+256;
sb.append(simple.charAt(i/16)).append(simple.charAt(i%16));
}
return sb.toString();
}
public static String hexLowerCaseFromByteArray5(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789abcdef";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt(Byte.toUnsignedInt(b)/16)).append(simple.charAt(Byte.toUnsignedInt(b)%16));
}
return sb.toString();
}
public static String hexUpperCaseFromByteArray5(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789ABCDEF";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt(Byte.toUnsignedInt(b)/16)).append(simple.charAt(Byte.toUnsignedInt(b)%16));
}
return sb.toString();
}
测试
package 将byte数组转为16进制字符串的方法;
import java.awt.FileDialog;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.FileInputStream;
import java.security.MessageDigest;
import javax.swing.JFrame;
public class ByteArrayToHexString {
public static String hexLowerCaseFromByteArray(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789abcdef";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt((b&0xff)>>>4)).append(simple.charAt(b<<28>>>28));
}
return sb.toString();
}
public static String hexUpperCaseFromByteArray(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789ABCDEF";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt((b&0xff)>>>4)).append(simple.charAt(b<<28>>>28));
}
return sb.toString();
}
public static String hexLowerCaseFromByteArray2(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789abcdef";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt((b&0xff)/16)).append(simple.charAt((b&0xff)%16));
}
return sb.toString();
}
public static String hexUpperCaseFromByteArray2(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789ABCDEF";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt((b&0xff)/16)).append(simple.charAt((b&0xff)%16));
}
return sb.toString();
}
public static String hexLowerCaseFromByteArray3(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789abcdef";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt((b&255)/16)).append(simple.charAt((b&255)%16));
}
return sb.toString();
}
public static String hexUpperCaseFromByteArray3(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789ABCDEF";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt((b&255)/16)).append(simple.charAt((b&255)%16));
}
return sb.toString();
}
public static String hexLowerCaseFromByteArray4(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789abcdef";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
int i=b>=0?b:b+256;
sb.append(simple.charAt(i/16)).append(simple.charAt(i%16));
}
return sb.toString();
}
public static String hexUpperCaseFromByteArray4(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789ABCDEF";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
int i=b>=0?b:b+256;
sb.append(simple.charAt(i/16)).append(simple.charAt(i%16));
}
return sb.toString();
}
public static String hexLowerCaseFromByteArray5(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789abcdef";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt(Byte.toUnsignedInt(b)/16)).append(simple.charAt(Byte.toUnsignedInt(b)%16));
}
return sb.toString();
}
public static String hexUpperCaseFromByteArray5(byte[] byteArray) {
if(byteArray==null)return null;
String simple = "0123456789ABCDEF";
StringBuilder sb = new StringBuilder(byteArray.length*2);
for(byte b : byteArray) {
sb.append(simple.charAt(Byte.toUnsignedInt(b)/16)).append(simple.charAt(Byte.toUnsignedInt(b)%16));
}
return sb.toString();
}
public static String hexLowerCaseFromByteArray6(byte[] byteArray) {
if(byteArray==null)return null;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < byteArray.length; i++) {
sb.append(String.format("%02x", byteArray[i]));
}
return sb.toString();
}
public static void main(String...arguments)throws Exception{
JFrame frame = new JFrame(Thread.currentThread().getStackTrace()[1].getClassName());
frame.addWindowListener(new WindowAdapter() {
@Override public void windowClosing(WindowEvent ev) {System.exit(0);}
});
FileDialog fDialog = new FileDialog(frame);
fDialog.setVisible(true);
if(fDialog.getFile()!=null) {
String pathFile = fDialog.getDirectory()+fDialog.getFile();
FileInputStream is = new FileInputStream(pathFile);
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] bf = new byte[10240];
int numRead;
do {
numRead = is.read(bf);
if (numRead > 0) {
digest.update(bf, 0, numRead);
}
} while (numRead != -1);
is.close();
byte[] resultByteArray = digest.digest();
String result;
result = hexLowerCaseFromByteArray(resultByteArray); System.out.println(result);
result = hexUpperCaseFromByteArray(resultByteArray); System.out.println(result);
result = hexLowerCaseFromByteArray2(resultByteArray); System.out.println(result);
result = hexUpperCaseFromByteArray2(resultByteArray); System.out.println(result);
result = hexLowerCaseFromByteArray3(resultByteArray); System.out.println(result);
result = hexUpperCaseFromByteArray3(resultByteArray); System.out.println(result);
result = hexLowerCaseFromByteArray4(resultByteArray); System.out.println(result);
result = hexUpperCaseFromByteArray4(resultByteArray); System.out.println(result);
result = hexLowerCaseFromByteArray5(resultByteArray); System.out.println(result);
result = hexUpperCaseFromByteArray5(resultByteArray); System.out.println(result);
result = hexLowerCaseFromByteArray6(resultByteArray); System.out.println(result);
}
System.exit(0);
}
}
一些应用例子
例1
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.FileInputStream;
import java.security.MessageDigest;
import java.util.*;
import javax.swing.*;
//import javax.swing.JButton;
public class SHA_MD_MessageDigest_230528 extends Frame{
/**
*
*/
private static final long serialVersionUID = 5242216018207119189L;
static void pln(Object o) {System.out.println(o);}
public final SHA_MD_MessageDigest_230528 I;
public final TextArea resultLowercaseShow = new TextArea("这里展示小写结果");
public final TextArea resultUppercaseShow = new TextArea("这里展示大写结果");
public final HashMap<String, MessageDigest> DigestGroup = new HashMap<>();
public final LinkedHashMap<String, Panel> ButtonForComputedGroup = new LinkedHashMap<>();
{
Set<String> set = java.security.Security.getAlgorithms("MessageDigest"); //获得支持的格式
ArrayList<String> nmAl = new ArrayList<>(set);
nmAl.sort((o1,o2)->o1.compareTo(o2));
try {
for(String nm : set) {
DigestGroup.put(nm, MessageDigest.getInstance(nm));
}
nmAl.forEach(nm->{
ButtonForComputedGroup.put(nm, new Btn(nm));
});
}catch(Exception ex) {ex.printStackTrace();}
}
//constructor 构造方法在此
public SHA_MD_MessageDigest_230528() {
I=this;
setTitle("文件校验, 点击按钮选择文件 ");
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
I.dispose();
System.exit(0);
}
});
setLayout(new GridLayout(3, 0, 1, 3));
Panel up = new Panel(); add(up); up.setBackground(Color.DARK_GRAY);
Panel panel010 = new Panel(); add(panel010);
// Panel panel020 = new Panel(); add(panel020);
JPanel panel020 = new JPanel(); add(panel020);
ButtonForComputedGroup.forEach((lb,btn)->{
up.add(btn);
});
panel010.setLayout(new BorderLayout(200,200));
panel010.add(resultLowercaseShow);
System.out.println(panel020.getLayout());
panel020.setLayout(new BorderLayout());
panel020.add(resultUppercaseShow);
setBounds(258, 235, 1600, 666);
setVisible(true);
// show();
}
public static void main(String ags[]) {new SHA_MD_MessageDigest_230528();}
void computed(String nm) {
pln(nm);
String lowercaseMapping = "0123456789abcdef" , uppercaseMapping = lowercaseMapping.toUpperCase();
FileDialog fileDialog = new FileDialog(this, "选择要生成Hash的文件", FileDialog.LOAD);
fileDialog.setVisible(true);
String directoryStr = fileDialog.getDirectory() , fileStr = fileDialog.getFile();
if(directoryStr!=null && fileStr!=null) {
try {
String pathStr = directoryStr+fileStr;
resultLowercaseShow.setText("正在计算 "+pathStr+" 的"+nm+"值");
FileInputStream is = new FileInputStream(pathStr);
MessageDigest digest = DigestGroup.get(nm);
byte[] bf = new byte[10240];
int numRead;
do {
numRead = is.read(bf);
if (numRead > 0) {
digest.update(bf, 0, numRead);
}
} while (numRead != -1);
is.close();
bf = digest.digest();
StringBuilder sb = new StringBuilder(bf.length*2);
for(byte b : bf) {
int idx1=(b&0xff)>>>4 , idx2=b<<28>>>28;
pln("idx1="+idx1+" idx2="+idx2);
sb.append(lowercaseMapping.charAt(idx1)).append(lowercaseMapping.charAt(idx2));
}
String hexLower = sb.toString();
resultLowercaseShow.setText(hexLower);
sb = new StringBuilder(bf.length*2);
for(byte b : bf) {
int idx1=(b&0xff)>>>4 , idx2=b<<28>>>28;
pln("idx1="+idx1+" idx2="+idx2);
sb.append(uppercaseMapping.charAt(idx1)).append(uppercaseMapping.charAt(idx2));
}
String hexUpper = sb.toString();
resultUppercaseShow.setText(hexUpper);
}catch(Throwable ex) {ex.printStackTrace(); resultLowercaseShow.setText(ex.toString()); }
}
}
class Btn extends Panel{
/**
* 镶嵌在Panel中的Button
*/
private static final long serialVersionUID = -3494086542207800072L;
public final Button btn;
Btn(String label){
super();
this.setBackground(Color.blue);
// setLayout(new BorderLayout());
setLayout(null);
setSize(210,60);
btn = new Button(label);
switch (label) {
case"MD5","SHA-256": btn.setForeground(Color.BLUE); break;
case"SHA-512": btn.setForeground(Color.WHITE);btn.setBackground(new Color(0,168,255)); break;
}
btn.setBounds(5, 5, 200, 50);
setFont(new Font("宋体", Font.CENTER_BASELINE, 25));
btn.addActionListener(ev->{
computed(btn.getActionCommand());
});
add(btn);
}
}
}