SHA-256(Secure Hash Algorithm 256-bit)是一种密码散列函数,是美国国家安全局作为 SHA2 家族的一部分开发的加密散列算法。
对于任意长度的消息,SHA-256 都会产生一个 256 位(32 字节)的哈希值,称作消息摘要。这个摘要相当于是个长度为 32 个字节的数组,通常使用一个长度为 64 的十六进制字符串来表示,其中1个字节 = 8位,使用两个十六进制的字符进行表示。例如:
hello world
加密后:
b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
输出长度固定:生成一个 256 位(32 字节)的哈希值。无论输入数据的大小如何,输出的哈希值长度始终保持不变。
不可逆性:由原始数据计算出 SHA-256 哈希值相对容易,但根据哈希值反推出原始数据在计算上是不可行的。
确定性:对于相同的输入,总是产生相同的哈希值。只要输入数据没有改变,每次计算得到的哈希值都是完全一致的。
抗碰撞性:很难找到两个不同的输入数据,使得它们的 SHA-256 哈希值相同。这种抗碰撞性是密码散列函数的重要安全特性之一。
密码存储:在用户密码存储系统中,通常不会直接存储用户的明文密码,而是存储密码的 SHA-256 哈希值。当用户登录时,系统计算用户输入密码的哈希值,并与存储的哈希值进行比较,以验证用户的身份。
数字签名:用于生成数字签名的一部分,确保数据的完整性和真实性。通过对数据进行 SHA-256 哈希计算,然后使用私钥对哈希值进行加密,形成数字签名。接收方可以使用公钥解密数字签名,并对数据进行 SHA-256 哈希计算,以验证数据是否被篡改。
区块链:在区块链技术中,SHA-256 被广泛用于计算区块的哈希值。每个区块包含前一个区块的哈希值,这样就形成了一个链式结构。通过 SHA-256 的抗碰撞性和不可逆性,保证了区块链的完整性和不可篡改。
文件完整性校验:在文件传输、下载或存储过程中,可以使用 SHA-256 计算文件的哈希值。接收方可以通过计算接收到的文件的哈希值,并与发送方提供的哈希值进行比较,来验证文件是否在传输过程中被篡改。
虽然 SHA-256 拥有众多优点,但还是具有以下一些相对的缺点或局限性:
性能较低:与一些其他哈希算法(如 MD5)相比,SHA-256 的计算速度较慢,执行哈希计算需要更多的时间和计算资源。在对性能要求极高的场景中,可能会对系统的整体效率产生一定影响。
内存占用较大:在某些特定的应用场景中,尤其是需要处理大量数据时,SHA-256 可能需要占用较多的内存来存储中间结果和进行计算,这可能会对硬件资源有限的设备或系统造成压力。
长度扩展攻击风险:虽然 SHA-256 本身具有较高的安全性,但它属于 Merkle-Damgård 结构的哈希函数,存在长度扩展攻击的理论可能性。尽管在实际应用中这种攻击可能并不容易实现,但它仍然是一种潜在的安全风险。比特币使用双 SHA-256 (即 SHA-256 (SHA-256 (value)) )就是为了抵御这种长度扩展攻击。
不适合某些特定场景:例如在一些对计算资源和存储资源极度受限的嵌入式系统或物联网设备中,SHA-256 的性能和资源占用可能不太适合,需要寻找更轻量级的哈希算法。
以下是用 Java 实现 SHA-256 哈希算法的示例代码:
package com.hxstrive.encryption_decryption.sha2; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class SHA256Example { public static String sha256(String input) { try { MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] hash = md.digest(input.getBytes()); StringBuilder hexString = new StringBuilder(); for (byte b : hash) { String hex = Integer.toHexString(0xff & b); if (hex.length() == 1) { hexString.append('0'); } hexString.append(hex); } return hexString.toString(); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } public static void main(String[] args) { String input = "Hello, World!"; String hash = sha256(input); System.out.println("SHA-256 哈希值: " + hash); //SHA-256 哈希值: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f } }
在上述代码中,定义了一个sha256方法,该方法使用MessageDigest类获取 SHA-256 消息摘要对象,对输入字符串进行哈希计算,并将结果转换为十六进制字符串返回。
读取文件并计算其 SHA-256 哈希值,代码如下:
package com.hxstrive.encryption_decryption.sha2; import java.io.FileInputStream; import java.io.IOException; import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class SHA256FileHashExample { public static String calculateFileHash(String filePath) { try (FileInputStream fis = new FileInputStream(filePath); DigestInputStream dis = new DigestInputStream(fis, MessageDigest.getInstance("SHA-256"))) { byte[] buffer = new byte[8192]; while (dis.read(buffer)!= -1) { // Just reading to update the digest } MessageDigest digest = dis.getMessageDigest(); byte[] hashBytes = digest.digest(); StringBuilder hexString = new StringBuilder(); for (byte b : hashBytes) { String hex = Integer.toHexString(0xff & b); if (hex.length() == 1) { hexString.append('0'); } hexString.append(hex); } return hexString.toString(); } catch (NoSuchAlgorithmException | IOException e) { e.printStackTrace(); return null; } } public static void main(String[] args) { String filePath = "E:\\demo_encryption_decryption\\src\\main\\resources\\file.txt"; String hash = calculateFileHash(filePath); if (hash!= null) { System.out.println("File SHA-256 hash: " + hash); //File SHA-256 hash: b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 } } }