refactor(applet): AliroGcm.setKeyAndIv consolidates re-keying (M2C.2)
This commit is contained in:
@@ -191,6 +191,65 @@ class AliroGcmTest {
|
||||
"different keys must produce different tags");
|
||||
}
|
||||
|
||||
/**
|
||||
* Rekey-across-encrypts: M2D.3's stream-encrypt path calls
|
||||
* {@link AliroGcm#encrypt} twice in a single session (once for the
|
||||
* EXCHANGE Reader Status ack, once for the ENVELOPE DeviceResponse) with
|
||||
* a different (key, IV) pair each time. This test pins that no leftover
|
||||
* state from the first call (cached H, M-table, AES key slot) corrupts
|
||||
* the second. M2C.2 extracts the rekey path into {@code setKeyAndIv};
|
||||
* this test is the regression spec for that refactor.
|
||||
*/
|
||||
@Test
|
||||
void setKeyAndIvAllowsRekeyAcrossMultipleEncrypts() {
|
||||
AliroGcm gcm = new AliroGcm();
|
||||
|
||||
// Encrypt block A under key1 + iv1
|
||||
byte[] keyA = makeKey((byte) 0xA0);
|
||||
byte[] ivA = makeIv((byte) 0xAA);
|
||||
byte[] ptA = bytes("hello A");
|
||||
byte[] outA = new byte[ptA.length + 16];
|
||||
gcm.encrypt(keyA, (short) 0, ivA, (short) 0,
|
||||
ptA, (short) 0, (short) ptA.length, outA, (short) 0);
|
||||
|
||||
// Rekey + encrypt block B under key2 + iv2
|
||||
byte[] keyB = makeKey((byte) 0xB0);
|
||||
byte[] ivB = makeIv((byte) 0xBB);
|
||||
byte[] ptB = bytes("hello B");
|
||||
byte[] outB = new byte[ptB.length + 16];
|
||||
gcm.encrypt(keyB, (short) 0, ivB, (short) 0,
|
||||
ptB, (short) 0, (short) ptB.length, outB, (short) 0);
|
||||
|
||||
// Both must round-trip cleanly through decrypt under their own key+iv
|
||||
byte[] ptAroundTrip = new byte[ptA.length];
|
||||
gcm.decrypt(keyA, (short) 0, ivA, (short) 0,
|
||||
outA, (short) 0, (short) outA.length, ptAroundTrip, (short) 0);
|
||||
assertArrayEquals(ptA, ptAroundTrip,
|
||||
"block A must decrypt under (keyA, ivA) after gcm has been re-keyed to B");
|
||||
|
||||
byte[] ptBroundTrip = new byte[ptB.length];
|
||||
gcm.decrypt(keyB, (short) 0, ivB, (short) 0,
|
||||
outB, (short) 0, (short) outB.length, ptBroundTrip, (short) 0);
|
||||
assertArrayEquals(ptB, ptBroundTrip,
|
||||
"block B must decrypt under (keyB, ivB) — no leftover state from A");
|
||||
}
|
||||
|
||||
private static byte[] makeKey(byte seed) {
|
||||
byte[] k = new byte[32];
|
||||
for (int i = 0; i < 32; i++) k[i] = (byte) (seed + i);
|
||||
return k;
|
||||
}
|
||||
|
||||
private static byte[] makeIv(byte seed) {
|
||||
byte[] iv = new byte[12];
|
||||
for (int i = 0; i < 12; i++) iv[i] = (byte) (seed + i);
|
||||
return iv;
|
||||
}
|
||||
|
||||
private static byte[] bytes(String s) {
|
||||
return s.getBytes(java.nio.charset.StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@Test
|
||||
void differentIvsProduceDifferentCiphertexts() {
|
||||
byte[] key = new byte[32];
|
||||
|
||||
Reference in New Issue
Block a user