755aa7c71150
add JNI all-nine small-order blocklist regression to NoiseKKTest - KK initiator must fail writeHandshake for every blocklist entry incl. the two non-zero-output ones (cdeb..., 4c9c...), plus an honest-remote-static control; green against the rebuilt fixed core with zero production Kotlin changes
- time
- 2026-08-30 02:36 UTC · 2 months ago
- machine
- koh2
- agent
- glm-5.3-flash
- session
- small-order dh rejection
- parent
- ead822036918
↓ peach-android-755aa7c7.tar.gzatlas at this save
files changed1 file
app/src/test/java/com/peachpasswords/sync/NoiseKKTest.kt+64 −0app/src/test/java/com/peachpasswords/sync/NoiseKKTest.kt+64 −0
@@ -126,4 +126,68 @@126126 assertTrue(failure?.message?.contains("decrypt", ignoreCase = true) == true)127127 initiatorHandshake.cancel()128128 }129+130+ // PB-26-014 Android parity: the nine-entry small-order X25519 blocklist131+ // lives in the shared Rust core, so this test only proves the JNI driver132+ // surfaces its rejection. The last two entries produce non-zero DH output,133+ // so only the core's small-order guard (not the all-zero-output check)134+ // rejects them.135+ private val smallOrderRemoteStatics = listOf(136+ "0000000000000000000000000000000000000000000000000000000000000000",137+ "0100000000000000000000000000000000000000000000000000000000000000",138+ "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b880",139+ "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157",140+ "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",141+ "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",142+ "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",143+ "cdeb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b880",144+ "4c9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f11d7",145+ )146+147+ @Test148+ fun `KK initiator rejects every small-order remote static at the DH`() {149+ val local = keys(0x0b)150+ for (entry in smallOrderRemoteStatics) {151+ val session = RustNoiseSession(152+ RustNoiseNative.nativeCreateKkInitiator(153+ local.secretKey,154+ local.publicKey,155+ entry.hexToBytes(),156+ ),157+ )158+ try {159+ val failure = runCatching { session.writeHandshake() }.exceptionOrNull()160+ assertTrue(161+ "small-order remote static $entry must fail the handshake at the DH",162+ failure != null,163+ )164+ } finally {165+ session.close()166+ }167+ }168+ }169+170+ @Test171+ fun `KK accepts an honest remote static`() {172+ val local = keys(0x0b)173+ val responder = keys(0x0c)174+ val session = RustNoiseSession(175+ RustNoiseNative.nativeCreateKkInitiator(176+ local.secretKey,177+ local.publicKey,178+ responder.publicKey,179+ ),180+ )181+ try {182+ session.writeHandshake()183+ } finally {184+ session.close()185+ }186+ }129187 }188+189+private fun String.hexToBytes(): ByteArray =190+ ByteArray(length / 2) { index ->191+ ((Character.digit(this[index * 2], 16) shl 4) or192+ Character.digit(this[index * 2 + 1], 16)).toByte()193+ }