b4bbb429a17e
test: pin official cryptographic vectors (v2.4.1)
- time
- 2026-07-26 06:34 UTC · 3 months ago
- machine
- koh2
- parent
- 3c69d09c658f
↓ peach-android-b4bbb429.tar.gzatlas at this save
files changed5 files
VERSION+1 −1app/build.gradle+2 −2app/src/main/jniLibs/arm64-v8a/libpeach_noise_core.sobinaryapp/src/main/jniLibs/x86_64/libpeach_noise_core.sobinaryapp/src/test/java/com/peachpasswords/vault/OfficialCryptoVectorsTest.kt+76 −0app/build.gradle+2 −2
@@ -16,8 +16,8 @@1616 applicationId "com.peachpasswords"1717 minSdk 261818 targetSdk 3519- versionCode 24000020- versionName "2.4.0"19+ versionCode 24000120+ versionName "2.4.1"2121 2222 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"2323 vectorDrawables {app/src/test/java/com/peachpasswords/vault/OfficialCryptoVectorsTest.kt+76 −0
@@ -0,0 +1,76 @@1+package com.peachpasswords.vault2+3+import org.bouncycastle.crypto.digests.Blake3Digest4+import org.bouncycastle.crypto.generators.Argon2BytesGenerator5+import org.bouncycastle.crypto.params.Argon2Parameters6+import org.junit.Assert.assertArrayEquals7+import org.junit.Assert.assertEquals8+import org.junit.Assert.assertThrows9+import org.junit.Test10+11+class OfficialCryptoVectorsTest {12+13+ @Test fun rfc_9106_argon2id_vector_matches_bouncy_castle() {14+ val parameters = Argon2Parameters.Builder(Argon2Parameters.ARGON2_id)15+ .withVersion(Argon2Parameters.ARGON2_VERSION_13)16+ .withMemoryAsKB(32)17+ .withIterations(3)18+ .withParallelism(4)19+ .withSalt(ByteArray(16) { 0x02 })20+ .withSecret(ByteArray(8) { 0x03 })21+ .withAdditional(ByteArray(12) { 0x04 })22+ .build()23+ val generator = Argon2BytesGenerator().apply { init(parameters) }24+ val output = ByteArray(32)25+ generator.generateBytes(ByteArray(32) { 0x01 }, output)26+27+ assertEquals(28+ "0d640df58d78766c08c037a34a8b53c9d01ef0452d75b65eb52520e96b01e659",29+ output.toHex(),30+ )31+ }32+33+ @Test fun production_argon2id_profile_matches_browser_hash_wasm() {34+ assertEquals(35+ "df187c8d241e8f3fd42810e1379660605aad1119dcb133d8ff916f87160d6a33",36+ VaultCrypto.deriveKey("testpassword", ByteArray(16) { 0xab.toByte() }).toHex(),37+ )38+ }39+40+ @Test fun nist_aes_256_gcm_cavp_vector_decrypts_and_rejects_bad_tag() {41+ val key = "4c8ebfe1444ec1b2d503c6986659af2c94fafe945f72c1e8486a5acfedb8a0f8".hexBytes()42+ val iv = "473360e0ad24889959858995".hexBytes()43+ val ciphertext = "d2c78110ac7e8f107c0df0570bd7c90c".hexBytes()44+ val tag = "c26a379b6d98ef2852ead8ce83a833a7".hexBytes()45+ val packed = iv + ciphertext + tag46+47+ assertEquals(48+ "7789b41cb3ee548814ca0b388c10b343",49+ VaultCrypto.decrypt(packed, key, ByteArray(0)).toHex(),50+ )51+52+ val tampered = packed.copyOf().also { it[it.lastIndex] = (it.last().toInt() xor 0x01).toByte() }53+ assertThrows(Throwable::class.java) {54+ VaultCrypto.decrypt(tampered, key, ByteArray(0))55+ }56+ }57+58+ @Test fun blake3_reference_vector_matches_bouncy_castle_across_chunk_boundary() {59+ val input = ByteArray(1024) { (it % 251).toByte() }60+ val digest = Blake3Digest(256)61+ digest.update(input, 0, input.size)62+ val output = ByteArray(32)63+ digest.doFinal(output, 0)64+65+ assertArrayEquals(66+ "42214739f095a406f3fc83deb889744ac00df831c10daa55189b5d121c855af7".hexBytes(),67+ output,68+ )69+ }70+71+ private fun String.hexBytes(): ByteArray =72+ chunked(2).map { it.toInt(16).toByte() }.toByteArray()73+74+ private fun ByteArray.toHex(): String =75+ joinToString("") { "%02x".format(it.toInt() and 0xff) }76+}