Java 8与OpenJDK 17的HMAC哈希值差异问题及解决方案
文件HMAC哈希跨Java版本一致性问题解决
我在实现通过对比文件HMAC哈希值验证文件完整性的功能时发现:Java 8(IBM J9 VM)与OpenJDK 17环境下,文本文件的哈希值一致,但xlsx这类非文本文件的哈希值存在差异。以下是问题代码、修正后的可行代码及不同版本的输出结果:
问题代码
import java.io.File; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.SystemUtils; @Slf4j public class TestHashing { private static String HMACH_KEY = "some_key"; private static String generateHMACHash(String message) { if (message == null) { message = ""; } Mac sha256HMAC = null; try { sha256HMAC = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKeySpec = new SecretKeySpec(HMACH_KEY.getBytes(), "HmacSHA256"); sha256HMAC.init(secretKeySpec); } catch (NoSuchAlgorithmException | InvalidKeyException e) { log.debug("Getting Exception in Hashing ", e.getMessage()); e.printStackTrace(); } return Base64.encodeBase64String(sha256HMAC.doFinal(message.toUpperCase().getBytes())); } public static void main(String[] args) throws IOException { String version = SystemUtils.JAVA_SPECIFICATION_VERSION; System.out.println("Java Virtual Machine specification version : " + System.getProperty("java.vm.specification.version")); System.out.println("Java Virtual Machine specification vendor : " + System.getProperty("java.vm.specification.vendor")); System.out.println("Java Virtual Machine specification name : " + System.getProperty("java.vm.specification.name")); System.out.println("Java Virtual Machine implementation version : " + System.getProperty("java.vm.version")); System.out.println("Java Virtual Machine implementation vendor : " + System.getProperty("java.vm.vendor")); System.out.println("Java Virtual Machine implementation name : " + System.getProperty("java.vm.name")); String fileName = "C:\\test\\fileTest.txt"; File file = new File(fileName); String data = FileUtils.readFileToString(file, "UTF-8"); String output = generateHMACHash(data); System.out.println(fileName + " FILE USING JAVA VERSION" + version); System.out.println(output); fileName = "C:\\test\\fileTest.xlsx"; file = new File(fileName); data = FileUtils.readFileToString(file, "UTF-8"); output = generateHMACHash(data); System.out.println(fileName + " FILE USING JAVA VERSION" + version); System.out.println(output); } }
修正后的可行代码
private static String generateHMACHash(File file) throws Exception { Mac sha256HMAC = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKeySpec = new SecretKeySpec(HMACH_KEY.getBytes(), "HmacSHA256"); sha256HMAC.init(secretKeySpec); // 获取文件输入流读取文件内容 FileInputStream fis = new FileInputStream(file); // 创建字节数组以分块读取数据 byte[] byteArray = new byte[1024]; int bytesCount = 0; // 读取文件数据并更新消息摘要 while ((bytesCount = fis.read(byteArray)) != -1) { sha256HMAC.update(byteArray, 0, bytesCount); } // 关闭输入流 fis.close(); // 存储doFinal()方法返回的字节 byte[] bytes = sha256HMAC.doFinal(); // 将字节数组转换为十六进制字符串 StringBuilder sb = new StringBuilder(); // 遍历字节数组 for (int i = 0; i < bytes.length; i++) { // 将十进制字节转换为十六进制并追加到StringBuilder sb.append(Integer .toString((bytes[i] & 0xff) + 0x100, 16) .substring(1)); } // 返回完整哈希值 return sb.toString(); }
不同Java版本输出结果
OpenJDK 17输出
Java虚拟机规范版本: 17 Java虚拟机规范厂商: Oracle Corporation Java虚拟机规范名称: Java Virtual Machine Specification Java虚拟机实现版本: 17.0.7+7 Java虚拟机实现厂商: Eclipse Adoptium Java虚拟机实现名称: OpenJDK 64-Bit Server VM C:\test\fileTest.txt 文件使用Java版本17 VfhDrMk6e8t2bdKM0r+AeCfBA+iYNAKmBDhkvocMcpU= C:\test\fileTest.xlsx 文件使用Java版本17 vPR0xPL0dIQgrYpSN/JJELMjFm90JoM0LqAeKL+2Yfo=
Java 8(IBM J9 VM)输出
Java虚拟机规范版本: 1.8 Java虚拟机规范厂商: Oracle Corporation Java虚拟机规范名称: Java Virtual Machine Specification Java虚拟机实现版本: 2.9 Java虚拟机实现厂商: IBM Corporation Java虚拟机实现名称: IBM J9 VM C:\test\fileTest.txt 文件使用Java版本1.8 VfhDrMk6e8t2bdKM0r+AeCfBA+iYNAKmBDhkvocMcpU= C:\test\fileTest.xlsx 文件使用Java版本1.8 n5Fb6b34VOnRUsGzYGcQn7vTAPNcLfg1zFoXJ2ZvM/w=
内容的提问来源于stack exchange,提问作者kvk95
相关产品推荐
相关产品推荐

