1package com.peachpasswords23import com.peachpasswords.sync.SASDerivation4import com.peachpasswords.sync.computeVaultId5import com.peachpasswords.sync.noiseXXDeterministicHandshakeHashForTest6import com.peachpasswords.sync.noiseNKHkdf2ForTest7import com.peachpasswords.sync.noiseNKInitHashForTest8import com.peachpasswords.sync.noiseXXHkdf2ForTest9import com.peachpasswords.sync.noiseXXInitHashForTest10import com.peachpasswords.vault.VaultCrypto11import org.junit.Assert.assertArrayEquals12import org.junit.Assert.assertEquals13import org.junit.Assert.assertFalse14import org.junit.Assert.assertNotEquals15import org.junit.Test16import java.text.Normalizer17181920212223242526class CrossPlatformKATTest {2728 private fun hex(b: ByteArray) = b.joinToString("") { "%02x".format(it) }2930 31 private val argonSalt = ByteArray(VaultCrypto.SALT_SIZE) { it.toByte() }3233 @Test fun argon2id_non_bmp_password_vector() {34 35 36 37 val key = VaultCrypto.deriveKey("test🔑", argonSalt)38 assertEquals("a519dd4e695d25c6cd69a2f89d51ddcabd952c979f5714ab29fb77f6d1ad3728", hex(key))39 }4041 @Test fun nfc_normalization_makes_composed_and_decomposed_match() {42 43 44 val nfd = Normalizer.normalize("café", Normalizer.Form.NFD)45 val nfc = Normalizer.normalize("café", Normalizer.Form.NFC)46 assertNotEquals(nfd, nfc)47 assertArrayEquals(VaultCrypto.deriveKey(nfd, argonSalt), VaultCrypto.deriveKey(nfc, argonSalt))48 }4950 @Test fun deriveKeyRaw_does_not_normalize() {51 val nfd = Normalizer.normalize("café", Normalizer.Form.NFD)52 val nfc = Normalizer.normalize("café", Normalizer.Form.NFC)53 assertFalse(54 VaultCrypto.deriveKeyRaw(nfd, argonSalt).contentEquals(VaultCrypto.deriveKeyRaw(nfc, argonSalt)),55 )56 }5758 @Test fun compute_vault_id_vector() {59 60 val masterKey = ByteArray(32) { it.toByte() }61 assertEquals("ae0ec54041c9ba3e20c0c2d33bdeb2552f3b9a3fb4be3286ec0ef0a61be2fc9c", computeVaultId(masterKey))62 }6364 @Test fun sas_derivation_vector() {65 66 val handshakeHash = byteArrayOf(0x12, 0x34, 0x56, 0x78) + ByteArray(28)67 assertEquals("419896", SASDerivation.derive(handshakeHash))68 }6970 71 72 73 74 75 @Test fun noise_xx_init_hash_is_blake2s_vector() {76 assertEquals(77 "1ceedd81c5f458b225923dc2507787bf156f9251fc17c45af63263a929fc1ed2",78 hex(noiseXXInitHashForTest()),79 )80 }8182 @Test fun noise_nk_init_hash_is_blake2s_vector() {83 assertEquals(84 "e01688d376ef280a27a8af5c559024a02017585b3763763e4f3c7118a979b09e",85 hex(noiseNKInitHashForTest()),86 )87 }8889 @Test fun noise_hkdf2_blake2s_vector() {90 91 val ck = ByteArray(32) { it.toByte() }92 val ikm = ByteArray(32) { (it + 32).toByte() }93 val (xk1, xk2) = noiseXXHkdf2ForTest(ck, ikm)94 assertEquals("6a96444e20e8d4c1cee974416acae1c10b3c92886010e54ed94dafb2c3b80ea0", hex(xk1))95 assertEquals("57af120b0de7acbe7907ec149c5ae870a2dbb74232b65777ba4123f1f7f888f5", hex(xk2))96 97 val (nk1, nk2) = noiseNKHkdf2ForTest(ck, ikm)98 assertArrayEquals(xk1, nk1)99 assertArrayEquals(xk2, nk2)100 }101102 @Test fun noise_xx_handshake_hash_includes_canonical_msg1_empty_payload_hash() {103 assertEquals(104 "505b6dcb59838e5d163f4fd4897cfff87c20ecca23aa993b416206aba25ee71c",105 hex(noiseXXDeterministicHandshakeHashForTest()),106 )107 }108}