1package com.peachpasswords.vault23import org.bouncycastle.crypto.digests.Blake3Digest4import org.bouncycastle.crypto.generators.Argon2BytesGenerator5import org.bouncycastle.crypto.params.Argon2Parameters6import org.junit.Assert.assertArrayEquals7import org.junit.Assert.assertEquals8import org.junit.Assert.assertThrows9import org.junit.Test1011class OfficialCryptoVectorsTest {1213 @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)2627 assertEquals(28 "0d640df58d78766c08c037a34a8b53c9d01ef0452d75b65eb52520e96b01e659",29 output.toHex(),30 )31 }3233 @Test fun production_argon2id_profile_matches_browser_hash_wasm() {34 assertEquals(35 "df187c8d241e8f3fd42810e1379660605aad1119dcb133d8ff916f87160d6a33",36 VaultCrypto.deriveKey("testpassword", ByteArray(16) { 0xab.toByte() }).toHex(),37 )38 }3940 @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 + tag4647 assertEquals(48 "7789b41cb3ee548814ca0b388c10b343",49 VaultCrypto.decrypt(packed, key, ByteArray(0)).toHex(),50 )5152 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 }5758 @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)6465 assertArrayEquals(66 "42214739f095a406f3fc83deb889744ac00df831c10daa55189b5d121c855af7".hexBytes(),67 output,68 )69 }7071 private fun String.hexBytes(): ByteArray =72 chunked(2).map { it.toInt(16).toByte() }.toByteArray()7374 private fun ByteArray.toHex(): String =75 joinToString("") { "%02x".format(it.toInt() and 0xff) }76}