Add AWS-style payment wrapper operations
This commit is contained in:
parent
3f1b63378f
commit
71b0a9871e
@ -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 AWS’s HSM-side translate-and-rewrap behavior.
|
- It does not recreate AWS’s 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.
|
||||||
|
|||||||
@ -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`
|
||||||
|
|||||||
@ -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"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
209
src/core/lib/PaymentDataCipher.mjs
Normal file
209
src/core/lib/PaymentDataCipher.mjs
Normal 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,
|
||||||
|
};
|
||||||
54
src/core/operations/DecryptPaymentData.mjs
Normal file
54
src/core/operations/DecryptPaymentData.mjs
Normal 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;
|
||||||
54
src/core/operations/EncryptPaymentData.mjs
Normal file
54
src/core/operations/EncryptPaymentData.mjs
Normal 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;
|
||||||
54
src/core/operations/GeneratePaymentPINData.mjs
Normal file
54
src/core/operations/GeneratePaymentPINData.mjs
Normal 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;
|
||||||
70
src/core/operations/ReEncryptPaymentData.mjs
Normal file
70
src/core/operations/ReEncryptPaymentData.mjs
Normal 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;
|
||||||
52
src/core/operations/TranslatePaymentPINData.mjs
Normal file
52
src/core/operations/TranslatePaymentPINData.mjs
Normal 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;
|
||||||
56
src/core/operations/VerifyEMVARQC.mjs
Normal file
56
src/core/operations/VerifyEMVARQC.mjs
Normal 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;
|
||||||
56
src/core/operations/VerifyPaymentPINData.mjs
Normal file
56
src/core/operations/VerifyPaymentPINData.mjs
Normal 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;
|
||||||
@ -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,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user