Add AWS-style payment wrapper operations

This commit is contained in:
J8k3 2026-04-25 09:39:46 -04:00
parent 3f1b63378f
commit 71b0a9871e
12 changed files with 812 additions and 35 deletions

View File

@ -22,18 +22,18 @@ Coverage legend:
| AWS operation | Coverage | Notes | | AWS operation | Coverage | Notes |
| --- | --- | --- | | --- | --- | --- |
| `EncryptData` | `Direct` / `Partial` | Direct for AES, TDES, RSA. Partial for DUKPT and EMV-derived encryption. | | `EncryptData` | `Direct` / `Partial` | Direct for AES, TDES, and the implemented DUKPT-TDES wrapper profiles. Partial for EMV-derived encryption and broader AWS attribute coverage. |
| `DecryptData` | `Direct` / `Partial` | Direct for AES, TDES, RSA. Partial for DUKPT and EMV-derived decryption. | | `DecryptData` | `Direct` / `Partial` | Direct for AES, TDES, and the implemented DUKPT-TDES wrapper profiles. Partial for EMV-derived decryption and broader AWS attribute coverage. |
| `ReEncryptData` | `Direct` / `Partial` | Direct for plain decrypt-then-encrypt workflows. Partial for DUKPT re-encryption. | | `ReEncryptData` | `Direct` / `Partial` | Direct for plain decrypt-then-encrypt workflows, including the implemented payment-facing AES/TDES wrapper flows. Partial for DUKPT re-encryption breadth and AWS-specific metadata handling. |
| `GenerateMac` | `Direct` / `Partial` | Direct for static-key HMAC and CMAC, and direct for the implemented DUKPT CMAC wrapper modes. Partial for ISO 9797, EMV MAC, and AS2805 flows. | | `GenerateMac` | `Direct` / `Partial` | Direct for static-key HMAC and CMAC, and direct for the implemented DUKPT CMAC wrapper modes. Partial for ISO 9797, EMV MAC, and AS2805 flows. |
| `VerifyMac` | `Direct` / `Partial` | Direct for static-key HMAC and CMAC, and direct for the implemented DUKPT CMAC wrapper modes. Partial for ISO 9797, EMV MAC, and AS2805 flows. | | `VerifyMac` | `Direct` / `Partial` | Direct for static-key HMAC and CMAC, and direct for the implemented DUKPT CMAC wrapper modes. Partial for ISO 9797, EMV MAC, and AS2805 flows. |
| `VerifyAuthRequestCryptogram` | `Partial` | Usable for AES-CMAC ARQC/ARPC-style checking when session key and preimage are already known. Dedicated ARQC and ARPC generators now exist for that constrained profile. | | `VerifyAuthRequestCryptogram` | `Partial` | Usable for AES-CMAC ARQC/ARPC-style checking when session key and preimage are already known. Dedicated ARQC, ARPC, and ARQC verify wrappers now exist for that constrained profile. |
| `TranslateKeyMaterial` | `Partial` | Useful for ECDH derivation and TR-31 inspection, not full HSM-side rewrap semantics. | | `TranslateKeyMaterial` | `Partial` | Useful for ECDH derivation and TR-31 inspection, not full HSM-side rewrap semantics. |
| `GenerateCardValidationData` | `Direct` | Direct for software CVV/CVV2/iCVV generation when the combined CVK pair is provided as clear hex. | | `GenerateCardValidationData` | `Direct` | Direct for software CVV/CVV2/iCVV generation when the combined CVK pair is provided as clear hex. |
| `VerifyCardValidationData` | `Direct` | Direct for software CVV/CVV2/iCVV verification using the same clear-CVK assumptions as generation. | | `VerifyCardValidationData` | `Direct` | Direct for software CVV/CVV2/iCVV verification using the same clear-CVK assumptions as generation. |
| `GeneratePinData` | `Partial` | Clear PIN-block build coverage now exists for ISO formats 0, 1, and 3. PVV, IBM3624, and encrypted-generation paths are still missing. | | `GeneratePinData` | `Partial` | Clear PIN-block wrapper coverage now exists for ISO formats 0, 1, and 3. PVV, IBM3624, and encrypted-generation paths are still missing. |
| `TranslatePinData` | `Partial` | Clear PIN-block parse and translate coverage now exists for ISO formats 0, 1, and 3. Encrypted PEK/BDK/ECDH translation is still missing. | | `TranslatePinData` | `Partial` | Clear PIN-block wrapper coverage now exists for ISO formats 0, 1, and 3. Encrypted PEK/BDK/ECDH translation is still missing. |
| `VerifyPinData` | `Partial` | Clear PIN-block decoding exists, but PVV / IBM3624 verification behavior is still missing. | | `VerifyPinData` | `Partial` | Clear PIN-block verification wrapper exists, but PVV / IBM3624 verification behavior is still missing. |
| `GenerateMacEmvPinChange` | `Not yet implemented` | Requires issuer-script PIN-change building blocks. | | `GenerateMacEmvPinChange` | `Not yet implemented` | Requires issuer-script PIN-change building blocks. |
| `GenerateAs2805KekValidation` | `Not yet implemented` | Requires AS2805-specific KEK-validation primitives. | | `GenerateAs2805KekValidation` | `Not yet implemented` | Requires AS2805-specific KEK-validation primitives. |
@ -53,7 +53,16 @@ Notes:
- AWS documents `EncryptData` as supporting symmetric `TDES` and `AES`, asymmetric `RSA`, and derived `DUKPT` or `EMV` schemes. - AWS documents `EncryptData` as supporting symmetric `TDES` and `AES`, asymmetric `RSA`, and derived `DUKPT` or `EMV` schemes.
- This starter directly covers only the non-derived AES, TDES, and RSA cases. - This starter directly covers only the non-derived AES, TDES, and RSA cases.
## 2) AWS `DecryptData`: AES / TDES / RSA ## 2) AWS `EncryptData`: Payment Wrapper
Operations:
- `Encrypt payment data`
Suggested use:
- Paste plaintext into the input field as hex.
- Choose a payment-facing profile for AES, TDES, or the implemented DUKPT-TDES wrapper modes.
- Provide the direct key or BDK plus KSN, and add the IV when required.
## 3) AWS `DecryptData`: AES / TDES / RSA
Operations: Operations:
- `AES Decrypt` or `Triple DES Decrypt` or `RSA Decrypt` - `AES Decrypt` or `Triple DES Decrypt` or `RSA Decrypt`
@ -63,7 +72,16 @@ Suggested use:
- Paste the key into the key argument using the correct format selector. - Paste the key into the key argument using the correct format selector.
- Match the AWS algorithm and mode manually in the chosen CyberChef operation. - Match the AWS algorithm and mode manually in the chosen CyberChef operation.
## 3) AWS `ReEncryptData`: Symmetric Rewrap ## 4) AWS `DecryptData`: Payment Wrapper
Operations:
- `Decrypt payment data`
Suggested use:
- Paste ciphertext into the input field as hex.
- Choose a payment-facing profile for AES, TDES, or the implemented DUKPT-TDES wrapper modes.
- Provide the direct key or BDK plus KSN, and add the IV when required.
## 5) AWS `ReEncryptData`: Symmetric Rewrap
Operations: Operations:
- `AES Decrypt` or `Triple DES Decrypt` - `AES Decrypt` or `Triple DES Decrypt`
- `AES Encrypt` or `Triple DES Encrypt` - `AES Encrypt` or `Triple DES Encrypt`
@ -77,7 +95,16 @@ Notes:
- This covers the software-visible decrypt-then-encrypt pattern. - This covers the software-visible decrypt-then-encrypt pattern.
- It does not model AWS wrapped-key handling or HSM-side key custody. - It does not model AWS wrapped-key handling or HSM-side key custody.
## 4) AWS `GenerateMac`: HMAC ## 6) AWS `ReEncryptData`: Payment Wrapper
Operations:
- `Re-encrypt payment data`
Suggested use:
- Paste source ciphertext into the input field as hex.
- Define the source decrypt profile and the target encrypt profile in one operation.
- Use this as the payment-facing version of the decrypt-then-encrypt recipe chain.
## 7) AWS `GenerateMac`: HMAC
Operations: Operations:
- `From Hex` - `From Hex`
- `HMAC` - `HMAC`
@ -89,7 +116,7 @@ Suggested use:
- Run `HMAC` with the appropriate key and hash function. - Run `HMAC` with the appropriate key and hash function.
- If AWS truncates the MAC, use `Take bytes` to keep the leftmost bytes that match `MacLength`. - If AWS truncates the MAC, use `Take bytes` to keep the leftmost bytes that match `MacLength`.
## 5) AWS `GenerateMac`: CMAC ## 8) AWS `GenerateMac`: CMAC
Operations: Operations:
- `From Hex` - `From Hex`
- `CMAC` - `CMAC`
@ -101,7 +128,7 @@ Suggested use:
- Run `CMAC` with `Encryption algorithm` set to `AES` or `Triple DES`. - Run `CMAC` with `Encryption algorithm` set to `AES` or `Triple DES`.
- Use `Take bytes` to match the requested `MacLength` if truncation is required. - Use `Take bytes` to match the requested `MacLength` if truncation is required.
## 6) AWS `VerifyMac`: Recompute And Compare ## 9) AWS `VerifyMac`: Recompute And Compare
Operations: Operations:
- `Verify payment MAC` - `Verify payment MAC`
@ -113,7 +140,7 @@ Notes:
- This covers the implemented static-key HMAC/CMAC and DUKPT-CMAC wrapper modes directly. - This covers the implemented static-key HMAC/CMAC and DUKPT-CMAC wrapper modes directly.
- ISO 9797, EMV MAC, and AS2805-specific verification are still partial gaps. - ISO 9797, EMV MAC, and AS2805-specific verification are still partial gaps.
## 7) AWS `GenerateMac`: Payment Wrapper ## 10) AWS `GenerateMac`: Payment Wrapper
Operations: Operations:
- `Generate payment MAC` - `Generate payment MAC`
@ -125,7 +152,7 @@ Notes:
- This wrapper exists for usability so payment users can stay in the `Payments` category without needing to know which low-level primitive is underneath. - This wrapper exists for usability so payment users can stay in the `Payments` category without needing to know which low-level primitive is underneath.
- It intentionally reuses the existing generic `HMAC` and `CMAC` implementations. - It intentionally reuses the existing generic `HMAC` and `CMAC` implementations.
## 8) AWS `GenerateCardValidationData`: CVV / CVV2 / iCVV ## 11) AWS `GenerateCardValidationData`: CVV / CVV2 / iCVV
Operations: Operations:
- `Generate card validation data` - `Generate card validation data`
@ -138,7 +165,7 @@ Notes:
- This directly covers software generation of CVV/CVV2/iCVV-style values. - This directly covers software generation of CVV/CVV2/iCVV-style values.
- Assumption: CVV2 forces service code `000` and iCVV forces `999`. - Assumption: CVV2 forces service code `000` and iCVV forces `999`.
## 9) AWS `VerifyCardValidationData`: CVV / CVV2 / iCVV ## 12) AWS `VerifyCardValidationData`: CVV / CVV2 / iCVV
Operations: Operations:
- `Verify card validation data` - `Verify card validation data`
@ -152,7 +179,7 @@ Notes:
## Partial Recipe Starters ## Partial Recipe Starters
## 10) AWS `EncryptData` / `DecryptData`: DUKPT-Derived Symmetric Flows ## 13) AWS `EncryptData` / `DecryptData`: DUKPT-Derived Symmetric Flows
Operations: Operations:
- `Derive DUKPT key` - `Derive DUKPT key`
- `AES Encrypt` or `AES Decrypt` or `Triple DES Encrypt` or `Triple DES Decrypt` - `AES Encrypt` or `AES Decrypt` or `Triple DES Encrypt` or `Triple DES Decrypt`
@ -165,20 +192,20 @@ Notes:
- This is useful for offline vector work. - This is useful for offline vector work.
- It does not claim one-to-one parity with every AWS DUKPT encryption attribute combination. - It does not claim one-to-one parity with every AWS DUKPT encryption attribute combination.
## 11) AWS `VerifyAuthRequestCryptogram`: EMV ARQC Check ## 14) AWS `VerifyAuthRequestCryptogram`: EMV ARQC Check
Operations: Operations:
- `Generate EMV ARQC` - `Verify EMV ARQC`
Suggested use: Suggested use:
- Paste the already-assembled EMV authorization-request preimage into the input field as hex. - Paste the already-assembled EMV authorization-request preimage into the input field as hex.
- Provide the already-derived AES session key and cryptogram length. - Provide the already-derived AES session key and cryptogram length.
- Compare the result to the incoming ARQC. - Provide the incoming ARQC and let the wrapper recompute and compare it.
Notes: Notes:
- This is only practical when the session key and exact preimage assembly are already known. - This is only practical when the session key and exact preimage assembly are already known.
- It is a good fit for AES-CMAC-based profiles, not a full generic EMV verifier. - It is a good fit for AES-CMAC-based profiles, not a full generic EMV verifier.
## 12) AWS `TranslateKeyMaterial`: ECDH And Wrapped-Key Inspection ## 15) AWS `TranslateKeyMaterial`: ECDH And Wrapped-Key Inspection
Operations: Operations:
- `Derive ECDH key material` - `Derive ECDH key material`
- `Parse TR-31 key block` - `Parse TR-31 key block`
@ -192,7 +219,7 @@ Notes:
- This helps with interoperability debugging. - This helps with interoperability debugging.
- It does not recreate AWSs HSM-side translate-and-rewrap behavior. - It does not recreate AWSs HSM-side translate-and-rewrap behavior.
## 13) AWS `GenerateMac`: EMV MAC Preimage Review ## 16) AWS `GenerateMac`: EMV MAC Preimage Review
Operations: Operations:
- `From Hex` - `From Hex`
- `CMAC` - `CMAC`
@ -205,9 +232,9 @@ Notes:
- AWS documents `GenerateMac` as supporting EMV MAC. - AWS documents `GenerateMac` as supporting EMV MAC.
- This fork does not yet have a dedicated EMV MAC operation, so this remains a profile-specific starter rather than a generic implementation. - This fork does not yet have a dedicated EMV MAC operation, so this remains a profile-specific starter rather than a generic implementation.
## 14) AWS `GeneratePinData`: Clear PIN Block Build ## 17) AWS `GeneratePinData`: Clear PIN Block Wrapper
Operations: Operations:
- `Build PIN block` - `Generate payment PIN data`
Suggested use: Suggested use:
- Paste the clear PIN into the input field. - Paste the clear PIN into the input field.
@ -218,9 +245,9 @@ Notes:
- This is useful for software test harnesses that need deterministic clear PIN-block construction before encryption. - This is useful for software test harnesses that need deterministic clear PIN-block construction before encryption.
- It does not yet implement PVV generation, IBM 3624 offsets, or encrypted AWS response semantics. - It does not yet implement PVV generation, IBM 3624 offsets, or encrypted AWS response semantics.
## 15) AWS `TranslatePinData`: Clear PIN Block Translation ## 18) AWS `TranslatePinData`: Clear PIN Block Wrapper
Operations: Operations:
- `Translate PIN block` - `Translate payment PIN data`
Suggested use: Suggested use:
- Paste the source clear PIN block into the input field as hex. - Paste the source clear PIN block into the input field as hex.
@ -231,13 +258,13 @@ Notes:
- This is a software emulation helper for test-vector work. - This is a software emulation helper for test-vector work.
- It does not yet emulate encrypted HSM-bound translation between PEK, BDK, or ECDH-derived keys. - It does not yet emulate encrypted HSM-bound translation between PEK, BDK, or ECDH-derived keys.
## 16) AWS `VerifyPinData`: Clear PIN Block Inspection ## 19) AWS `VerifyPinData`: Clear PIN Block Wrapper
Operations: Operations:
- `Parse PIN block` - `Verify payment PIN data`
Suggested use: Suggested use:
- Paste the clear PIN block into the input field as hex. - Paste the clear PIN block into the input field as hex.
- Decode the PIN-block structure and compare the recovered PIN to your expected test data. - Provide the expected clear PIN and let the wrapper decode and compare it.
Notes: Notes:
- This is only structural verification today. - This is only structural verification today.

View File

@ -32,7 +32,22 @@ Suggested use:
- Derive IPEK from BDK + KSN. - Derive IPEK from BDK + KSN.
- Derive base session key and apply a variant mask (`PIN`, `MAC Request`, `MAC Response`, `Data`). - Derive base session key and apply a variant mask (`PIN`, `MAC Request`, `MAC Response`, `Data`).
## 6) PIN Block Build / Parse / Translate ## 6) Payment Data Encrypt / Decrypt / Re-encrypt
Operations:
- `Encrypt payment data`
- `Decrypt payment data`
- `Re-encrypt payment data`
Suggested use:
- Paste the message or ciphertext into the input field as hex.
- Choose a payment-facing cipher profile for AES, TDES, or DUKPT-derived TDES.
- Provide the direct key or BDK plus KSN, then add the IV when the selected mode requires one.
Scope note:
- These wrappers currently cover AES CBC/CTR/ECB, TDES CBC/ECB, and DUKPT-derived TDES CBC/ECB.
- They are intended for software test harnesses and intentionally reuse the existing generic cipher implementations underneath.
## 7) PIN Block Build / Parse / Translate
Operations: Operations:
- `Build PIN block` - `Build PIN block`
- `Parse PIN block` - `Parse PIN block`
@ -47,7 +62,21 @@ Scope note:
- This starter currently covers clear software test blocks for ISO formats 0, 1, and 3. - This starter currently covers clear software test blocks for ISO formats 0, 1, and 3.
- It does not yet generate PVV, IBM 3624 offsets, or encrypted PEK/BDK translation flows by itself. - It does not yet generate PVV, IBM 3624 offsets, or encrypted PEK/BDK translation flows by itself.
## 7) Card Validation Data (CVV / CVV2 / iCVV) ## 8) Payment PIN Data Wrappers
Operations:
- `Generate payment PIN data`
- `Translate payment PIN data`
- `Verify payment PIN data`
Suggested use:
- Use these wrappers when you want AWS-style PIN-data naming instead of the lower-level PIN-block operations.
- They currently cover clear ISO 9564 formats 0, 1, and 3 by delegating to the existing build, translate, and parse operations.
Scope note:
- This is still clear-PIN-block coverage only.
- Encrypted PIN data, PVV, and IBM 3624 are still future additions.
## 9) Card Validation Data (CVV / CVV2 / iCVV)
Operations: Operations:
- `Generate card validation data` - `Generate card validation data`
- `Verify card validation data` - `Verify card validation data`
@ -62,7 +91,7 @@ Scope note:
- CVV2 forces service code `000` and iCVV forces `999`. - CVV2 forces service code `000` and iCVV forces `999`.
- It does not try to emulate scheme-specific dCVV, token CVV, or issuer-host formatting differences beyond the common decimalization flow. - It does not try to emulate scheme-specific dCVV, token CVV, or issuer-host formatting differences beyond the common decimalization flow.
## 8) Payment MAC Generation And Verification ## 10) Payment MAC Generation And Verification
Operations: Operations:
- `Generate payment MAC` - `Generate payment MAC`
- `Verify payment MAC` - `Verify payment MAC`
@ -77,9 +106,10 @@ Scope note:
- Current DUKPT coverage derives TDES session keys and applies TDES-CMAC for request and response MAC variants. - Current DUKPT coverage derives TDES session keys and applies TDES-CMAC for request and response MAC variants.
- ISO 9797, EMV session-derivation MAC, and AS2805 are still future additions. - ISO 9797, EMV session-derivation MAC, and AS2805 are still future additions.
## 9) EMV ARQC Generation (AES-CMAC Profile) ## 11) EMV ARQC Generation And Verification (AES-CMAC Profile)
Operations: Operations:
- `Generate EMV ARQC` - `Generate EMV ARQC`
- `Verify EMV ARQC`
Suggested use: Suggested use:
- Paste the already-assembled ARQC input block into the input field as hex. - Paste the already-assembled ARQC input block into the input field as hex.
@ -90,7 +120,7 @@ Scope note:
- This operation is intentionally limited to AES-CMAC-style EMV profiles. - This operation is intentionally limited to AES-CMAC-style EMV profiles.
- It does not derive EMV session keys or assemble CDOL/tag data for you. - It does not derive EMV session keys or assemble CDOL/tag data for you.
## 10) EMV ARPC Generation (AES-CMAC Response Profile) ## 12) EMV ARPC Generation (AES-CMAC Response Profile)
Operations: Operations:
- `Generate EMV ARPC` - `Generate EMV ARPC`
@ -103,7 +133,7 @@ Scope note:
- This operation is intentionally limited to AES-CMAC response profiles where the issuer session key and exact preimage are already known. - This operation is intentionally limited to AES-CMAC response profiles where the issuer session key and exact preimage are already known.
- Legacy 3DES EMV ARQC/ARPC flows are not covered. - Legacy 3DES EMV ARQC/ARPC flows are not covered.
## 11) Combined Message Triage ## 13) Combined Message Triage
Operations: Operations:
- `Parse TR-34 B9 envelope` - `Parse TR-34 B9 envelope`
- `Parse ASN.1 hex string` - `Parse ASN.1 hex string`

View File

@ -581,15 +581,22 @@
"Calculate payment KCV", "Calculate payment KCV",
"Derive ECDH key material", "Derive ECDH key material",
"Derive DUKPT key", "Derive DUKPT key",
"Encrypt payment data",
"Decrypt payment data",
"Re-encrypt payment data",
"Generate payment MAC", "Generate payment MAC",
"Verify payment MAC", "Verify payment MAC",
"Generate card validation data", "Generate card validation data",
"Verify card validation data", "Verify card validation data",
"Generate EMV ARQC", "Generate EMV ARQC",
"Generate EMV ARPC", "Generate EMV ARPC",
"Verify EMV ARQC",
"Build PIN block", "Build PIN block",
"Parse PIN block", "Parse PIN block",
"Translate PIN block" "Translate PIN block",
"Generate payment PIN data",
"Translate payment PIN data",
"Verify payment PIN data"
] ]
}, },
{ {

View File

@ -0,0 +1,209 @@
/**
* @license Apache-2.0
*/
import OperationError from "../errors/OperationError.mjs";
import AESEncrypt from "../operations/AESEncrypt.mjs";
import AESDecrypt from "../operations/AESDecrypt.mjs";
import TripleDESEncrypt from "../operations/TripleDESEncrypt.mjs";
import TripleDESDecrypt from "../operations/TripleDESDecrypt.mjs";
import DeriveDUKPTKey from "../operations/DeriveDUKPTKey.mjs";
const PAYMENT_CIPHER_PROFILES = [
"AES CBC",
"AES CTR",
"AES ECB",
"TDES CBC",
"TDES ECB",
"DUKPT TDES CBC",
"DUKPT TDES ECB",
];
const DUKPT_DATA_VARIANTS = ["None", "Data"];
/**
* Validates hex input.
*
* @param {string} value
* @param {string} name
* @param {boolean} allowEmpty
* @returns {string}
*/
function normalizeHex(value, name, allowEmpty=false) {
const normalized = (value || "").replace(/\s+/g, "").toUpperCase();
if (!normalized.length && allowEmpty) return "";
if (!/^[0-9A-F]+$/.test(normalized) || normalized.length % 2 !== 0) {
throw new OperationError(`${name} must be even-length hex.`);
}
return normalized;
}
/**
* Resolves the working key for the selected cipher profile.
*
* @param {string} profile
* @param {string} keyHex
* @param {string} ksn
* @param {string} dukptVariant
* @returns {{keyHex: string, keyContext: Object}}
*/
function resolveCipherKey(profile, keyHex, ksn, dukptVariant) {
if (!profile.startsWith("DUKPT ")) {
return {
keyHex: normalizeHex(keyHex, "Key"),
keyContext: { keySource: "Direct key input" }
};
}
const normalizedKey = normalizeHex(keyHex, "BDK");
const normalizedKsn = normalizeHex(ksn, "KSN");
const dukpt = new DeriveDUKPTKey();
const derivedKey = dukpt.run(normalizedKey, ["Derive Session Key", normalizedKsn, dukptVariant, false]);
return {
keyHex: derivedKey,
keyContext: {
keySource: "Derived from DUKPT BDK",
ksn: normalizedKsn,
dukptVariant
}
};
}
/**
* Encrypts payment data using the selected profile.
*
* @param {string} inputHex
* @param {string} profile
* @param {string} keyHex
* @param {string} ivHex
* @param {string} ksn
* @param {string} dukptVariant
* @returns {Object}
*/
function encryptPaymentData(inputHex, profile, keyHex, ivHex, ksn, dukptVariant) {
const plaintextHex = normalizeHex(inputHex, "Input data");
const normalizedIv = normalizeHex(ivHex, "IV", true);
const { keyHex: effectiveKeyHex, keyContext } = resolveCipherKey(profile, keyHex, ksn, dukptVariant);
let ciphertextHex;
if (profile.startsWith("AES ")) {
const aes = new AESEncrypt();
const mode = profile.substring(4);
ciphertextHex = aes.run(plaintextHex, [
{ string: effectiveKeyHex, option: "Hex" },
{ string: normalizedIv, option: "Hex" },
mode,
"Hex",
"Hex",
{ string: "", option: "Hex" }
]).toUpperCase();
} else {
const tdes = new TripleDESEncrypt();
const mode = profile.endsWith("CBC") ? "CBC" : "ECB";
ciphertextHex = tdes.run(plaintextHex, [
{ string: effectiveKeyHex, option: "Hex" },
{ string: normalizedIv, option: "Hex" },
mode,
"Hex",
"Hex"
]).toUpperCase();
}
return {
profile,
plaintextHex,
ciphertextHex,
ivHex: normalizedIv,
...keyContext
};
}
/**
* Decrypts payment data using the selected profile.
*
* @param {string} inputHex
* @param {string} profile
* @param {string} keyHex
* @param {string} ivHex
* @param {string} ksn
* @param {string} dukptVariant
* @returns {Object}
*/
function decryptPaymentData(inputHex, profile, keyHex, ivHex, ksn, dukptVariant) {
const ciphertextHex = normalizeHex(inputHex, "Input data");
const normalizedIv = normalizeHex(ivHex, "IV", true);
const { keyHex: effectiveKeyHex, keyContext } = resolveCipherKey(profile, keyHex, ksn, dukptVariant);
let plaintextHex;
if (profile.startsWith("AES ")) {
const aes = new AESDecrypt();
const mode = profile.substring(4);
plaintextHex = aes.run(ciphertextHex, [
{ string: effectiveKeyHex, option: "Hex" },
{ string: normalizedIv, option: "Hex" },
mode,
"Hex",
"Hex",
{ string: "", option: "Hex" },
{ string: "", option: "Hex" }
]).toUpperCase();
} else {
const tdes = new TripleDESDecrypt();
const mode = profile.endsWith("CBC") ? "CBC" : "ECB";
plaintextHex = tdes.run(ciphertextHex, [
{ string: effectiveKeyHex, option: "Hex" },
{ string: normalizedIv, option: "Hex" },
mode,
"Hex",
"Hex"
]).toUpperCase();
}
return {
profile,
ciphertextHex,
plaintextHex,
ivHex: normalizedIv,
...keyContext
};
}
/**
* Re-encrypts payment data by decrypting under one profile and encrypting under another.
*
* @param {string} inputHex
* @param {Object} params
* @returns {Object}
*/
function reEncryptPaymentData(inputHex, params) {
const decrypted = decryptPaymentData(
inputHex,
params.sourceProfile,
params.sourceKeyHex,
params.sourceIvHex,
params.sourceKsn,
params.sourceDukptVariant
);
const encrypted = encryptPaymentData(
decrypted.plaintextHex,
params.targetProfile,
params.targetKeyHex,
params.targetIvHex,
params.targetKsn,
params.targetDukptVariant
);
return {
source: decrypted,
target: encrypted
};
}
export {
DUKPT_DATA_VARIANTS,
PAYMENT_CIPHER_PROFILES,
decryptPaymentData,
encryptPaymentData,
reEncryptPaymentData,
};

View File

@ -0,0 +1,54 @@
/**
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import { DUKPT_DATA_VARIANTS, PAYMENT_CIPHER_PROFILES, decryptPaymentData } from "../lib/PaymentDataCipher.mjs";
/**
* Decrypt payment data operation.
*/
class DecryptPaymentData extends Operation {
/**
* DecryptPaymentData constructor.
*/
constructor() {
super();
this.name = "Decrypt payment data";
this.module = "Payment";
this.description = "Paste ciphertext into the input field as hex and decrypt it using a payment-facing cipher wrapper.<br><br><b>Input:</b> ciphertext hex.<br><b>Arguments:</b> choose the cipher profile, provide a direct key or BDK, add IV where needed, and provide KSN plus DUKPT variant when using a DUKPT profile.";
this.inlineHelp = "<strong>Input:</strong> ciphertext hex.<br><strong>Args:</strong> choose AES, TDES, or DUKPT-wrapped TDES, then provide key, IV, and optional KSN context.";
this.testDataSamples = [
{
name: "AES CBC sample",
input: "76D0627DA1D290436E21A4AF7FCA94B7177C1FC94173D442E36EE79D7CA0E461",
args: ["AES CBC", "00112233445566778899AABBCCDDEEFF", "000102030405060708090A0B0C0D0E0F", "", "Data", false]
}
];
this.infoURL = "https://docs.aws.amazon.com/payment-cryptography/latest/DataAPIReference/API_DecryptData.html";
this.inputType = "string";
this.outputType = "string";
this.args = [
{ name: "Cipher profile", type: "option", value: PAYMENT_CIPHER_PROFILES, comment: "Select the payment-facing decryption profile. DUKPT profiles derive a session key first, then run TDES decryption." },
{ name: "Key / BDK", type: "string", value: "", comment: "Provide the clear AES/TDES key for static profiles, or the clear BDK for DUKPT profiles." },
{ name: "IV (hex)", type: "string", value: "", comment: "Initialization vector as hex. Leave blank for ECB. Use 16 bytes for AES CBC/CTR and 8 bytes for TDES CBC." },
{ name: "KSN (DUKPT only)", type: "string", value: "", comment: "Required only for DUKPT profiles. Provide the full 10-byte KSN as hex." },
{ name: "DUKPT variant", type: "option", value: DUKPT_DATA_VARIANTS, defaultIndex: 1, comment: "Applies only to DUKPT profiles. Use <code>Data</code> for the current data-key masking behavior in this fork." },
{ name: "Output as JSON", type: "boolean", value: false, comment: "When enabled, returns the effective cipher context and plaintext." },
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [profile, keyHex, ivHex, ksn, dukptVariant, outputJson] = args;
const result = decryptPaymentData(input, profile, keyHex, ivHex, ksn, dukptVariant);
return outputJson ? JSON.stringify(result, null, 4) : result.plaintextHex;
}
}
export default DecryptPaymentData;

View File

@ -0,0 +1,54 @@
/**
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import { DUKPT_DATA_VARIANTS, PAYMENT_CIPHER_PROFILES, encryptPaymentData } from "../lib/PaymentDataCipher.mjs";
/**
* Encrypt payment data operation.
*/
class EncryptPaymentData extends Operation {
/**
* EncryptPaymentData constructor.
*/
constructor() {
super();
this.name = "Encrypt payment data";
this.module = "Payment";
this.description = "Paste plaintext into the input field as hex and encrypt it using a payment-facing cipher wrapper.<br><br><b>Input:</b> plaintext hex.<br><b>Arguments:</b> choose the cipher profile, provide a direct key or BDK, add IV where needed, and provide KSN plus DUKPT variant when using a DUKPT profile.";
this.inlineHelp = "<strong>Input:</strong> plaintext hex.<br><strong>Args:</strong> choose AES, TDES, or DUKPT-wrapped TDES, then provide key, IV, and optional KSN context.";
this.testDataSamples = [
{
name: "AES CBC sample",
input: "00112233445566778899AABBCCDDEEFF",
args: ["AES CBC", "00112233445566778899AABBCCDDEEFF", "000102030405060708090A0B0C0D0E0F", "", "Data", false]
}
];
this.infoURL = "https://docs.aws.amazon.com/payment-cryptography/latest/DataAPIReference/API_EncryptData.html";
this.inputType = "string";
this.outputType = "string";
this.args = [
{ name: "Cipher profile", type: "option", value: PAYMENT_CIPHER_PROFILES, comment: "Select the payment-facing encryption profile. DUKPT profiles derive a session key first, then run TDES encryption." },
{ name: "Key / BDK", type: "string", value: "", comment: "Provide the clear AES/TDES key for static profiles, or the clear BDK for DUKPT profiles." },
{ name: "IV (hex)", type: "string", value: "", comment: "Initialization vector as hex. Leave blank for ECB. Use 16 bytes for AES CBC/CTR and 8 bytes for TDES CBC." },
{ name: "KSN (DUKPT only)", type: "string", value: "", comment: "Required only for DUKPT profiles. Provide the full 10-byte KSN as hex." },
{ name: "DUKPT variant", type: "option", value: DUKPT_DATA_VARIANTS, defaultIndex: 1, comment: "Applies only to DUKPT profiles. Use <code>Data</code> for the current data-key masking behavior in this fork." },
{ name: "Output as JSON", type: "boolean", value: false, comment: "When enabled, returns the effective cipher context and ciphertext." },
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [profile, keyHex, ivHex, ksn, dukptVariant, outputJson] = args;
const result = encryptPaymentData(input, profile, keyHex, ivHex, ksn, dukptVariant);
return outputJson ? JSON.stringify(result, null, 4) : result.ciphertextHex;
}
}
export default EncryptPaymentData;

View File

@ -0,0 +1,54 @@
/**
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import BuildPINBlock from "./BuildPINBlock.mjs";
/**
* Generate payment PIN data operation.
*/
class GeneratePaymentPINData extends Operation {
/**
* GeneratePaymentPINData constructor.
*/
constructor() {
super();
this.name = "Generate payment PIN data";
this.module = "Payment";
this.description = "Paste the clear PIN into the input field and generate clear PIN-block test data using an AWS-style payment wrapper.<br><br><b>Input:</b> clear PIN digits.<br><b>Arguments:</b> choose the PIN-block format, provide the PAN when required, and optionally return structured JSON.";
this.inlineHelp = "<strong>Input:</strong> clear PIN digits.<br><strong>Args:</strong> choose the block format and provide the PAN for PAN-bound formats.";
this.testDataSamples = [
{
name: "Format 0 sample",
input: "1234",
args: ["ISO Format 0", "5432101234567890", false, false]
}
];
this.infoURL = "https://docs.aws.amazon.com/payment-cryptography/latest/DataAPIReference/API_GeneratePinData.html";
this.inputType = "string";
this.outputType = "string";
this.args = [
{ name: "Format", type: "option", value: ["ISO Format 0", "ISO Format 1", "ISO Format 3"], comment: "Clear ISO 9564 format to generate. This wrapper currently supports only formats 0, 1, and 3." },
{ name: "Primary account number", type: "string", value: "", comment: "Required for formats 0 and 3. Enter digits only." },
{ name: "Randomize fill digits", type: "boolean", value: false, comment: "Affects only formats 1 and 3. Leave disabled for repeatable vectors." },
{ name: "Output as JSON", type: "boolean", value: false, comment: "When enabled, returns the clear PIN block plus the source context." },
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [format, pan, randomizeFill, outputJson] = args;
const builder = new BuildPINBlock();
const pinBlockHex = builder.run(input, [format, pan, randomizeFill]);
const result = { format, pan, pinBlockHex };
return outputJson ? JSON.stringify(result, null, 4) : pinBlockHex;
}
}
export default GeneratePaymentPINData;

View File

@ -0,0 +1,70 @@
/**
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import { DUKPT_DATA_VARIANTS, PAYMENT_CIPHER_PROFILES, reEncryptPaymentData } from "../lib/PaymentDataCipher.mjs";
/**
* Re-encrypt payment data operation.
*/
class ReEncryptPaymentData extends Operation {
/**
* ReEncryptPaymentData constructor.
*/
constructor() {
super();
this.name = "Re-encrypt payment data";
this.module = "Payment";
this.description = "Paste ciphertext into the input field as hex, decrypt it under the source key context, then re-encrypt it under the target key context.<br><br><b>Input:</b> source ciphertext hex.<br><b>Arguments:</b> choose source and target profiles, provide the corresponding key or BDK material, add IVs, and supply KSN plus DUKPT variant when using DUKPT profiles.";
this.inlineHelp = "<strong>Input:</strong> source ciphertext hex.<br><strong>Args:</strong> define the source decrypt context, then the target encrypt context.";
this.testDataSamples = [
{
name: "AES CBC to TDES CBC sample",
input: "76D0627DA1D290436E21A4AF7FCA94B7177C1FC94173D442E36EE79D7CA0E461",
args: ["AES CBC", "00112233445566778899AABBCCDDEEFF", "000102030405060708090A0B0C0D0E0F", "", "Data", "TDES CBC", "0123456789ABCDEFFEDCBA9876543210", "1234567890ABCDEF", "", "Data", false]
}
];
this.infoURL = "https://docs.aws.amazon.com/payment-cryptography/latest/DataAPIReference/API_ReEncryptData.html";
this.inputType = "string";
this.outputType = "string";
this.args = [
{ name: "Source profile", type: "option", value: PAYMENT_CIPHER_PROFILES, comment: "How to decrypt the input ciphertext." },
{ name: "Source key / BDK", type: "string", value: "", comment: "Source clear AES/TDES key or DUKPT BDK." },
{ name: "Source IV (hex)", type: "string", value: "", comment: "Source IV as hex. Leave blank for ECB." },
{ name: "Source KSN (DUKPT only)", type: "string", value: "", comment: "Required only for DUKPT source profiles." },
{ name: "Source DUKPT variant", type: "option", value: DUKPT_DATA_VARIANTS, defaultIndex: 1, comment: "Applies only to DUKPT source profiles." },
{ name: "Target profile", type: "option", value: PAYMENT_CIPHER_PROFILES, comment: "How to encrypt the recovered plaintext." },
{ name: "Target key / BDK", type: "string", value: "", comment: "Target clear AES/TDES key or DUKPT BDK." },
{ name: "Target IV (hex)", type: "string", value: "", comment: "Target IV as hex. Leave blank for ECB." },
{ name: "Target KSN (DUKPT only)", type: "string", value: "", comment: "Required only for DUKPT target profiles." },
{ name: "Target DUKPT variant", type: "option", value: DUKPT_DATA_VARIANTS, defaultIndex: 1, comment: "Applies only to DUKPT target profiles." },
{ name: "Output as JSON", type: "boolean", value: false, comment: "When enabled, returns both the source decrypt and target encrypt contexts." },
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [sourceProfile, sourceKeyHex, sourceIvHex, sourceKsn, sourceDukptVariant, targetProfile, targetKeyHex, targetIvHex, targetKsn, targetDukptVariant, outputJson] = args;
const result = reEncryptPaymentData(input, {
sourceProfile,
sourceKeyHex,
sourceIvHex,
sourceKsn,
sourceDukptVariant,
targetProfile,
targetKeyHex,
targetIvHex,
targetKsn,
targetDukptVariant,
});
return outputJson ? JSON.stringify(result, null, 4) : result.target.ciphertextHex;
}
}
export default ReEncryptPaymentData;

View File

@ -0,0 +1,52 @@
/**
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import TranslatePINBlock from "./TranslatePINBlock.mjs";
/**
* Translate payment PIN data operation.
*/
class TranslatePaymentPINData extends Operation {
/**
* TranslatePaymentPINData constructor.
*/
constructor() {
super();
this.name = "Translate payment PIN data";
this.module = "Payment";
this.description = "Paste a clear PIN block into the input field as hex and translate it between supported clear ISO 9564 formats using an AWS-style wrapper.<br><br><b>Input:</b> clear PIN block hex.<br><b>Arguments:</b> choose source and target formats, provide PAN values when required, and optionally randomize target filler digits.";
this.inlineHelp = "<strong>Input:</strong> source clear PIN block hex.<br><strong>Args:</strong> define source and target format plus PAN context.";
this.testDataSamples = [
{
name: "Format 0 to 1 sample",
input: "041215FEDCBA9876",
args: ["ISO Format 0", "5432101234567890", "ISO Format 1", "", false]
}
];
this.infoURL = "https://docs.aws.amazon.com/payment-cryptography/latest/DataAPIReference/API_TranslatePinData.html";
this.inputType = "string";
this.outputType = "string";
this.args = [
{ name: "Source format", type: "option", value: ["ISO Format 0", "ISO Format 1", "ISO Format 3"], comment: "How to decode the input PIN block." },
{ name: "Source PAN", type: "string", value: "", comment: "Required for source formats 0 and 3." },
{ name: "Target format", type: "option", value: ["ISO Format 0", "ISO Format 1", "ISO Format 3"], defaultIndex: 1, comment: "Target clear PIN-block format." },
{ name: "Target PAN", type: "string", value: "", comment: "Required for target formats 0 and 3." },
{ name: "Randomize target fill digits", type: "boolean", value: false, comment: "Affects only target formats 1 and 3." },
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const translator = new TranslatePINBlock();
return translator.run(input, args);
}
}
export default TranslatePaymentPINData;

View File

@ -0,0 +1,56 @@
/**
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import { generateEmvAesCmacCryptogram } from "../lib/EmvCryptogram.mjs";
/**
* Verify EMV ARQC operation.
*/
class VerifyEMVARQC extends Operation {
/**
* VerifyEMVARQC constructor.
*/
constructor() {
super();
this.name = "Verify EMV ARQC";
this.module = "Payment";
this.description = "Paste the already-assembled EMV authorization-request input into the input field as hex and verify an AES-CMAC-based ARQC.<br><br><b>Input:</b> preassembled ARQC input data as hex.<br><b>Arguments:</b> provide the EMV session key, cryptogram length, and expected ARQC hex value.<br><br>This operation intentionally covers only AES-CMAC-style EMV profiles where the session key and preimage are already known.";
this.inlineHelp = "<strong>Input:</strong> preassembled ARQC data as hex.<br><strong>Args:</strong> provide the AES session key and expected ARQC.";
this.testDataSamples = [
{
name: "AES-CMAC ARQC verification sample",
input: "000102030405060708090A0B0C0D0E0F",
args: ["00112233445566778899AABBCCDDEEFF", 8, "C1F732B52FB20CAA"]
}
];
this.infoURL = "https://docs.aws.amazon.com/payment-cryptography/latest/DataAPIReference/API_VerifyAuthRequestCryptogram.html";
this.inputType = "string";
this.outputType = "string";
this.args = [
{ name: "Session key (hex)", type: "string", value: "", comment: "Provide the already-derived EMV session key as hex. This wrapper does not derive EMV session keys." },
{ name: "Cryptogram bytes", type: "number", value: 8, min: 1, max: 16, comment: "Number of leftmost CMAC bytes to compare." },
{ name: "Expected ARQC (hex)", type: "string", value: "", comment: "Expected ARQC value as hex." },
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [sessionKeyHex, cryptogramBytes, expectedArqc] = args;
const generated = generateEmvAesCmacCryptogram(input, sessionKeyHex, cryptogramBytes);
const normalizedExpected = (expectedArqc || "").replace(/\s+/g, "").toUpperCase();
return JSON.stringify({
...generated,
expectedArqcHex: normalizedExpected,
valid: generated.cryptogramHex === normalizedExpected
}, null, 4);
}
}
export default VerifyEMVARQC;

View File

@ -0,0 +1,56 @@
/**
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import ParsePINBlock from "./ParsePINBlock.mjs";
/**
* Verify payment PIN data operation.
*/
class VerifyPaymentPINData extends Operation {
/**
* VerifyPaymentPINData constructor.
*/
constructor() {
super();
this.name = "Verify payment PIN data";
this.module = "Payment";
this.description = "Paste a clear PIN block into the input field as hex and verify it against an expected PIN using an AWS-style wrapper.<br><br><b>Input:</b> clear PIN block hex.<br><b>Arguments:</b> choose the format, provide the PAN when required, and supply the expected clear PIN.";
this.inlineHelp = "<strong>Input:</strong> clear PIN block hex.<br><strong>Args:</strong> define the PIN-block format, PAN context, and expected PIN.";
this.testDataSamples = [
{
name: "Format 0 verification sample",
input: "041215FEDCBA9876",
args: ["ISO Format 0", "5432101234567890", "1234"]
}
];
this.infoURL = "https://docs.aws.amazon.com/payment-cryptography/latest/DataAPIReference/API_VerifyPinData.html";
this.inputType = "string";
this.outputType = "string";
this.args = [
{ name: "Format", type: "option", value: ["ISO Format 0", "ISO Format 1", "ISO Format 3"], comment: "How to decode the input PIN block." },
{ name: "Primary account number", type: "string", value: "", comment: "Required for formats 0 and 3." },
{ name: "Expected PIN", type: "string", value: "", comment: "Clear PIN digits to compare against." },
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [format, pan, expectedPin] = args;
const parser = new ParsePINBlock();
const parsed = JSON.parse(parser.run(input, [format, pan]));
return JSON.stringify({
...parsed,
expectedPin,
valid: parsed.pin === String(expectedPin || "")
}, null, 4);
}
}
export default VerifyPaymentPINData;

View File

@ -255,6 +255,57 @@ TestRegister.addTests([
} }
] ]
}, },
{
name: "Verify EMV ARQC: AES-CMAC profile",
input: "000102030405060708090A0B0C0D0E0F",
expectedOutput: JSON.stringify({
inputHex: "000102030405060708090A0B0C0D0E0F",
outputBytes: 8,
fullMacHex: "C1F732B52FB20CAAB58D5B6C78CBD514",
cryptogramHex: "C1F732B52FB20CAA",
expectedArqcHex: "C1F732B52FB20CAA",
valid: true
}, null, 4),
recipeConfig: [
{
op: "Verify EMV ARQC",
args: ["00112233445566778899AABBCCDDEEFF", 8, "C1F732B52FB20CAA"]
}
]
},
{
name: "Encrypt payment data: AES CBC",
input: "00112233445566778899AABBCCDDEEFF",
expectedOutput: "67423557CA0509243B9EE04A5DA3448AA397F6D29B5C8BCE065D9CDC936B7F9B",
recipeConfig: [
{
op: "Encrypt payment data",
args: ["AES CBC", "00112233445566778899AABBCCDDEEFF", "000102030405060708090A0B0C0D0E0F", "", "Data", false]
}
]
},
{
name: "Decrypt payment data: AES CBC",
input: "67423557CA0509243B9EE04A5DA3448AA397F6D29B5C8BCE065D9CDC936B7F9B",
expectedOutput: "00112233445566778899AABBCCDDEEFF",
recipeConfig: [
{
op: "Decrypt payment data",
args: ["AES CBC", "00112233445566778899AABBCCDDEEFF", "000102030405060708090A0B0C0D0E0F", "", "Data", false]
}
]
},
{
name: "Re-encrypt payment data: AES CBC to TDES CBC",
input: "67423557CA0509243B9EE04A5DA3448AA397F6D29B5C8BCE065D9CDC936B7F9B",
expectedOutput: "C47BC6E91A9D566F649D750BCE1CE9889FB5AE1489A16692",
recipeConfig: [
{
op: "Re-encrypt payment data",
args: ["AES CBC", "00112233445566778899AABBCCDDEEFF", "000102030405060708090A0B0C0D0E0F", "", "Data", "TDES CBC", "0123456789ABCDEFFEDCBA9876543210", "1234567890ABCDEF", "", "Data", false]
}
]
},
{ {
name: "Generate payment MAC: AES-CMAC", name: "Generate payment MAC: AES-CMAC",
input: "1122334455667788", input: "1122334455667788",
@ -309,6 +360,63 @@ TestRegister.addTests([
} }
] ]
}, },
{
name: "Generate payment PIN data: ISO Format 0",
input: "1234",
expectedOutput: "041215FEDCBA9876",
recipeConfig: [
{
op: "Generate payment PIN data",
args: ["ISO Format 0", "5432101234567890", false, false]
}
]
},
{
name: "Translate payment PIN data: ISO Format 0 to ISO Format 1",
input: "041215FEDCBA9876",
expectedOutput: JSON.stringify({
source: {
format: "ISO Format 0",
pin: "1234",
pinLength: 4,
pinFieldHex: "041234FFFFFFFFFF",
panFieldHex: "0000210123456789",
blockHex: "041215FEDCBA9876",
fillDigitsHex: "FFFFFFFFFF"
},
target: {
format: "ISO Format 1",
blockHex: "141234FFFFFFFFFF"
}
}, null, 4),
recipeConfig: [
{
op: "Translate payment PIN data",
args: ["ISO Format 0", "5432101234567890", "ISO Format 1", "", false]
}
]
},
{
name: "Verify payment PIN data: ISO Format 0",
input: "041215FEDCBA9876",
expectedOutput: JSON.stringify({
format: "ISO Format 0",
pin: "1234",
pinLength: 4,
pinFieldHex: "041234FFFFFFFFFF",
panFieldHex: "0000210123456789",
blockHex: "041215FEDCBA9876",
fillDigitsHex: "FFFFFFFFFF",
expectedPin: "1234",
valid: true
}, null, 4),
recipeConfig: [
{
op: "Verify payment PIN data",
args: ["ISO Format 0", "5432101234567890", "1234"]
}
]
},
{ {
name: "Derive ECDH key material: raw shared secret", name: "Derive ECDH key material: raw shared secret",
input: ecdhPrivateKey, input: ecdhPrivateKey,