Add Futurex Excrypt command parser
This commit is contained in:
parent
5cc38496bd
commit
17c004a66b
@ -200,16 +200,25 @@ Important assumptions:
|
|||||||
- `Derive DUKPT Key` is TDES DUKPT, not AES DUKPT
|
- `Derive DUKPT Key` is TDES DUKPT, not AES DUKPT
|
||||||
- `Generate AS2805 KEK Validation` is an emulation-oriented helper and explicitly documents its simplifications in the operation comments
|
- `Generate AS2805 KEK Validation` is an emulation-oriented helper and explicitly documents its simplifications in the operation comments
|
||||||
|
|
||||||
## 10) Key Container Inspection
|
## 10) Key Container And HSM Command Inspection
|
||||||
Operations:
|
Operations:
|
||||||
|
- `Parse Thales payShield command`
|
||||||
|
- `Parse Futurex Excrypt command`
|
||||||
- `Parse TR-31 key block`
|
- `Parse TR-31 key block`
|
||||||
- `Parse TR-34 B9 envelope`
|
- `Parse TR-34 B9 envelope`
|
||||||
|
|
||||||
Use this when:
|
Use this when:
|
||||||
- you need to inspect inbound wrapped-key material or transport frames during testing
|
- you need to inspect vendor HSM command syntax, wrapped-key material, or transport frames during testing
|
||||||
|
|
||||||
Input:
|
Input:
|
||||||
- full TR-31 or TR-34 payload as text or hex, depending on the operation comment
|
- `Parse Thales payShield command`: raw legacy host command or response text
|
||||||
|
- `Parse Futurex Excrypt command`: raw bracketed Excrypt command or response text
|
||||||
|
- `Parse TR-31 key block` / `Parse TR-34 B9 envelope`: full payload as text or hex, depending on the operation comment
|
||||||
|
|
||||||
|
Important assumptions:
|
||||||
|
- the Thales and Futurex parsers currently focus on visible message syntax, delimiters, command identification, and field splitting rather than deep per-command semantic decoding
|
||||||
|
- `Parse Thales payShield command` expects the configured message-header length to be supplied in the op args
|
||||||
|
- `Parse Futurex Excrypt command` treats Excrypt messages as delimiter-based tag/value fields and commonly uses the `AO` field as the command code
|
||||||
|
|
||||||
## Chaining Patterns
|
## Chaining Patterns
|
||||||
|
|
||||||
@ -309,3 +318,13 @@ Operations:
|
|||||||
Flow:
|
Flow:
|
||||||
- inspect the KEK with `Calculate Payment KCV`
|
- inspect the KEK with `Calculate Payment KCV`
|
||||||
- generate request or response RandomKeySend / RandomKeyReceive values with the AS2805 helper
|
- generate request or response RandomKeySend / RandomKeyReceive values with the AS2805 helper
|
||||||
|
|
||||||
|
## J) Vendor Command Triage
|
||||||
|
Operations:
|
||||||
|
- `Parse Thales payShield command`
|
||||||
|
- `Parse Futurex Excrypt command`
|
||||||
|
|
||||||
|
Flow:
|
||||||
|
- paste the raw host message first before trying to interpret the business meaning
|
||||||
|
- use the parsed command code, delimiters, header, trailer, or tag/value split to confirm what family of command you are looking at
|
||||||
|
- follow with lower-level payment, EMV, PIN, or key-container recipes only after the transport syntax is understood
|
||||||
|
|||||||
@ -615,6 +615,7 @@
|
|||||||
"Calculate Payment KCV",
|
"Calculate Payment KCV",
|
||||||
"Generate AS2805 KEK Validation",
|
"Generate AS2805 KEK Validation",
|
||||||
"Parse Thales payShield command",
|
"Parse Thales payShield command",
|
||||||
|
"Parse Futurex Excrypt command",
|
||||||
"Parse TR-31 key block",
|
"Parse TR-31 key block",
|
||||||
"Parse TR-34 B9 envelope",
|
"Parse TR-34 B9 envelope",
|
||||||
"HMAC",
|
"HMAC",
|
||||||
|
|||||||
177
src/core/operations/ParseFuturexExcryptCommand.mjs
Normal file
177
src/core/operations/ParseFuturexExcryptCommand.mjs
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
/**
|
||||||
|
* @license Apache-2.0
|
||||||
|
* @author Jacob Marks [https://jacobmarks.com]
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
|
||||||
|
const COMMANDS = {
|
||||||
|
CAAV: "Calculate Account holder Authentication Value",
|
||||||
|
DAPT: "Decrypt Apple Pay Token",
|
||||||
|
DCDK: "Decrypt Cardholder Data Using DUKPT",
|
||||||
|
DGPT: "Decrypt Google Pay Token",
|
||||||
|
DRKI: "Identification Request",
|
||||||
|
DRKK: "Key Request",
|
||||||
|
DRKV: "Key Verification Request",
|
||||||
|
DSPT: "Decrypt Samsung Pay Token",
|
||||||
|
ECDK: "Encrypt Cardholder Data Using DUKPT",
|
||||||
|
EMPT: "Translate PIN Block for EMV Personalization",
|
||||||
|
EMVA: "Verify ARQC and optionally generate ARPC",
|
||||||
|
EMVG: "Generate Master Key",
|
||||||
|
EMVK: "Derive Key from Vendor Master Key and Derivation Data",
|
||||||
|
EMVM: "Generate or Verify MAC",
|
||||||
|
EMVP: "PIN Change",
|
||||||
|
EMVR: "EMV RSA Private Key or Component Translation to Encryption Under a Personalization Key",
|
||||||
|
EMVS: "Translate an ICC Master Key to Encryption Under a Personalization Key",
|
||||||
|
EMVT: "EMV Translate Sensitive Data",
|
||||||
|
GCAV: "Generate CAVV",
|
||||||
|
GCIV: "Generate a CVC3 IV",
|
||||||
|
GCSC: "Generate American Express CSC Value",
|
||||||
|
GCVC: "Generate CVC and CVC2",
|
||||||
|
GCVV: "Generate CVV or CVC Value",
|
||||||
|
GDAC: "Generate a Data Authentication Code",
|
||||||
|
GDCV: "Generate dCVV/CVC3",
|
||||||
|
GDDC: "Generate Discover dynamic CVV",
|
||||||
|
GEMC: "Generate EMV ICC Certificate",
|
||||||
|
GEMQ: "Generate EMV Issuer CSR",
|
||||||
|
GHMC: "Generate HCE Mobile Cryptogram",
|
||||||
|
GHMD: "Generate HCE Magstripe Verification Value",
|
||||||
|
GHMK: "Generate HCE Mobile Keys",
|
||||||
|
GHPB: "Generate HMAC and PBKDF2 Obfuscated Value",
|
||||||
|
GIDN: "Generate an ICC dynamic number",
|
||||||
|
GMAC: "Generate Message Authentication Code",
|
||||||
|
GNOF: "Generate New Offset",
|
||||||
|
GOFC: "Generate Offset of Clear PIN",
|
||||||
|
GOFF: "Generate PIN offset value",
|
||||||
|
GOPC: "Generate Offset and EMV PIN Change",
|
||||||
|
GPIN: "Generate PIN",
|
||||||
|
GPMC: "General Purpose Symmetric MAC",
|
||||||
|
GVDC: "Generate dynamic CVV",
|
||||||
|
HMAC: "Generate MAC Hash",
|
||||||
|
OFPC: "Perform EMV PIN Change Using Offset",
|
||||||
|
ONGQ: "Translate PAN Encrypted Under an Asymmetric Key Pair to a Different Trusted Public Key",
|
||||||
|
PEDK: "Key Request",
|
||||||
|
RKHM: "Generate or Verify HMAC",
|
||||||
|
RPIN: "PIN Change and Optional PIN Verification",
|
||||||
|
SSAD: "Sign Static Authentication Data with Issuer Private Key",
|
||||||
|
TCDK: "Translate Cardholder Data Using DUKPT",
|
||||||
|
TDKD: "Translate Cardholder Data Using DUKPT and Symmetric Keys",
|
||||||
|
TKDR: "Translate DUKPT Data to RSA with Specific Output Data",
|
||||||
|
TPCP: "Translate Encrypted PIN Coordinates to a PEK for Generate New Map Collection",
|
||||||
|
TPDD: "Allow an encrypted ANSI PIN block to be translated",
|
||||||
|
TPIN: "Translate PIN blocks",
|
||||||
|
TRPN: "Translate PIN from RSA to Symmetric PIN Block",
|
||||||
|
TSPN: "Translate PIN from PIN block to RSA encryption",
|
||||||
|
VAAV: "Verify Account Holder Authentication Value",
|
||||||
|
VCAC: "Verify EMV Mastercard CAP Token",
|
||||||
|
VCAV: "Verify Cardholder Authentication Verification Value",
|
||||||
|
VCSC: "Verify American Express CSC Value",
|
||||||
|
VCVC: "Verify CVC and CVC2",
|
||||||
|
VCVV: "Verify CVV",
|
||||||
|
VDAC: "Verify a Data Authentication Code",
|
||||||
|
VDCV: "Verify CVC3",
|
||||||
|
VDDC: "Verify dynamic CVC value",
|
||||||
|
VEMI: "Verify an EMV Issuer Certificate",
|
||||||
|
VHMC: "Verify HCE Mobile Cryptogram",
|
||||||
|
VHMD: "Verify HCE Magstripe Verification Value",
|
||||||
|
VIDN: "Verify an ICC dynamic number",
|
||||||
|
VMAC: "Verify Message Authentication Code",
|
||||||
|
VMAP: "Verify MAC and PIN",
|
||||||
|
VPIN: "Verify PIN",
|
||||||
|
VVDC: "Verify a dynamic CVV",
|
||||||
|
WPIN: "Weak PIN checking",
|
||||||
|
XPIN: "PIN translation"
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an Excrypt field into tag/value components.
|
||||||
|
*
|
||||||
|
* @param {string} field
|
||||||
|
* @returns {{raw: string, tag: string, value: string}}
|
||||||
|
*/
|
||||||
|
function parseField(field) {
|
||||||
|
const tag = field.substring(0, Math.min(2, field.length)).toUpperCase();
|
||||||
|
return {
|
||||||
|
raw: field,
|
||||||
|
tag,
|
||||||
|
value: field.substring(tag.length)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse Futurex Excrypt command operation.
|
||||||
|
*/
|
||||||
|
class ParseFuturexExcryptCommand extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ParseFuturexExcryptCommand constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Parse Futurex Excrypt command";
|
||||||
|
this.module = "Payment";
|
||||||
|
this.description = "Paste a Futurex Excrypt command or response into the input field as text.<br><br><b>General syntax:</b> Excrypt messages are enclosed by opening and closing delimiters, typically <code>[</code> and <code>]</code>. Inside the message, fields are semicolon-delimited. Each field is a tag/value pair, for example <code>AOECHO</code> where <code>AO</code> is the tag and <code>ECHO</code> is the value. The command code is commonly carried in the <code>AO</code> field.<br><br><b>Input:</b> raw Excrypt message text.<br><br>This operation parses the visible Excrypt message syntax, extracts semicolon-delimited fields, splits fields into tag/value pairs, and resolves the <code>AO</code> command code to a known payment command name when available from the Futurex payment integration guide.";
|
||||||
|
this.inlineHelp = "<strong>Syntax:</strong> <code>[tagvalue;tagvalue;...]</code> where fields are separated by semicolons and tags are typically two characters such as <code>AO</code>.<br><strong>Input:</strong> raw Futurex Excrypt message text.";
|
||||||
|
this.testDataSamples = [
|
||||||
|
{
|
||||||
|
name: "Excrypt command sample",
|
||||||
|
input: "[AOGMAC;FS6;RV0011223344556677;]"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input) {
|
||||||
|
const rawInput = (input || "").replace(/\r?\n/g, "");
|
||||||
|
if (!rawInput.length) {
|
||||||
|
throw new OperationError("No input.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const openingDelimiterPresent = rawInput.startsWith("[");
|
||||||
|
const closingDelimiterPresent = rawInput.endsWith("]");
|
||||||
|
const body = rawInput.replace(/^\[/, "").replace(/\]$/, "");
|
||||||
|
const rawFields = body.split(";").filter(field => field.length > 0);
|
||||||
|
|
||||||
|
if (!rawFields.length) {
|
||||||
|
throw new OperationError("No Excrypt fields found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = rawFields.map(parseField);
|
||||||
|
const commandField = fields.find(field => field.tag === "AO") || fields[0];
|
||||||
|
const commandCode = commandField.value.toUpperCase();
|
||||||
|
const commandName = COMMANDS[commandCode] || null;
|
||||||
|
const notes = [];
|
||||||
|
|
||||||
|
if (!openingDelimiterPresent || !closingDelimiterPresent) {
|
||||||
|
notes.push("Message is missing one or both expected Excrypt outer delimiters.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!commandName) {
|
||||||
|
notes.push("Command code was not found in the Futurex payment integration guide lookup.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.stringify({
|
||||||
|
rawInput,
|
||||||
|
openingDelimiterPresent,
|
||||||
|
closingDelimiterPresent,
|
||||||
|
body,
|
||||||
|
rawFields,
|
||||||
|
fields,
|
||||||
|
commandFieldTag: commandField.tag,
|
||||||
|
commandCode,
|
||||||
|
commandName,
|
||||||
|
fieldCount: fields.length,
|
||||||
|
notes
|
||||||
|
}, null, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ParseFuturexExcryptCommand;
|
||||||
@ -92,6 +92,94 @@ TestRegister.addTests([
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Parse Futurex Excrypt command: bracketed fields",
|
||||||
|
input: "[AOGMAC;FS6;RV0011223344556677;]",
|
||||||
|
expectedOutput: JSON.stringify({
|
||||||
|
rawInput: "[AOGMAC;FS6;RV0011223344556677;]",
|
||||||
|
openingDelimiterPresent: true,
|
||||||
|
closingDelimiterPresent: true,
|
||||||
|
body: "AOGMAC;FS6;RV0011223344556677;",
|
||||||
|
rawFields: [
|
||||||
|
"AOGMAC",
|
||||||
|
"FS6",
|
||||||
|
"RV0011223344556677"
|
||||||
|
],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
raw: "AOGMAC",
|
||||||
|
tag: "AO",
|
||||||
|
value: "GMAC"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raw: "FS6",
|
||||||
|
tag: "FS",
|
||||||
|
value: "6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raw: "RV0011223344556677",
|
||||||
|
tag: "RV",
|
||||||
|
value: "0011223344556677"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
commandFieldTag: "AO",
|
||||||
|
commandCode: "GMAC",
|
||||||
|
commandName: "Generate Message Authentication Code",
|
||||||
|
fieldCount: 3,
|
||||||
|
notes: []
|
||||||
|
}, null, 4),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Parse Futurex Excrypt command",
|
||||||
|
args: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Parse Futurex Excrypt command: missing closing delimiter",
|
||||||
|
input: "[AOVMAC;FS6;RV89ABCDEF",
|
||||||
|
expectedOutput: JSON.stringify({
|
||||||
|
rawInput: "[AOVMAC;FS6;RV89ABCDEF",
|
||||||
|
openingDelimiterPresent: true,
|
||||||
|
closingDelimiterPresent: false,
|
||||||
|
body: "AOVMAC;FS6;RV89ABCDEF",
|
||||||
|
rawFields: [
|
||||||
|
"AOVMAC",
|
||||||
|
"FS6",
|
||||||
|
"RV89ABCDEF"
|
||||||
|
],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
raw: "AOVMAC",
|
||||||
|
tag: "AO",
|
||||||
|
value: "VMAC"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raw: "FS6",
|
||||||
|
tag: "FS",
|
||||||
|
value: "6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
raw: "RV89ABCDEF",
|
||||||
|
tag: "RV",
|
||||||
|
value: "89ABCDEF"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
commandFieldTag: "AO",
|
||||||
|
commandCode: "VMAC",
|
||||||
|
commandName: "Verify Message Authentication Code",
|
||||||
|
fieldCount: 3,
|
||||||
|
notes: [
|
||||||
|
"Message is missing one or both expected Excrypt outer delimiters."
|
||||||
|
]
|
||||||
|
}, null, 4),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Parse Futurex Excrypt command",
|
||||||
|
args: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Parse TR-31 key block: fixed header only",
|
name: "Parse TR-31 key block: fixed header only",
|
||||||
input: "D0016D0AB00E0000",
|
input: "D0016D0AB00E0000",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user