diff --git a/AWS_PAYMENT_CRYPTOGRAPHY_RECIPES.md b/AWS_PAYMENT_CRYPTOGRAPHY_RECIPES.md
index f6f65422..1edfdcc2 100644
--- a/AWS_PAYMENT_CRYPTOGRAPHY_RECIPES.md
+++ b/AWS_PAYMENT_CRYPTOGRAPHY_RECIPES.md
@@ -25,8 +25,8 @@ Coverage legend:
| `EncryptData` | `Direct` / `Partial` | Direct for AES, TDES, RSA. Partial for DUKPT and EMV-derived encryption. |
| `DecryptData` | `Direct` / `Partial` | Direct for AES, TDES, RSA. Partial for DUKPT and EMV-derived decryption. |
| `ReEncryptData` | `Direct` / `Partial` | Direct for plain decrypt-then-encrypt workflows. Partial for DUKPT re-encryption. |
-| `GenerateMac` | `Direct` / `Partial` | Direct for HMAC and CMAC. Partial for DUKPT MAC and EMV MAC flows. |
-| `VerifyMac` | `Direct` / `Partial` | Direct by recomputing and comparing HMAC/CMAC. Partial for DUKPT MAC and EMV MAC 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. |
| `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. |
| `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. |
@@ -103,15 +103,29 @@ Suggested use:
## 6) AWS `VerifyMac`: Recompute And Compare
Operations:
-- `From Hex`
-- `HMAC` or `CMAC`
-- `Take bytes`
+- `Verify payment MAC`
Suggested use:
-- Recompute the MAC using the same starter as `GenerateMac`.
-- Compare the result to the AWS `Mac` value manually or with a follow-on comparison recipe.
+- Paste the message into the input field, choose the MAC method, and provide either the direct key or the DUKPT BDK plus KSN.
+- Supply the expected MAC in hex and let the wrapper recompute and compare it.
-## 7) AWS `GenerateCardValidationData`: CVV / CVV2 / iCVV
+Notes:
+- 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.
+
+## 7) AWS `GenerateMac`: Payment Wrapper
+Operations:
+- `Generate payment MAC`
+
+Suggested use:
+- Paste the message into the input field and choose the payment MAC method that best matches the AWS attributes.
+- Use direct key input for static HMAC or CMAC modes, or provide a BDK plus KSN for the implemented DUKPT CMAC request and response modes.
+
+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.
+- It intentionally reuses the existing generic `HMAC` and `CMAC` implementations.
+
+## 8) AWS `GenerateCardValidationData`: CVV / CVV2 / iCVV
Operations:
- `Generate card validation data`
@@ -124,7 +138,7 @@ Notes:
- This directly covers software generation of CVV/CVV2/iCVV-style values.
- Assumption: CVV2 forces service code `000` and iCVV forces `999`.
-## 8) AWS `VerifyCardValidationData`: CVV / CVV2 / iCVV
+## 9) AWS `VerifyCardValidationData`: CVV / CVV2 / iCVV
Operations:
- `Verify card validation data`
@@ -138,7 +152,7 @@ Notes:
## Partial Recipe Starters
-## 9) AWS `EncryptData` / `DecryptData`: DUKPT-Derived Symmetric Flows
+## 10) AWS `EncryptData` / `DecryptData`: DUKPT-Derived Symmetric Flows
Operations:
- `Derive DUKPT key`
- `AES Encrypt` or `AES Decrypt` or `Triple DES Encrypt` or `Triple DES Decrypt`
@@ -151,20 +165,6 @@ Notes:
- This is useful for offline vector work.
- It does not claim one-to-one parity with every AWS DUKPT encryption attribute combination.
-## 10) AWS `GenerateMac` / `VerifyMac`: DUKPT MAC
-Operations:
-- `Derive DUKPT key`
-- `From Hex`
-- `CMAC` or `HMAC`
-- `Take bytes`
-
-Suggested use:
-- Derive the transaction key from BDK and KSN.
-- Convert `MessageData` from hex and generate the MAC using the derived key.
-
-Notes:
-- Treat this as a lab starter, not proof of parity with AWS’s full DUKPT MAC union attributes.
-
## 11) AWS `VerifyAuthRequestCryptogram`: EMV ARQC Check
Operations:
- `Generate EMV ARQC`
@@ -257,6 +257,7 @@ Why:
If you want closer AWS coverage, the highest-value missing operations are:
1. PIN block encode/decode for ISO 9564 formats 0, 1, 3, and 4.
2. IBM 3624 and VISA PVV generation and verification.
-3. Dedicated EMV MAC and profile-specific EMV session-derivation helpers.
-4. Clear-to-encrypted and encrypted-to-encrypted PIN translation flows.
-5. TR-31 unwrap and rewrap helpers for dynamic-key workflows.
+3. ISO 9797 and AS2805-specific MAC generation and verification.
+4. Dedicated EMV MAC and profile-specific EMV session-derivation helpers.
+5. Clear-to-encrypted and encrypted-to-encrypted PIN translation flows.
+6. TR-31 unwrap and rewrap helpers for dynamic-key workflows.
diff --git a/PAYMENT_RECIPES.md b/PAYMENT_RECIPES.md
index 81d72ee2..8c5ced0f 100644
--- a/PAYMENT_RECIPES.md
+++ b/PAYMENT_RECIPES.md
@@ -62,7 +62,22 @@ Scope note:
- 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.
-## 8) EMV ARQC Generation (AES-CMAC Profile)
+## 8) Payment MAC Generation And Verification
+Operations:
+- `Generate payment MAC`
+- `Verify payment MAC`
+
+Suggested use:
+- Paste the message data into the input field.
+- Choose whether the MAC should use static `HMAC`, static `CMAC`, or DUKPT-derived TDES-CMAC.
+- Provide either a direct MAC key or a BDK plus KSN, depending on the selected method.
+
+Scope note:
+- This wrapper intentionally reuses the existing generic `HMAC` and `CMAC` implementations instead of duplicating crypto code.
+- 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.
+
+## 9) EMV ARQC Generation (AES-CMAC Profile)
Operations:
- `Generate EMV ARQC`
@@ -75,7 +90,7 @@ Scope note:
- 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.
-## 9) EMV ARPC Generation (AES-CMAC Response Profile)
+## 10) EMV ARPC Generation (AES-CMAC Response Profile)
Operations:
- `Generate EMV ARPC`
@@ -88,7 +103,7 @@ Scope note:
- 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.
-## 10) Combined Message Triage
+## 11) Combined Message Triage
Operations:
- `Parse TR-34 B9 envelope`
- `Parse ASN.1 hex string`
diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json
index 47248cf2..72356ef5 100644
--- a/src/core/config/Categories.json
+++ b/src/core/config/Categories.json
@@ -568,11 +568,21 @@
{
"name": "Payments",
"ops": [
+ "HMAC",
+ "CMAC",
+ "AES Encrypt",
+ "AES Decrypt",
+ "Triple DES Encrypt",
+ "Triple DES Decrypt",
+ "AES Key Wrap",
+ "AES Key Unwrap",
"Parse TR-31 key block",
"Parse TR-34 B9 envelope",
"Calculate payment KCV",
"Derive ECDH key material",
"Derive DUKPT key",
+ "Generate payment MAC",
+ "Verify payment MAC",
"Generate card validation data",
"Verify card validation data",
"Generate EMV ARQC",
diff --git a/src/core/lib/PaymentMac.mjs b/src/core/lib/PaymentMac.mjs
new file mode 100644
index 00000000..56fc4e6a
--- /dev/null
+++ b/src/core/lib/PaymentMac.mjs
@@ -0,0 +1,175 @@
+/**
+ * @license Apache-2.0
+ */
+
+import Utils from "../Utils.mjs";
+import OperationError from "../errors/OperationError.mjs";
+import HMAC from "../operations/HMAC.mjs";
+import CMAC from "../operations/CMAC.mjs";
+import DeriveDUKPTKey from "../operations/DeriveDUKPTKey.mjs";
+
+const PAYMENT_MAC_METHODS = [
+ "HMAC SHA-224",
+ "HMAC SHA-256",
+ "HMAC SHA-384",
+ "HMAC SHA-512",
+ "AES-CMAC",
+ "TDES-CMAC",
+ "DUKPT MAC Request CMAC",
+ "DUKPT MAC Response CMAC",
+];
+
+/**
+ * Converts a string input into an ArrayBuffer according to the selected format.
+ *
+ * @param {string} input
+ * @param {string} inputFormat
+ * @returns {ArrayBuffer}
+ */
+function convertInputToBuffer(input, inputFormat) {
+ const byteString = Utils.convertToByteString(input || "", inputFormat);
+ return Utils.strToArrayBuffer(byteString);
+}
+
+/**
+ * Resolves the effective MAC key for the selected method.
+ *
+ * @param {string} method
+ * @param {Object} keySpec
+ * @returns {{keyHex: string, keyContext: Object}}
+ */
+function resolveMacKey(method, keySpec) {
+ const normalizedKey = (keySpec.keyValue || "").replace(/\s+/g, "");
+
+ if (method === "DUKPT MAC Request CMAC" || method === "DUKPT MAC Response CMAC") {
+ if (keySpec.keyFormat !== "Hex") {
+ throw new OperationError("DUKPT BDK must be provided in hex.");
+ }
+ if (!keySpec.ksn) {
+ throw new OperationError("KSN is required for DUKPT MAC methods.");
+ }
+
+ const variant = method === "DUKPT MAC Request CMAC" ? "MAC Request" : "MAC Response";
+ const dukpt = new DeriveDUKPTKey();
+ const keyHex = dukpt.run(normalizedKey, ["Derive Session Key", keySpec.ksn, variant, false]);
+
+ return {
+ keyHex,
+ keyContext: {
+ keySource: "Derived from DUKPT BDK",
+ ksn: keySpec.ksn.replace(/\s+/g, "").toUpperCase(),
+ dukptVariant: variant
+ }
+ };
+ }
+
+ const byteString = Utils.convertToByteString(keySpec.keyValue || "", keySpec.keyFormat);
+ if (!byteString.length) {
+ throw new OperationError("Key material is required.");
+ }
+
+ return {
+ keyHex: byteStringToHex(byteString),
+ keyContext: {
+ keySource: "Direct key input"
+ }
+ };
+}
+
+/**
+ * Converts a byte string into uppercase hex.
+ *
+ * @param {string} byteString
+ * @returns {string}
+ */
+function byteStringToHex(byteString) {
+ return Array.from(byteString, ch => ch.charCodeAt(0).toString(16).padStart(2, "0")).join("").toUpperCase();
+}
+
+/**
+ * Generates a payment MAC using the selected method.
+ *
+ * @param {string} input
+ * @param {string} inputFormat
+ * @param {string} method
+ * @param {string} keyValue
+ * @param {string} keyFormat
+ * @param {string} ksn
+ * @param {number} outputBytes
+ * @returns {Object}
+ */
+function generatePaymentMac(input, inputFormat, method, keyValue, keyFormat, ksn, outputBytes) {
+ const normalizedOutputBytes = Math.max(1, Number(outputBytes) || 8);
+ const inputBuffer = convertInputToBuffer(input, inputFormat);
+ const inputHex = byteStringToHex(Utils.arrayBufferToStr(inputBuffer, false));
+ const { keyHex, keyContext } = resolveMacKey(method, { keyValue, keyFormat, ksn });
+
+ let fullMacHex;
+ if (method.startsWith("HMAC ")) {
+ const hmac = new HMAC();
+ const hashName = {
+ "HMAC SHA-224": "SHA224",
+ "HMAC SHA-256": "SHA256",
+ "HMAC SHA-384": "SHA384",
+ "HMAC SHA-512": "SHA512",
+ }[method];
+ fullMacHex = hmac.run(inputBuffer, [{ string: keyHex, option: "Hex" }, hashName]).toUpperCase();
+ } else {
+ const cmac = new CMAC();
+ const algorithm = method === "AES-CMAC" ? "AES" : "Triple DES";
+ fullMacHex = cmac.run(inputBuffer, [{ string: keyHex, option: "Hex" }, algorithm]).toUpperCase();
+ }
+
+ const macHex = fullMacHex.substring(0, normalizedOutputBytes * 2);
+
+ return {
+ method,
+ inputFormat,
+ inputHex,
+ outputBytes: normalizedOutputBytes,
+ fullMacHex,
+ macHex,
+ ...keyContext
+ };
+}
+
+/**
+ * Verifies a payment MAC by recomputing and comparing it.
+ *
+ * @param {string} input
+ * @param {string} inputFormat
+ * @param {string} method
+ * @param {string} keyValue
+ * @param {string} keyFormat
+ * @param {string} ksn
+ * @param {string} expectedMac
+ * @returns {Object}
+ */
+function verifyPaymentMac(input, inputFormat, method, keyValue, keyFormat, ksn, expectedMac) {
+ const normalizedExpected = (expectedMac || "").replace(/\s+/g, "").toUpperCase();
+ if (!/^[0-9A-F]+$/.test(normalizedExpected) || normalizedExpected.length % 2 !== 0) {
+ throw new OperationError("Expected MAC must be even-length hex.");
+ }
+
+ const generated = generatePaymentMac(
+ input,
+ inputFormat,
+ method,
+ keyValue,
+ keyFormat,
+ ksn,
+ normalizedExpected.length / 2
+ );
+
+ return {
+ ...generated,
+ expectedMacHex: normalizedExpected,
+ valid: generated.macHex === normalizedExpected
+ };
+}
+
+export {
+ PAYMENT_MAC_METHODS,
+ generatePaymentMac,
+ verifyPaymentMac,
+};
diff --git a/src/core/operations/GeneratePaymentMAC.mjs b/src/core/operations/GeneratePaymentMAC.mjs
new file mode 100644
index 00000000..c0680051
--- /dev/null
+++ b/src/core/operations/GeneratePaymentMAC.mjs
@@ -0,0 +1,93 @@
+/**
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation.mjs";
+import { PAYMENT_MAC_METHODS, generatePaymentMac } from "../lib/PaymentMac.mjs";
+
+/**
+ * Generate payment MAC operation.
+ */
+class GeneratePaymentMAC extends Operation {
+
+ /**
+ * GeneratePaymentMAC constructor.
+ */
+ constructor() {
+ super();
+
+ this.name = "Generate payment MAC";
+ this.module = "Payment";
+ this.description = "Paste the message data into the input field and generate a payment-oriented MAC using one payment-facing operation.
Input: message data in the selected input format.
Arguments: choose the MAC method, provide either a direct key or a DUKPT BDK, optionally provide a KSN for DUKPT methods, and choose the truncation length.
This wrapper reuses existing HMAC, CMAC, and DUKPT operations instead of duplicating their crypto logic.";
+ this.inlineHelp = "Input: message data.
Args: choose the payment MAC method, then provide either a direct key or a DUKPT BDK plus KSN.";
+ this.testDataSamples = [
+ {
+ name: "Static AES-CMAC sample",
+ input: "1122334455667788",
+ args: ["Hex", "AES-CMAC", "00112233445566778899AABBCCDDEEFF", "Hex", "", 8, false]
+ }
+ ];
+ this.infoURL = "https://docs.aws.amazon.com/payment-cryptography/latest/DataAPIReference/API_GenerateMac.html";
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [
+ {
+ name: "Input format",
+ type: "option",
+ value: ["Hex", "UTF8", "Latin1", "Base64"],
+ comment: "How to decode the input field before MAC generation. Use Hex for payment test vectors expressed as hex."
+ },
+ {
+ name: "MAC method",
+ type: "option",
+ value: PAYMENT_MAC_METHODS,
+ comment: "Static-key HMAC and CMAC modes reuse the existing generic primitives. DUKPT modes derive a TDES session key first and then apply TDES-CMAC."
+ },
+ {
+ name: "Key / BDK",
+ type: "string",
+ value: "",
+ comment: "Provide the direct MAC key for HMAC or CMAC methods, or the clear BDK for DUKPT methods."
+ },
+ {
+ name: "Key format",
+ type: "option",
+ value: ["Hex", "UTF8", "Latin1", "Base64"],
+ comment: "How to decode the key input. Assumption: DUKPT BDK input must be Hex."
+ },
+ {
+ name: "KSN (DUKPT only)",
+ type: "string",
+ value: "",
+ comment: "Required only for DUKPT MAC methods. Provide the full 10-byte KSN as 20 hex characters."
+ },
+ {
+ name: "Output bytes",
+ type: "number",
+ value: 8,
+ min: 1,
+ max: 64,
+ comment: "Number of leftmost MAC bytes to return. Leave at 8 for common payment truncation lengths."
+ },
+ {
+ name: "Output as JSON",
+ type: "boolean",
+ value: false,
+ comment: "When enabled, returns the full MAC, truncation details, and key-context metadata."
+ }
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ const [inputFormat, method, keyValue, keyFormat, ksn, outputBytes, outputJson] = args;
+ const result = generatePaymentMac(input, inputFormat, method, keyValue, keyFormat, ksn, outputBytes);
+ return outputJson ? JSON.stringify(result, null, 4) : result.macHex;
+ }
+}
+
+export default GeneratePaymentMAC;
diff --git a/src/core/operations/VerifyPaymentMAC.mjs b/src/core/operations/VerifyPaymentMAC.mjs
new file mode 100644
index 00000000..0fc524d3
--- /dev/null
+++ b/src/core/operations/VerifyPaymentMAC.mjs
@@ -0,0 +1,91 @@
+/**
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation.mjs";
+import { PAYMENT_MAC_METHODS, verifyPaymentMac } from "../lib/PaymentMac.mjs";
+
+/**
+ * Verify payment MAC operation.
+ */
+class VerifyPaymentMAC extends Operation {
+
+ /**
+ * VerifyPaymentMAC constructor.
+ */
+ constructor() {
+ super();
+
+ this.name = "Verify payment MAC";
+ this.module = "Payment";
+ this.description = "Paste the message data into the input field and verify a payment-oriented MAC using one payment-facing operation.
Input: message data in the selected input format.
Arguments: choose the MAC method, provide either a direct key or a DUKPT BDK, add the KSN for DUKPT methods, and supply the expected MAC as hex.
This wrapper recomputes the MAC using the same payment-specific assumptions as the generate operation.";
+ this.inlineHelp = "Input: message data.
Args: choose the payment MAC method, provide the key context, then paste the expected MAC.";
+ this.testDataSamples = [
+ {
+ name: "Static AES-CMAC verification sample",
+ input: "1122334455667788",
+ args: ["Hex", "AES-CMAC", "00112233445566778899AABBCCDDEEFF", "Hex", "", "339AF1AD1650E908", true]
+ }
+ ];
+ this.infoURL = "https://docs.aws.amazon.com/payment-cryptography/latest/DataAPIReference/API_VerifyMac.html";
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [
+ {
+ name: "Input format",
+ type: "option",
+ value: ["Hex", "UTF8", "Latin1", "Base64"],
+ comment: "How to decode the input field before MAC verification."
+ },
+ {
+ name: "MAC method",
+ type: "option",
+ value: PAYMENT_MAC_METHODS,
+ comment: "Static-key HMAC and CMAC modes reuse the existing generic primitives. DUKPT modes derive a TDES session key first and then apply TDES-CMAC."
+ },
+ {
+ name: "Key / BDK",
+ type: "string",
+ value: "",
+ comment: "Provide the direct MAC key for HMAC or CMAC methods, or the clear BDK for DUKPT methods."
+ },
+ {
+ name: "Key format",
+ type: "option",
+ value: ["Hex", "UTF8", "Latin1", "Base64"],
+ comment: "How to decode the key input. Assumption: DUKPT BDK input must be Hex."
+ },
+ {
+ name: "KSN (DUKPT only)",
+ type: "string",
+ value: "",
+ comment: "Required only for DUKPT MAC methods. Provide the full 10-byte KSN as 20 hex characters."
+ },
+ {
+ name: "Expected MAC (hex)",
+ type: "string",
+ value: "",
+ comment: "MAC value to compare against, expressed as even-length hex."
+ },
+ {
+ name: "Output as JSON",
+ type: "boolean",
+ value: true,
+ comment: "When enabled, returns the recomputed MAC, comparison target, and validity result."
+ }
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ const [inputFormat, method, keyValue, keyFormat, ksn, expectedMac, outputJson] = args;
+ const result = verifyPaymentMac(input, inputFormat, method, keyValue, keyFormat, ksn, expectedMac);
+ return outputJson ? JSON.stringify(result, null, 4) : String(result.valid);
+ }
+}
+
+export default VerifyPaymentMAC;
diff --git a/src/web/stylesheets/components/_operation.css b/src/web/stylesheets/components/_operation.css
index 4f5edf66..1b36d460 100755
--- a/src/web/stylesheets/components/_operation.css
+++ b/src/web/stylesheets/components/_operation.css
@@ -221,6 +221,8 @@ input.toggle-string {
filter: brightness(100%);
}
+.operation .form-group.is-filled label.bmd-label-floating,
+.operation .form-group.is-focused label.bmd-label-floating,
.operation .bmd-form-group.is-filled label.bmd-label-floating,
.operation .bmd-form-group.is-focused label.bmd-label-floating {
top: 4px !important;
diff --git a/tests/operations/tests/Payment.mjs b/tests/operations/tests/Payment.mjs
index 7f982c57..c5bf0847 100644
--- a/tests/operations/tests/Payment.mjs
+++ b/tests/operations/tests/Payment.mjs
@@ -255,6 +255,60 @@ TestRegister.addTests([
}
]
},
+ {
+ name: "Generate payment MAC: AES-CMAC",
+ input: "1122334455667788",
+ expectedOutput: "339AF1AD1650E908",
+ recipeConfig: [
+ {
+ op: "Generate payment MAC",
+ args: ["Hex", "AES-CMAC", "00112233445566778899AABBCCDDEEFF", "Hex", "", 8, false]
+ }
+ ]
+ },
+ {
+ name: "Generate payment MAC: HMAC SHA-256",
+ input: "1122334455667788",
+ expectedOutput: "9300E1D36DD30415",
+ recipeConfig: [
+ {
+ op: "Generate payment MAC",
+ args: ["Hex", "HMAC SHA-256", "00112233445566778899AABBCCDDEEFF", "Hex", "", 8, false]
+ }
+ ]
+ },
+ {
+ name: "Generate payment MAC: DUKPT MAC Request CMAC",
+ input: "1122334455667788",
+ expectedOutput: "3616961727FE155D",
+ recipeConfig: [
+ {
+ op: "Generate payment MAC",
+ args: ["Hex", "DUKPT MAC Request CMAC", "0123456789ABCDEFFEDCBA9876543210", "Hex", "FFFF9876543210E00008", 8, false]
+ }
+ ]
+ },
+ {
+ name: "Verify payment MAC: AES-CMAC",
+ input: "1122334455667788",
+ expectedOutput: JSON.stringify({
+ method: "AES-CMAC",
+ inputFormat: "Hex",
+ inputHex: "1122334455667788",
+ outputBytes: 8,
+ fullMacHex: "339AF1AD1650E908A794284D91DC6D29",
+ macHex: "339AF1AD1650E908",
+ keySource: "Direct key input",
+ expectedMacHex: "339AF1AD1650E908",
+ valid: true
+ }, null, 4),
+ recipeConfig: [
+ {
+ op: "Verify payment MAC",
+ args: ["Hex", "AES-CMAC", "00112233445566778899AABBCCDDEEFF", "Hex", "", "339AF1AD1650E908", true]
+ }
+ ]
+ },
{
name: "Derive ECDH key material: raw shared secret",
input: ecdhPrivateKey,