# Security — Key Management & PIN Block Generation

This document describes how cryptographic keys (KEK, TMK/MK, DUKPT IPEK) are stored and how PIN blocks are generated in this application.

---

## Key Hierarchy Overview

```
BDK (Base Derivation Key) — held by key custodian, never on device
  └─ IPEK (Initial PIN Encryption Key) — injected into hardware securely
       └─ Future Keys (derived per-transaction from IPEK + KSN)
            └─ PEK (PIN Encryption Key) — ephemeral, derived each transaction
                 └─ PIN Block — ISO 9564-0 encrypted PIN sent in field 52

KEK (Key Encryption Key) — injected first, used to protect TMK in transit
  └─ TMK / MK (Terminal Master Key / Master Key) — decrypted by KEK, stored in hardware
       └─ Session Keys (Work Keys) — derived from TMK for MAC, DATA
```

---

## 1. KEK / Base Key Storage

### Purpose
The KEK (Key Encryption Key) is injected into the terminal first. It protects the TMK during transport — the TMK arrives encrypted under the KEK.

### Loading Methods

**`sdk_helper/.../BPinpad.java` — hardware API wrapper:**

| Method | When Used |
|--------|-----------|
| `loadClearKekKey(int masterIndex, byte[] key)` | Test/lab environments — plaintext KEK |
| `loadCipherKekKey(int masterIndex, byte[] key)` | Production — KEK encrypted under a transport key |

Both delegate to the Morefun hardware API:
```java
DeviceHelper.getPinpad().loadKEK(masterIndex, key, null);
DeviceHelper.getPinpad().loadCipherKEK(masterIndex, key, null);
```

**`sdk_helper/.../BPinpad_Nsdk.java` — NSDK KeyManager path:**
```java
SymmetricKey destKey = new SymmetricKey();
destKey.setKeyID((byte) masterIndex);
destKey.setKeyType(KeyType.DES);
destKey.setKeyUsage(KeyUsage.KEK);
destKey.setKeyLen(16);
destKey.setKeyData(key);
mKeyManager.generateKey(KeyGenerateMethod.CLEAR, null, null, destKey);
```

### Storage Location
The KEK is stored **inside the hardware security module (HSM) of the POS terminal**. It never exists in Android application memory beyond the injection call. The index used to reference it later is stored in `SharedPreferences` via `ParamsConst.PARAMS_KEY_PINPAD_MASTER_KEY_INDEX`.

### Injection Flow (Manual — Test Only)
`core/.../masterkey/InjectMasterKey.java` → `InjectMasterKeyStep.java`:

1. User authenticates (user `01`, password `0000`)
2. `PinpadHelper.loadKekKey(kekKey)` is called with a hard-coded test KEK (`730BC451D6D64CAB0B37A486049E6DC4`)
3. KCV is calculated via `KcvUtil.calculateKcv()` and shown as a toast for verification

> **Note:** The hard-coded KEK in `InjectMasterKeyStep.java` is for development/testing only. Production key injection must use encrypted transport (`loadCipherKekKey`) or the RKL flow described below.

### Remote Key Loading (Production)
`sdk_helper/.../FlyKeyHelper.java` — uses Newland RKL (Remote Key Loader):

```java
FlyKeyHelper.downloadMsterKey(context, isExternalPinpad, listener);
```

1. RKL configuration loaded from assets
2. Device certificate authenticates to key server
3. Encrypted key bundle downloaded
4. Keys installed via `RKLProcessor.getInstance().getInstalledKeyInfo()`

### KCV Verification
`base/.../crypto/KcvUtil.java` — standard 3DES KCV (first 3 bytes / 6 hex digits of encrypting an all-zero 8-byte block):

```java
public static String calculateKcv(byte[] keySrc, int kcvLength) {
    byte[] keyBytes = buildDesKey(keySrc); // expand to 24-byte 3DES key
    Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "DESede"));
    byte[] encrypted = cipher.doFinal(new byte[8]); // encrypt 8 zero bytes
    return hex(encrypted).substring(0, kcvLength).toUpperCase();
}
```

---

## 2. TMK / Terminal Master Key (MK) Storage

### Purpose
The TMK (Terminal Master Key) is the root key for MKSK (Master Key / Session Key) mode. Session keys for MAC and DATA operations are derived from it per-transaction. In DUKPT mode the equivalent role is served by the IPEK (see section 3).

### Loading Methods

**Encrypted under KEK (production):**
```java
// BPinpad.java
DeviceHelper.getPinpad().loadCipherMKey(masterIndex, key, null, masterIndex);
```
The TMK arrives ciphertext-encrypted under the KEK already loaded at `masterIndex`. The hardware decrypts and stores it internally.

**NSDK path (`BPinpad_Nsdk.java`):**
```java
SymmetricKey destKey = new SymmetricKey();
destKey.setKeyID((byte) masterIndex);
destKey.setKeyType(KeyType.DES);
destKey.setKeyUsage(KeyUsage.KEK);   // KeyUsage.KEK signals this is a master-level key
destKey.setKeyLen(16);
destKey.setKeyData(key);
mKeyManager.generateKey(KeyGenerateMethod.CLEAR, null, null, destKey);
```

### Storage Location
Stored **in hardware** (same HSM as KEK). The application only holds the integer `masterIndex` in `SharedPreferences`. The active algorithm (DUKPT vs MKSK) is stored at `ParamsConst.PARAMS_KEY_PINPAD_ALGORITHM_TYPE`:

```java
// KeyAlgorithmType.java
public static final int DUKPT = 0x00;
public static final int MKSK  = 0x01;
```

### Work Keys (MKSK Mode)
Work keys are derived from TMK inside the hardware. The application requests them by type:

```java
// WorkKeyType.java
PIN_KEY   // encrypts the PIN block
MAC_KEY   // generates message authentication codes
DATA_KEY  // encrypts sensitive field data
```

KCV for both KEK and TMK is retrieved via:
```java
PinpadHelper.getKcvForKek();
PinpadHelper.getKcvForMasterKey();
```

---

## 3. DUKPT IPEK Storage

### Purpose
The IPEK (Initial PIN Encryption Key) is the DUKPT equivalent of the TMK. Combined with the KSN (Key Serial Number), it seeds the entire DUKPT key tree. Each transaction derives a unique PEK (PIN Encryption Key) from the IPEK + current KSN, so no two transactions share a key.

### Loading Methods

**`BPinpad.java` — three variants:**

| Method | `DukptKeyTypeEnum` | Use Case |
|--------|--------------------|----------|
| `loadClearDukptIpek(ipek, ksn)` | `DUKPT_IPEK_PLAINTEXT` | Lab/test only |
| `loadMasterEncryptedDukptIpek(ipek, ksn)` | `DUKPT_IPEK_ENC_MAK` | Production — IPEK encrypted under TMK |
| *(deprecated)* | `DUKPT_IPEK_ENC_KEK` | IPEK encrypted under KEK |

All three call:
```java
int ret = DeviceHelper.getPinpad().dukptLoad(dukptLoadObj);
```

**NSDK path (`BPinpad_Nsdk.java`):**
```java
DUKPTKey destKey = new DUKPTKey();
destKey.setKeyID((byte) masterIndex);
destKey.setKeyType(KeyType.DES);
destKey.setKeyUsage(KeyUsage.DUKPT);
destKey.setKeyData(ipek);       // 16-byte IPEK
destKey.setKSN(ksn);            // 10-byte initial KSN
destKey.setKeyLen(16);
mKeyManager.generateKey(KeyGenerateMethod.CLEAR, null, null, destKey);
```

### Storage Location
The IPEK is stored **in hardware**. The application never holds the raw IPEK value after injection. The KSN counter is maintained by the hardware and incremented atomically.

### KSN Lifecycle
The KSN (Key Serial Number) uniquely identifies the DUKPT key state and is sent to the host alongside the encrypted PIN so the host can reconstruct the same PEK using its copy of the BDK.

```java
// PinpadHelper.java
PinpadHelper.increaseDukptKsn();     // increment before PIN entry (called in InputPinStep)
PinpadHelper.asyncIncreaseKsn();     // background increment variant
String ksn = PinpadHelper.getKsn();  // retrieve current KSN for field 63
```

> **Critical:** `increaseDukptKsn()` must always be called **before** PIN entry. Missing this call reuses a KSN, which breaks DUKPT security.

### Software DUKPT (offline derivation — `base/.../crypto/DukptUtils.java`)
Used for testing or host-side verification:

```java
// Derive IPEK from BDK + KSN (host side)
byte[] ipek = DukptUtils.generateIpekByBdk(bdk, ksn);

// Derive PEK from IPEK + KSN (per-transaction)
byte[] pek  = DukptUtils.generatePek(ipek, ksn);

// Derive work keys from PEK
byte[][] workKeys = DukptUtils.generateWorkKey(pek);
// workKeys[0] = PIN key
// workKeys[1] = MAC key
// workKeys[2] = DATA key
```

IPEK generation (mirrors ANSI X9.24-1):
```
ipekLeft  = 3DES_ECB(bdk, ksn[0:8])
ipekRight = 3DES_ECB(bdk XOR VARIANT_MASK, ksn[0:8])
ipek      = ipekLeft || ipekRight
```

---

## 4. PIN Block Generation with DUKPT

### End-to-End Flow

```
InputPinStep.java
  1. PinpadHelper.increaseDukptKsn()         ← increment KSN before entry
  2. PinpadHelper.startPinInput(isOnlinePin, pan, pinLengths, listener)
        ↓ (hardware handles everything below)
  3. Hardware derives PEK = f(IPEK, currentKSN)
  4. Hardware builds ISO 9564-0 PIN block from user-entered PIN + PAN
  5. Hardware encrypts PIN block with PEK using 3DES
  6. Hardware returns encrypted PIN block bytes
        ↓
  7. onPinRslt(byte[] pin) callback
  8. pubBean.setPinBlock(BytesUtils.bcdToString(pin))

PackSaleStep.java
  9. iso8583.setField(52, pubBean.getPinBlock().substring(0, 16))  ← encrypted PIN block
 10. iso8583.setField(63, new PinpadHelper().getKsn())             ← KSN for host
```

### ISO 9564-0 PIN Block Format (hardware-enforced)

```
PIN Block = 3DES_CBC(PEK,  XOR(PIN_Field, PAN_Field) )

PIN_Field: [ PIN_LEN (4 bits) | PIN digits | 0xF padding ] → 8 bytes
PAN_Field: [ 0x00 0x00        | rightmost 12 PAN digits (excluding check digit) ] → 8 bytes
```

The hardware PIN entry module (`BPinpad_Nsdk.java`) configures this via:
```java
mPinEntry.startOnlinePINEntry(key, pan, timeout, params, listener);
```

### Software Fallback (`base/.../crypto/PinUtils.java`)
For testing or offline scenarios only — never used for live transactions:

```java
public static byte[] softPinBlock(byte[] pinKey, String pin, String cardNo) {
    // PAN field: last 12 digits excluding check digit, left-padded with 0x0000
    String pinPan = cardNo.substring(cardNo.length() - 13, cardNo.length() - 1);
    byte[] pan = concat(new byte[]{0x00, 0x00}, bcd(pinPan));     // 8 bytes

    // PIN field: [length nibble][PIN digits][0xF padding]
    byte[] pinField = bcd(pin.length() + pin + "FFFFFFFFFFFFFF");  // 8 bytes

    // Encrypt: 3DES( pinKey, XOR(pan, pinField) )
    return DesUtils.softDes(pinKey, xor(pan, pinField));
}
```

### ISO 8583 Field Mapping

| Field | Content | Source |
|-------|---------|--------|
| 52 | Encrypted PIN block (16 hex chars = 8 bytes) | `pubBean.getPinBlock()` |
| 63 | KSN (current DUKPT Key Serial Number) | `PinpadHelper.getKsn()` |

---

## 5. External PIN Pad

When `ParamsConst.PARAMS_KEY_EXTERNAL_PINPAD` is `true`, the application routes key management and PIN entry through `ExtServiceHelper` (NSDK external module) rather than the built-in hardware. The key injection and PIN block APIs are identical from the application layer; only the hardware target changes.

---

## 6. Key Security Properties Summary

| Key | Storage | Exposed to App? | Transport Protection |
|-----|---------|-----------------|----------------------|
| KEK | Hardware HSM | No (index only) | Plaintext (test) / encrypted (prod) |
| TMK / MK | Hardware HSM | No (index only) | Encrypted under KEK |
| IPEK | Hardware HSM | No (index only) | Plaintext (test) / encrypted under TMK (prod) |
| PEK | Ephemeral in hardware | Never | Derived per-transaction, not transmitted |
| PIN Block | Application memory briefly | Yes (encrypted bytes only) | 3DES encrypted; sent in field 52 |
| KSN | Hardware counter + field 63 | Yes (non-secret) | Plaintext; used by host to reconstruct PEK |

---

## 7. Relevant Source Files

| File | Role |
|------|------|
| `sdk_helper/.../pin/BPinpad.java` | Morefun hardware pinpad API — key loading, PIN entry |
| `sdk_helper/.../pin/BPinpad_Nsdk.java` | NSDK KeyManager / PINEntry API path |
| `sdk_helper/.../FlyKeyHelper.java` | RKL remote key download |
| `core/.../masterkey/InjectMasterKey.java` | Manual KEK injection transaction |
| `core/.../masterkey/InjectMasterKeyStep.java` | KEK injection step (test KEK hard-coded here) |
| `core/.../steps/InputPinStep.java` | PIN entry step — KSN increment + PIN capture |
| `core/.../steps/PackSaleStep.java` | Field 52/63 packing |
| `core/.../tools/PinpadHelper.java` | Application-level pinpad wrapper |
| `base/.../crypto/DukptUtils.java` | Software DUKPT derivation (IPEK → PEK → work keys) |
| `base/.../crypto/PinUtils.java` | Software ISO 9564-0 PIN block (test/offline only) |
| `base/.../crypto/KcvUtil.java` | KCV calculation (3DES of zero block) |
| `sdk_helper/.../pin/constant/KeyAlgorithmType.java` | DUKPT (0x00) vs MKSK (0x01) constants |
| `sdk_helper/.../pin/constant/WorkKeyType.java` | PIN_KEY, MAC_KEY, DATA_KEY |
