SyncEntryEnvelopeKatTest.kt

1.9 KB · raw

1package com.peachpasswords.sync23import kotlinx.serialization.json.Json4import kotlinx.serialization.json.jsonObject5import kotlinx.serialization.json.jsonPrimitive6import org.bouncycastle.crypto.digests.SHA256Digest7import org.bouncycastle.crypto.generators.HKDFBytesGenerator8import org.bouncycastle.crypto.params.HKDFParameters9import org.junit.Assert.assertEquals10import org.junit.Test11import java.util.Base6412import javax.crypto.Cipher13import javax.crypto.spec.GCMParameterSpec14import javax.crypto.spec.SecretKeySpec1516class SyncEntryEnvelopeKatTest {17    @Test fun matches_cross_client_sync_entry_v1_envelope_vector() {18        val vector = Json.parseToJsonElement(19            checkNotNull(javaClass.classLoader?.getResource("fixtures/golden/sync-entry-envelope-v1.json"))20                .readText(),21        ).jsonObject22        val master = hexToBytes(vector.getValue("masterKeyHex").jsonPrimitive.content)23        val entryId = vector.getValue("entryId").jsonPrimitive.content24        val nonce = hexToBytes(vector.getValue("nonceHex").jsonPrimitive.content)25        val info = (entryId + "\u0000sync-entry-v1").toByteArray(Charsets.UTF_8)26        val key = ByteArray(32)27        HKDFBytesGenerator(SHA256Digest()).apply {28            init(HKDFParameters(master, ByteArray(0), info))29            generateBytes(key, 0, key.size)30        }31        val cipher = Cipher.getInstance("AES/GCM/NoPadding")32        cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, "AES"), GCMParameterSpec(128, nonce))33        cipher.updateAAD("peach-sync-entry-v1".toByteArray(Charsets.UTF_8))34        val ciphertext = cipher.doFinal(35            vector.getValue("plaintext").jsonPrimitive.content.toByteArray(Charsets.UTF_8),36        )3738        assertEquals(39            vector.getValue("envelopeBase64").jsonPrimitive.content,40            Base64.getEncoder().encodeToString(nonce + ciphertext),41        )42        key.fill(0)43        master.fill(0)44    }45}