一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
作为 Java 程序员,我们在生活中受到哈希的轰炸。早期我们被介绍了该 hashCode()
方法,我们知道我们需要覆盖一些不可预见的坏事。后来我们被展示LinkedHashMap
和它的朋友。这些基于该hashCode()
方法来组织数据以进行快速检索。
在其他地方,我们有加密哈希函数。这些被到处使用。HTTPS 证书、Git 提交、BitTorrent 完整性检查和区块链块都使用加密哈希。良好地使用哈希可以提高应用程序的性能、隐私、安全性和简单性。
每个加密哈希函数都接受一个可变长度的输入字节流,并产生一个称为“哈希”的固定长度字节字符串值。哈希函数具有以下重要特性:
- 确定性:每个输入总是产生相同的输出。
- Uniform:每个输出字节串的可能性相同。很难找到或创建产生相同输出的不同输入对。这被称为“碰撞”。
- 不可逆:知道输出并不能帮助您找到输入。请注意,如果您知道一些可能的输入,您可以对它们进行散列以查看它们的散列是否匹配。
- 众所周知:哈希无处不在,并且被严格理解。
好的散列函数计算起来非常便宜(几十微秒),而反向计算起来很昂贵(几千亿)。计算和数学的稳步发展已经导致曾经伟大的哈希函数变得便宜。选择哈希函数时,请注意并非所有人都是平等的!Okio 支持这些著名的加密哈希函数:
- MD5:128 位(16 字节)加密哈希。它既不安全又过时,因为逆转成本很低!提供此哈希是因为它在对安全性不敏感的遗留系统中很流行且方便使用。
- SHA-1:160 位(20 字节)加密哈希。最近证明,创建 SHA-1 冲突是可行的。考虑从 SHA-1 升级到 SHA-256。
- SHA-256:256 位(32 字节)加密哈希。SHA-256 已广为人知,而且逆转成本高昂。这是大多数系统应该使用的哈希。
- SHA-512:512 位(64 字节)加密哈希。逆转是昂贵的。
每个哈希创建一个ByteString
指定长度的。用于hex()
获取常规的人类可读形式。或将其保留为 a ByteString
,因为这是一种方便的模型类型!
Okio 可以从字节字符串生成加密哈希:
ByteString byteString = readByteString(Path.get("README.md"));
System.out.println(" md5: " + byteString.md5().hex());
System.out.println(" sha1: " + byteString.sha1().hex());
System.out.println("sha256: " + byteString.sha256().hex());
System.out.println("sha512: " + byteString.sha512().hex());
從緩衝區:
Buffer buffer = readBuffer(Path.get("README.md"));
System.out.println(" md5: " + buffer.md5().hex());
System.out.println(" sha1: " + buffer.sha1().hex());
System.out.println("sha256: " + buffer.sha256().hex());
System.out.println("sha512: " + buffer.sha512().hex());
從源流式傳輸時:
try (HashingSink hashingSink = HashingSink.sha256(Okio.blackhole());
BufferedSource source = Okio.buffer(FileSystem.SYSTEM.source(path))) {
source.readAll(hashingSink);
System.out.println("sha256: " + hashingSink.hash().hex());
}
流式傳輸到接收器時:
try (HashingSink hashingSink = HashingSink.sha256(Okio.blackhole());
BufferedSink sink = Okio.buffer(hashingSink);
Source source = FileSystem.SYSTEM.source(path)) {
sink.writeAll(source);
sink.close();
// Emit anything buffered.
System.out.println("sha256: " + hashingSink.hash().hex());
}
Okio 還支持結合秘密和哈希的 HMAC(哈希消息驗證碼)。應用程序使用 HMAC 進行數據完整性和身份驗證。
ByteString secret = ByteString.decodeHex("7065616e7574627574746572");
System.out.println("hmacSha256: " + byteString.hmacSha256(secret).hex());
與散列一樣,您可以從ByteString
、Buffer
、HashingSource
和 生成 HMAC HashingSink
。請注意,Okio 沒有為 MD5 實現 HMAC。
在 Android 和 Java 上,Okio 將 Javajava.security.MessageDigest
用於加密哈希和 javax.crypto.Mac
HMAC。在其他平台上,Okio 使用自己優化的這些算法實現。