X-CUBE-ALIRO firmware sends a Reader Status sub-event via EXCHANGE (CLA=0x80, INS=0xC9) after the step-up AID SELECT, per Aliro §8.3.3.5 Table 8-14. The payload is encrypted with StepUpSKReader using AES-256-GCM with IV = 0x0000000000000000 || stepup_reader_counter (4B BE) per §8.3.1.8. For Milestone 1 we decrypt-and-discard: tag verification proves we have matching session keys, then we return SW=9000 with empty payload. M2 will add a proper encrypted Reader Status response sub-event. Extends CryptoSingletons to hold the shared AliroGcm instance too -- opt 1 sibling of the AliroCrypto sharing from M1A.2. Adds AliroGcm.decrypt since the prior pipeline only encrypted (AUTH1 response path). Counter starts at 1 per session-bound init (spec §8.4.3 -> mdoc [6] §9.1.1.5), incremented after each successful decrypt. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
46 lines
1.8 KiB
Java
46 lines
1.8 KiB
Java
package com.dangerousthings.aliro;
|
|
|
|
/**
|
|
* Lazy holders for crypto objects shared between {@link AliroApplet} and
|
|
* {@link StepUpApplet}. Both applets live in the same package and only one
|
|
* is selected at a time, so the shared instances are safe — Java Card runs
|
|
* one applet at a time and the JCRE serializes APDU dispatch.
|
|
*
|
|
* <p>Java Card forbids {@code new} in {@code <clinit>}, so the getter lazy-
|
|
* creates on first call. Subsequent calls return the cached instance. The
|
|
* combined transient footprint of one shared {@link AliroCrypto} is roughly
|
|
* 352 B (kdfWorkbuf 64 + hkdfPrevT 32 + expandScratch 256); without this
|
|
* sharing each applet would allocate its own.
|
|
*/
|
|
final class CryptoSingletons {
|
|
|
|
private static AliroCrypto aliroCrypto;
|
|
private static AliroGcm aliroGcm;
|
|
|
|
private CryptoSingletons() { }
|
|
|
|
/** Returns the process-wide {@link AliroCrypto} instance. Allocates on
|
|
* first call; cheap thereafter. */
|
|
static AliroCrypto getAliroCrypto() {
|
|
if (aliroCrypto == null) {
|
|
aliroCrypto = new AliroCrypto();
|
|
}
|
|
return aliroCrypto;
|
|
}
|
|
|
|
/** Returns the process-wide {@link AliroGcm} instance. Same Java-Card
|
|
* {@code <clinit>}-cannot-{@code new} rationale as {@link #getAliroCrypto()}:
|
|
* lazy-allocate on first call so both {@link AliroApplet} and
|
|
* {@link StepUpApplet} share one userland-GCM machine. Each shared
|
|
* instance saves ~370 B of transient/EEPROM footprint that a per-applet
|
|
* duplicate would otherwise pay. The two applets are never selected
|
|
* simultaneously and the JCRE serializes APDU dispatch, so the shared
|
|
* scratch and {@code AESKey} slot don't race. */
|
|
static AliroGcm getAliroGcm() {
|
|
if (aliroGcm == null) {
|
|
aliroGcm = new AliroGcm();
|
|
}
|
|
return aliroGcm;
|
|
}
|
|
}
|