OfficialCryptoVectorsTest.kt

2.8 KB · raw

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}