Add payment MAC wrapper operations
This commit is contained in:
parent
7433b07f2b
commit
3f1b63378f
@ -25,8 +25,8 @@ Coverage legend:
|
|||||||
| `EncryptData` | `Direct` / `Partial` | Direct for AES, TDES, RSA. Partial for DUKPT and EMV-derived encryption. |
|
| `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. |
|
| `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. |
|
| `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. |
|
| `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 by recomputing and comparing HMAC/CMAC. Partial for DUKPT MAC and EMV MAC 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 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. |
|
| `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. |
|
||||||
@ -103,15 +103,29 @@ Suggested use:
|
|||||||
|
|
||||||
## 6) AWS `VerifyMac`: Recompute And Compare
|
## 6) AWS `VerifyMac`: Recompute And Compare
|
||||||
Operations:
|
Operations:
|
||||||
- `From Hex`
|
- `Verify payment MAC`
|
||||||
- `HMAC` or `CMAC`
|
|
||||||
- `Take bytes`
|
|
||||||
|
|
||||||
Suggested use:
|
Suggested use:
|
||||||
- Recompute the MAC using the same starter as `GenerateMac`.
|
- Paste the message into the input field, choose the MAC method, and provide either the direct key or the DUKPT BDK plus KSN.
|
||||||
- Compare the result to the AWS `Mac` value manually or with a follow-on comparison recipe.
|
- 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:
|
Operations:
|
||||||
- `Generate card validation data`
|
- `Generate card validation data`
|
||||||
|
|
||||||
@ -124,7 +138,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`.
|
||||||
|
|
||||||
## 8) AWS `VerifyCardValidationData`: CVV / CVV2 / iCVV
|
## 9) AWS `VerifyCardValidationData`: CVV / CVV2 / iCVV
|
||||||
Operations:
|
Operations:
|
||||||
- `Verify card validation data`
|
- `Verify card validation data`
|
||||||
|
|
||||||
@ -138,7 +152,7 @@ Notes:
|
|||||||
|
|
||||||
## Partial Recipe Starters
|
## Partial Recipe Starters
|
||||||
|
|
||||||
## 9) AWS `EncryptData` / `DecryptData`: DUKPT-Derived Symmetric Flows
|
## 10) 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`
|
||||||
@ -151,20 +165,6 @@ 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.
|
||||||
|
|
||||||
## 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
|
## 11) AWS `VerifyAuthRequestCryptogram`: EMV ARQC Check
|
||||||
Operations:
|
Operations:
|
||||||
- `Generate EMV ARQC`
|
- `Generate EMV ARQC`
|
||||||
@ -257,6 +257,7 @@ Why:
|
|||||||
If you want closer AWS coverage, the highest-value missing operations are:
|
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.
|
1. PIN block encode/decode for ISO 9564 formats 0, 1, 3, and 4.
|
||||||
2. IBM 3624 and VISA PVV generation and verification.
|
2. IBM 3624 and VISA PVV generation and verification.
|
||||||
3. Dedicated EMV MAC and profile-specific EMV session-derivation helpers.
|
3. ISO 9797 and AS2805-specific MAC generation and verification.
|
||||||
4. Clear-to-encrypted and encrypted-to-encrypted PIN translation flows.
|
4. Dedicated EMV MAC and profile-specific EMV session-derivation helpers.
|
||||||
5. TR-31 unwrap and rewrap helpers for dynamic-key workflows.
|
5. Clear-to-encrypted and encrypted-to-encrypted PIN translation flows.
|
||||||
|
6. TR-31 unwrap and rewrap helpers for dynamic-key workflows.
|
||||||
|
|||||||
@ -62,7 +62,22 @@ 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) 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:
|
Operations:
|
||||||
- `Generate EMV ARQC`
|
- `Generate EMV ARQC`
|
||||||
|
|
||||||
@ -75,7 +90,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.
|
||||||
|
|
||||||
## 9) EMV ARPC Generation (AES-CMAC Response Profile)
|
## 10) EMV ARPC Generation (AES-CMAC Response Profile)
|
||||||
Operations:
|
Operations:
|
||||||
- `Generate EMV ARPC`
|
- `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.
|
- 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.
|
||||||
|
|
||||||
## 10) Combined Message Triage
|
## 11) 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`
|
||||||
|
|||||||
@ -568,11 +568,21 @@
|
|||||||
{
|
{
|
||||||
"name": "Payments",
|
"name": "Payments",
|
||||||
"ops": [
|
"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-31 key block",
|
||||||
"Parse TR-34 B9 envelope",
|
"Parse TR-34 B9 envelope",
|
||||||
"Calculate payment KCV",
|
"Calculate payment KCV",
|
||||||
"Derive ECDH key material",
|
"Derive ECDH key material",
|
||||||
"Derive DUKPT key",
|
"Derive DUKPT key",
|
||||||
|
"Generate 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",
|
||||||
|
|||||||
175
src/core/lib/PaymentMac.mjs
Normal file
175
src/core/lib/PaymentMac.mjs
Normal file
@ -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,
|
||||||
|
};
|
||||||
93
src/core/operations/GeneratePaymentMAC.mjs
Normal file
93
src/core/operations/GeneratePaymentMAC.mjs
Normal file
@ -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.<br><br><b>Input:</b> message data in the selected input format.<br><b>Arguments:</b> 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.<br><br>This wrapper reuses existing HMAC, CMAC, and DUKPT operations instead of duplicating their crypto logic.";
|
||||||
|
this.inlineHelp = "<strong>Input:</strong> message data.<br><strong>Args:</strong> 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 <code>Hex</code> 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 <code>Hex</code>."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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 <code>8</code> 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;
|
||||||
91
src/core/operations/VerifyPaymentMAC.mjs
Normal file
91
src/core/operations/VerifyPaymentMAC.mjs
Normal file
@ -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.<br><br><b>Input:</b> message data in the selected input format.<br><b>Arguments:</b> 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.<br><br>This wrapper recomputes the MAC using the same payment-specific assumptions as the generate operation.";
|
||||||
|
this.inlineHelp = "<strong>Input:</strong> message data.<br><strong>Args:</strong> 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 <code>Hex</code>."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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;
|
||||||
@ -221,6 +221,8 @@ input.toggle-string {
|
|||||||
filter: brightness(100%);
|
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-filled label.bmd-label-floating,
|
||||||
.operation .bmd-form-group.is-focused label.bmd-label-floating {
|
.operation .bmd-form-group.is-focused label.bmd-label-floating {
|
||||||
top: 4px !important;
|
top: 4px !important;
|
||||||
|
|||||||
@ -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",
|
name: "Derive ECDH key material: raw shared secret",
|
||||||
input: ecdhPrivateKey,
|
input: ecdhPrivateKey,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user