1package com.peachpasswords.sync23import org.junit.Assert.assertArrayEquals4import org.junit.Assert.assertEquals5import org.junit.Assert.assertTrue6import org.junit.Test78class SyncPaddingTest {910 @Test fun round_trips_payloads_of_every_shape() {11 for (size in listOf(0, 1, 5, 251, 252, 253, 1000, 70_000)) {12 val payload = ByteArray(size) { ((it * 31) and 0xFF).toByte() }13 assertArrayEquals(payload, SyncPadding.unpad(SyncPadding.pad(payload)))14 }15 }1617 @Test fun small_control_frames_collapse_to_one_indistinguishable_size() {18 19 val hello = ("{\"type\":\"SYNC_HELLO\",\"vaultId\":\"" + "a".repeat(64) + "\"}")20 .toByteArray(Charsets.UTF_8)21 val done = "{\"type\":\"SYNC_DONE\"}".toByteArray(Charsets.UTF_8)22 assertEquals(SyncPadding.pad(hello).size, SyncPadding.pad(done).size)23 assertEquals(256, SyncPadding.pad(done).size)24 }2526 @Test fun bucket_ladder_matches_the_browser_kat() {27 28 29 val cases = listOf(30 0 to 256,31 252 to 256,32 253 to 512,33 1024 to 2048,34 65_532 to 65_536,35 65_533 to 131_072,36 200_000 to 262_144,37 )38 for ((payload, expected) in cases) {39 assertEquals(expected, SyncPadding.bucket(4 + payload))40 assertEquals(expected, SyncPadding.pad(ByteArray(payload)).size)41 }42 }4344 @Test fun large_frame_overhead_stays_bounded() {45 val twelveMiB = 12 * 1024 * 102446 val padded = SyncPadding.bucket(twelveMiB)47 assertTrue(padded >= twelveMiB)48 assertTrue(padded - twelveMiB < 64 * 1024)49 }5051 @Test fun rejects_a_frame_declaring_more_payload_than_it_carries() {52 val forged = ByteArray(256)53 forged[0] = 0; forged[1] = 0; forged[2] = 0x27; forged[3] = 0x0F.toByte() 54 var threw = false55 try { SyncPadding.unpad(forged) } catch (_: IllegalArgumentException) { threw = true }56 assertTrue(threw)57 }5859 @Test fun rejects_a_frame_shorter_than_its_length_header() {60 var threw = false61 try { SyncPadding.unpad(ByteArray(3)) } catch (_: IllegalArgumentException) { threw = true }62 assertTrue(threw)63 }6465 66 67 68 69 7071 @Test fun max_noise_plaintext_bytes_matches_the_crypto_core_limit() {72 73 74 75 assertEquals(65519, MAX_NOISE_PLAINTEXT_BYTES)76 }7778 @Test fun the_bucket_ladder_produces_frames_above_the_noise_limit_the_bug() {79 80 81 82 83 84 85 86 val padded = SyncPadding.pad(ByteArray(32 * 1024))87 assertTrue(padded.size > MAX_NOISE_PLAINTEXT_BYTES)88 }8990 @Test fun the_continuation_marker_is_the_byte_the_chunking_protocol_uses() {91 92 93 94 95 assertEquals(0x01.toByte(), FRAME_CONTINUATION_MARKER)96 }97}