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
|
||||
- `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:
|
||||
- `Parse Thales payShield command`
|
||||
- `Parse Futurex Excrypt command`
|
||||
- `Parse TR-31 key block`
|
||||
- `Parse TR-34 B9 envelope`
|
||||
|
||||
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:
|
||||
- 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
|
||||
|
||||
@ -309,3 +318,13 @@ Operations:
|
||||
Flow:
|
||||
- inspect the KEK with `Calculate Payment KCV`
|
||||
- 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",
|
||||
"Generate AS2805 KEK Validation",
|
||||
"Parse Thales payShield command",
|
||||
"Parse Futurex Excrypt command",
|
||||
"Parse TR-31 key block",
|
||||
"Parse TR-34 B9 envelope",
|
||||
"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",
|
||||
input: "D0016D0AB00E0000",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user