【JAVA】MANIFEST.MF / CERT.SF 中 文件SHA1-Digest计算方法

前言: 给旧手机刷机,rom.zip 直接解压魔改,完后再压缩为zip刷入手机。其间遇到了 MANIFEST.MF / CERT.SF 这两个文件,看看是怎么回事吧。

MANIFEST.MF

Manifest-Version: 1.0
Created-By: 1.0 (Android SignApk)
...
Name: system/app/webview/webview.apk
SHA1-Digest: zjehQbk00n2eu+YoBb1LZdieREo=

CERT.SF

Name: system/app/webview/webview.apk
SHA1-Digest: fH0N47kRuw8L0flpR4GW0c3mq58=

这两个SHA1是怎么计算的呢?很简单:

为 MANIFEST.MF 计算 SHA1

直接从文件摘录SHA1,结果为字节数组,将这个字节数组用Java自带的base64编码器编码一下,结果仍然为字节数组,最后从此字节数组构建字符串,即为Android SignApkMANIFEST.MF生成的SHA摘要。
代码:

@Test
public void toSHA1() throws IOException {
	byte[] dig = Digest_SHA1(new FileInputStream("C:\\Users\\TEST\\Desktop\\desktop\\ceshi\\7to-cm13-christer12-bo1318\\system\\priv-app\\InputDevices\\InputDevices.apk"));
	dig = Digest_SHA1(new FileInputStream("C:\\Users\\TEST\\Desktop\\desktop\\ceshi\\7to-cm13-christer12-bo1318\\system/app/webview/webview.apk"));

	CMN.Log(new String(Base64.getEncoder().encode(dig)));
}

byte[] Digest_SHA1(InputStream input) {
	 try (InputStream data_in = input){
		 MessageDigest digest =MessageDigest.getInstance("SHA");
		 byte[] buffer = new byte[4096];
		 int len;
		 while((len=data_in.read(buffer))>=0) {
			 digest.update(buffer, 0, len);
		 }
		 return digest.digest();
	 } catch (NoSuchAlgorithmException | IOException e) {
		 CMN.Log(e);
	 }
	 return ArrayUtils.EMPTY_BYTE_ARRAY;
}

为 CERT.SF 计算 SHA1

和上面同一个流程,只不过第一步从文件获取摘要变成了从字节数组获取摘要:

dig=Digest_SHA1(new ByteArrayInputStream("Name: system/app/webview/webview.apk\r\nSHA1-Digest: zjehQbk00n2eu+YoBb1LZdieREo=\r\n\r\n".getBytes()));
CMN.Log(new String(Base64.getEncoder().encode(dig)));

也就是说从以下MANIFETS.MF中的文本获取摘要:

Name: system/app/webview/webview.apk(\r\n换行)
SHA1-Digest: zjehQbk00n2eu+YoBb1LZdieREo=(\r\n换行)
(\r\n换行)

The End

完整代码

package test.privateTest.DebugBuilder;

import org.apache.commons.lang.ArrayUtils;
import org.junit.Test;
import test.CMN;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class SHA_Android_Manifest_Test {
	@Test
	public void test() throws IOException {
		String name="system/priv-app/InputDevices/InputDevices.apk";
		name="system/app/webview/webview.apk";

		byte[] dig = Digest_SHA1(new FileInputStream("C:\\Users\\TEST\\Desktop\\desktop\\ceshi\\7to-cm13-christer12-bo1318\\"+name));

		String digStr = new String(Base64.getEncoder().encode(dig), StandardCharsets.UTF_8);
		CMN.Log(digStr);

		dig=Digest_SHA1(new ByteArrayInputStream(("Name: "+name+"\r\nSHA1-Digest: "+digStr+"\r\n\r\n").getBytes()));
		CMN.Log(new String(Base64.getEncoder().encode(dig)));
	}

	private String BytesToHexString(byte[] value) {
		StringBuilder hexValue = new StringBuilder(value.length*2);
		for (byte b : value) {
			int val = ((int) b) & 0xff;
			if (val < 16) {
				hexValue.append("0");
			}
			hexValue.append(Integer.toHexString(val).toUpperCase());
		}
		return hexValue.toString();
	}

	private byte[] HexStringToBytes(String value) {
		byte[] ret = new byte[value.length()/2];
		for (int i = 0; i < ret.length; i++) {
			ret[i] = (byte) Integer.parseInt(value.substring(i*2, i*2+2), 16);
		}
		return ret;
	}

	byte[] Digest_SHA1(InputStream input) {
		try (InputStream data_in = input){
			MessageDigest digest =MessageDigest.getInstance("SHA");
			byte[] buffer = new byte[4096];
			int len;
			while((len=data_in.read(buffer))>=0) {
				digest.update(buffer, 0, len);
			}
			return digest.digest();
		} catch (NoSuchAlgorithmException | IOException e) {
			CMN.Log(e);
		}
		return ArrayUtils.EMPTY_BYTE_ARRAY;
	}
}

上一篇:【安全算法之SHA256】SHA256摘要运算的C语言源码实现


下一篇:OpenSSL数字签名实验