Add DUKPT session key variant, PIN block edge case, and EMV MAC boundary tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
31310d5d57
commit
c628207471
@ -418,6 +418,82 @@ TestRegister.addTests([
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// ── DUKPT Derive TDES Key — session key variants (ANSI X9.24-1) ──────────
|
||||||
|
// Same BDK/KSN as IPEK test above. IPEK = 6AC292FAA1315B4D858AB3A3D7D5933A.
|
||||||
|
// sessionBase at counter 1 = 042666B49184CFA368DE9628D0397BC9 (confirmed
|
||||||
|
// empirically; variant keys are sessionBase XOR the ANSI X9.24-1 masks).
|
||||||
|
name: "DUKPT Derive TDES Key: session key, variant None, counter 1",
|
||||||
|
input: "0123456789ABCDEFFEDCBA9876543210",
|
||||||
|
expectedOutput: "042666B49184CFA368DE9628D0397BC9",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "DUKPT Derive TDES Key",
|
||||||
|
args: ["Derive Session Key", "FFFF9876543210E00001", "None", false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DUKPT Derive TDES Key: session key, variant PIN, counter 1",
|
||||||
|
input: "0123456789ABCDEFFEDCBA9876543210",
|
||||||
|
expectedOutput: "042666B49184CF5C68DE9628D0397B36",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "DUKPT Derive TDES Key",
|
||||||
|
args: ["Derive Session Key", "FFFF9876543210E00001", "PIN", false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DUKPT Derive TDES Key: session key, variant MAC Request, counter 1",
|
||||||
|
input: "0123456789ABCDEFFEDCBA9876543210",
|
||||||
|
expectedOutput: "042666B4918430A368DE9628D03984C9",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "DUKPT Derive TDES Key",
|
||||||
|
args: ["Derive Session Key", "FFFF9876543210E00001", "MAC Request", false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DUKPT Derive TDES Key: session key, variant MAC Response, counter 1",
|
||||||
|
input: "0123456789ABCDEFFEDCBA9876543210",
|
||||||
|
expectedOutput: "042666B46E84CFA368DE96282F397BC9",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "DUKPT Derive TDES Key",
|
||||||
|
args: ["Derive Session Key", "FFFF9876543210E00001", "MAC Response", false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DUKPT Derive TDES Key: session key, variant Data, counter 1",
|
||||||
|
input: "0123456789ABCDEFFEDCBA9876543210",
|
||||||
|
expectedOutput: "042666B4917BCFA368DE9628D0C67BC9",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "DUKPT Derive TDES Key",
|
||||||
|
args: ["Derive Session Key", "FFFF9876543210E00001", "Data", false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DUKPT Derive TDES Key: session key JSON output includes ipek and sessionBase",
|
||||||
|
input: "0123456789ABCDEFFEDCBA9876543210",
|
||||||
|
expectedOutput: JSON.stringify({
|
||||||
|
mode: "Derive Session Key",
|
||||||
|
ipek: "6AC292FAA1315B4D858AB3A3D7D5933A",
|
||||||
|
sessionBase: "042666B49184CFA368DE9628D0397BC9",
|
||||||
|
variant: "None",
|
||||||
|
sessionKey: "042666B49184CFA368DE9628D0397BC9"
|
||||||
|
}, null, 4),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "DUKPT Derive TDES Key",
|
||||||
|
args: ["Derive Session Key", "FFFF9876543210E00001", "None", true]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "PIN Block Build: ISO Format 0",
|
name: "PIN Block Build: ISO Format 0",
|
||||||
input: "1234",
|
input: "1234",
|
||||||
@ -533,6 +609,83 @@ TestRegister.addTests([
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// ── PIN Block — edge cases ────────────────────────────────────────────────
|
||||||
|
// Leading-zero PAN: exercises the padStart("0",12) path in buildPanField.
|
||||||
|
// PAN "0000001234567890": strip check → "000000123456789", right-12 → "000123456789"
|
||||||
|
name: "PIN Block Build: ISO Format 0, leading-zero PAN",
|
||||||
|
input: "1234",
|
||||||
|
expectedOutput: "041234FEDCBA9876",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PIN Block Build",
|
||||||
|
args: ["ISO Format 0", "0000001234567890", false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PIN Block Parse: ISO Format 0, leading-zero PAN",
|
||||||
|
input: "041234FEDCBA9876",
|
||||||
|
expectedOutput: JSON.stringify({
|
||||||
|
format: "ISO Format 0",
|
||||||
|
pin: "1234",
|
||||||
|
pinLength: 4,
|
||||||
|
pinFieldHex: "041234FFFFFFFFFF",
|
||||||
|
panFieldHex: "0000000123456789",
|
||||||
|
blockHex: "041234FEDCBA9876",
|
||||||
|
fillDigitsHex: "FFFFFFFFFF"
|
||||||
|
}, null, 4),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PIN Block Parse",
|
||||||
|
args: ["ISO Format 0", "0000001234567890"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// 12-digit PAN: strip check → 11 digits, padStart adds one leading zero.
|
||||||
|
// PAN "123456789012": strip check → "12345678901" (11 chars), right-12 pads to "012345678901"
|
||||||
|
name: "PIN Block Build: ISO Format 0, 12-digit PAN (padStart path)",
|
||||||
|
input: "1234",
|
||||||
|
expectedOutput: "041235DCBA9876FE",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PIN Block Build",
|
||||||
|
args: ["ISO Format 0", "123456789012", false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// 6-digit PIN: maximum PIN length per ISO 9564; length nibble = 6 and fill is 8 nibbles.
|
||||||
|
name: "PIN Block Build: ISO Format 0, 6-digit PIN",
|
||||||
|
input: "123456",
|
||||||
|
expectedOutput: "06121557DCBA9876",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PIN Block Build",
|
||||||
|
args: ["ISO Format 0", "5432101234567890", false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PIN Block Parse: ISO Format 0, 6-digit PIN",
|
||||||
|
input: "06121557DCBA9876",
|
||||||
|
expectedOutput: JSON.stringify({
|
||||||
|
format: "ISO Format 0",
|
||||||
|
pin: "123456",
|
||||||
|
pinLength: 6,
|
||||||
|
pinFieldHex: "06123456FFFFFFFF",
|
||||||
|
panFieldHex: "0000210123456789",
|
||||||
|
blockHex: "06121557DCBA9876",
|
||||||
|
fillDigitsHex: "FFFFFFFF"
|
||||||
|
}, null, 4),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PIN Block Parse",
|
||||||
|
args: ["ISO Format 0", "5432101234567890"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Card Validation Data Generate: known CVV2 sample",
|
name: "Card Validation Data Generate: known CVV2 sample",
|
||||||
input: "0123456789ABCDEFFEDCBA9876543210",
|
input: "0123456789ABCDEFFEDCBA9876543210",
|
||||||
@ -807,6 +960,55 @@ TestRegister.addTests([
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// ── EMV Generate MAC — Method 2 padding boundary cases ───────────────────
|
||||||
|
// Method 2: append 0x80 then zeros to next block boundary; if already
|
||||||
|
// block-aligned, a full extra 8-byte block is appended. These tests
|
||||||
|
// cover 0-byte (one block of pure padding), 1-byte (pads to 8), and
|
||||||
|
// 8-byte / 16-byte inputs (each triggers the full-extra-block path).
|
||||||
|
name: "EMV Generate MAC: Method 2, empty input (0 bytes — pure padding block)",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "F1FBCF2A56D19BA7",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "EMV Generate MAC",
|
||||||
|
args: ["0123456789ABCDEFFEDCBA9876543210", "Method 2", 8, false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "EMV Generate MAC: Method 2, 1-byte input (pads to single block)",
|
||||||
|
input: "FF",
|
||||||
|
expectedOutput: "3A8AE1947D2AD964",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "EMV Generate MAC",
|
||||||
|
args: ["0123456789ABCDEFFEDCBA9876543210", "Method 2", 8, false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "EMV Generate MAC: Method 2, 8-byte input (block-aligned — extra block appended)",
|
||||||
|
input: "0102030405060708",
|
||||||
|
expectedOutput: "59997D5B782645F9",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "EMV Generate MAC",
|
||||||
|
args: ["0123456789ABCDEFFEDCBA9876543210", "Method 2", 8, false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "EMV Generate MAC: Method 2, 16-byte input (two-block-aligned — extra block appended)",
|
||||||
|
input: "000102030405060708090A0B0C0D0E0F",
|
||||||
|
expectedOutput: "99F6CC9FB8367150",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "EMV Generate MAC",
|
||||||
|
args: ["0123456789ABCDEFFEDCBA9876543210", "Method 2", 8, false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "EMV Verify MAC: issuer script sample",
|
name: "EMV Verify MAC: issuer script sample",
|
||||||
input: "8424000008999E57FD0F47CACE0007",
|
input: "8424000008999E57FD0F47CACE0007",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user