Change verity hash algorithm to pad the last chunk
As the result, all existing cases takes complete chunk for hashing.
Also bump to version number.
Test: without also bumping the version, apk with 0x401 hash won't install
Test: apk with 0x411 hash installs
Bug: 30972906
Change-Id: I48c15c886ac6eab4512f1b2b9744b07e746c6211
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index 4146f6f..40db758 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -373,9 +373,9 @@
static final int SIGNATURE_ECDSA_WITH_SHA256 = 0x0201;
static final int SIGNATURE_ECDSA_WITH_SHA512 = 0x0202;
static final int SIGNATURE_DSA_WITH_SHA256 = 0x0301;
- static final int SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256 = 0x0401;
- static final int SIGNATURE_VERITY_ECDSA_WITH_SHA256 = 0x0403;
- static final int SIGNATURE_VERITY_DSA_WITH_SHA256 = 0x0405;
+ static final int SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256 = 0x0411;
+ static final int SIGNATURE_VERITY_ECDSA_WITH_SHA256 = 0x0413;
+ static final int SIGNATURE_VERITY_DSA_WITH_SHA256 = 0x0415;
static final int CONTENT_DIGEST_CHUNKED_SHA256 = 1;
static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2;
@@ -754,9 +754,6 @@
md.update(buffer);
}
}
-
- @Override
- public void finish() {}
}
}
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
index a3eeb27..7b89967 100644
--- a/core/java/android/util/apk/ApkVerityBuilder.java
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -207,14 +207,10 @@
}
}
- /** Finish the current digestion if any. */
- @Override
- public void finish() throws DigestException {
- if (mBytesDigestedSinceReset == 0) {
- return;
+ public void assertEmptyBuffer() throws DigestException {
+ if (mBytesDigestedSinceReset != 0) {
+ throw new IllegalStateException("Buffer is not empty: " + mBytesDigestedSinceReset);
}
- mMd.digest(mDigestBuffer, 0, mDigestBuffer.length);
- mOutput.put(mDigestBuffer);
}
private void fillUpLastOutputChunk() {
@@ -279,9 +275,15 @@
new MemoryMappedFileDataSource(apk.getFD(), offsetAfterEocdCdOffsetField,
apk.length() - offsetAfterEocdCdOffsetField),
MMAP_REGION_SIZE_BYTES);
- digester.finish();
- // 5. Fill up the rest of buffer with 0s.
+ // 5. Pad 0s up to the nearest 4096-byte block before hashing.
+ int lastIncompleteChunkSize = (int) (apk.length() % CHUNK_SIZE_BYTES);
+ if (lastIncompleteChunkSize != 0) {
+ digester.consume(ByteBuffer.allocate(CHUNK_SIZE_BYTES - lastIncompleteChunkSize));
+ }
+ digester.assertEmptyBuffer();
+
+ // 6. Fill up the rest of buffer with 0s.
digester.fillUpLastOutputChunk();
}
@@ -300,8 +302,7 @@
DataSource source = new ByteBufferDataSource(inputBuffer);
BufferedDigester digester = new BufferedDigester(salt, outputBuffer);
consumeByChunk(digester, source, CHUNK_SIZE_BYTES);
- digester.finish();
-
+ digester.assertEmptyBuffer();
digester.fillUpLastOutputChunk();
}
@@ -309,7 +310,7 @@
byte[] rootHash = new byte[DIGEST_SIZE_BYTES];
BufferedDigester digester = new BufferedDigester(salt, ByteBuffer.wrap(rootHash));
digester.consume(slice(output, 0, CHUNK_SIZE_BYTES));
- digester.finish();
+ digester.assertEmptyBuffer();
return rootHash;
}
diff --git a/core/java/android/util/apk/DataDigester.java b/core/java/android/util/apk/DataDigester.java
index 278be80..18d1dff 100644
--- a/core/java/android/util/apk/DataDigester.java
+++ b/core/java/android/util/apk/DataDigester.java
@@ -22,7 +22,4 @@
interface DataDigester {
/** Consumes the {@link ByteBuffer}. */
void consume(ByteBuffer buffer) throws DigestException;
-
- /** Finishes the digestion. Must be called after the last {@link #consume(ByteBuffer)}. */
- void finish() throws DigestException;
}