Skip to content

Instantly share code, notes, and snippets.

@cyberphone
Last active January 10, 2024 07:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cyberphone/99a8ae517b21f48d105ec69f39ac9d23 to your computer and use it in GitHub Desktop.
Save cyberphone/99a8ae517b21f48d105ec69f39ac9d23 to your computer and use it in GitHub Desktop.
Signed data, followed by partial encrypt
Code showing a payment authorization where all data is signed.
Since some of the signed data contains PII this part is removed
(after being signed) and then encrypted using a public key.
The encryption key is issuer-wide for avoiding PII.
The goal is creating a compact container only needing a single
signing and encryption operation. By keeping the transaction
request in clear, data duplication is minimized.
The need for encryption is because the authorization is sent back
to the (potentially untrusted) merchant. Since the transaction
request is in clear the merchant can verify its correctness
before submitting the authorization to the payment network.
=======================================================
Unlike existing payment authorization schemes, both the
signature and the encryption are fully end-to-end.
=======================================================
This scheme depends on translations of CBOR maps which in order
to be safe depends on a high level CBOR implementation where CBOR
data items are free-standing objects using deterministic encoding.
The example builds on FIDO for user signature keys.
User signing key in JWK format:
{
"kty": "EC",
"crv": "P-256",
"x": "6BKxpty8cI-exDzCkh-goU6dXq3MbcY0cd1LaAxiNrU",
"y": "mCbcvUzm44j3Lt2b5BPyQloQ91tf2D2V-gzeUxWaUdg",
"d": "6XxMFXhcYT5QN9w5TIg2aSKsbcj-pj4BnZkK7ZOt4B8"
}
Merchant 'W3C PaymentRequest' (PRCD) data:
{
1: "Space Shop", # Merchant claimed common name
2: "7040566321", # Request ID
3: "435.00", # Amount
4: "EUR" # Currency
}
Signed assertion:
{
1: {
1: "Space Shop",
2: "7040566321",
3: "435.00",
4: "EUR"
},
2: "spaceshop.com", # Merchant 'hostname' according to the browser
3: "FR7630002111110020050014382", # Account ID (IBAN)
4: "https://banknet2.org", # Payment method
5: "0057162932", # Credential ID
6: "additional stuff...", # Optional
7: { # Application info
1: {
3: "Android",
4: "12.0"
},
2: {
3: "Chrome",
4: "108"
}
},
8: [40.74844, -73.984559], # User location (optional)
9: "2023-02-16T10:14:07+01:00", # Time stamp
-1: { # Enveloped signture object
1: -7, # COSE signture algorithm
2: { # User signature key in COSE format
1: 2,
-1: 1,
-2: h'e812b1a6dcbc708f9ec43cc2921fa0a14e9d5eadcc6dc63471dd4b680c6236b5',
-3: h'9826dcbd4ce6e388f72edd9be413f2425a10f75b5fd83d95fa0cde53159a51d8'
},
# FIDO authentictor ID
3: h'412e175a0f0bdc06dabf0b1db79b97541c08dbacee7e31c97a553588ee922ea70500000017',
# FIDO signature
4: h'3044022076f0f01d9298d8ad91713d23c8029f3c8608a903c23cb1f052a59100faf2d5d702207919c0002f8491307db4924ea05e3b1e4716c807ea872e187571c988969ad4ba'
}
}
Signed assertion after PRCD removal (leaving us with the PII data to encrypt):
{
2: "spaceshop.com",
3: "FR7630002111110020050014382",
4: "https://banknet2.org",
5: "0057162932",
6: "additional stuff...",
7: {
1: {
3: "Android",
4: "12.0"
},
2: {
3: "Chrome",
4: "108"
}
},
8: [40.74844, -73.984559],
9: "2023-02-16T10:14:07+01:00",
-1: {
1: -7,
2: {
1: 2,
-1: 1,
-2: h'e812b1a6dcbc708f9ec43cc2921fa0a14e9d5eadcc6dc63471dd4b680c6236b5',
-3: h'9826dcbd4ce6e388f72edd9be413f2425a10f75b5fd83d95fa0cde53159a51d8'
},
3: h'412e175a0f0bdc06dabf0b1db79b97541c08dbacee7e31c97a553588ee922ea70500000017',
4: h'3044022076f0f01d9298d8ad91713d23c8029f3c8608a903c23cb1f052a59100faf2d5d702207919c0002f8491307db4924ea05e3b1e4716c807ea872e187571c988969ad4ba'
}
}
Encryption happens here...
Issuer encryption key in JWK format:
{
"kty": "OKP",
"crv": "X25519",
"x": "6ZoM7yBYlJYNmxwFl4UT3MtCoTv7ztUjpRuKEXrV8Aw",
"d": "cxfl86EVmcqrR07mWENCf1F_5Ni5mt1ViGyERB6Q1vA"
}
Encrypted assertion with non-PII data in clear:
1010(["https://fido-web-pay.github.io/ns/p1", {
# Encryption object
0: {
1: "Space Shop",
2: "7040566321",
3: "435.00",
4: "EUR"
},
1: 3,
2: {
1: -31,
3: "x25519:2022:1",
7: {
1: 1,
-1: 4,
-2: h'6e8c2b10d0644eff2cb8a4b0519772fbe66aef90e426f877fad1d2635357b443'
},
10: h'70e3e4ad71ca75d008438f91c7125c7e69d8bce5cafea3ee09b74b608886d8401f04fb52dfa86b56'
},
8: h'ca0260e1cc73a23dd8d985a32a5331f6',
9: h'd96b8901e4626e49326b9ff9',
10: h'3ed7ab1703b1a0fac41c0f5906f7a886d6f58aad2cf4c210b4cc0e0911401462673fd50f9380299b7adc2d6da76ff18248014a9c383bd850b19e7d3e7d45ba5a3c66bc294d37c9e8353eda89db1ac3533bf48b3ba1ec8e57bb27f72e13ae88f983216fc39358c5d1430957dbb64e84cb3b35a8a1a334ae36c3c737564d8ac27bb65c7fcba386ae1bca0b683ce42a871e4e69691cda57a77480cb357102ae34d558a1c7ada5e81805f9a5474df950325bc0a26fec50ef9ef50cbea994a2a23830e10adb5ae6141c31bd5eaeea65f922b6b4df1468f5d114345617004a40322a505df34a9bdbec01224b2db701bec98f1059fce0f4c3f4d0884a4520d5055c1c2d0189f8e6beb1e6addd46549c6a2e131bb6cd8a523dd11ba4df0710ddc174b3e525a053c2e3da3ffd5c406275e9471d32ec9dfb6d8cf4a68834becccc3e1e66fcb35de27b5d42ae620797d47ce4c060b182fc4b2c9b66fe17fc058685a9b8900d8a579075d2d2e40b5cfdf2bc156fcaa06a07f0c80c4138de'
}])
Note: the entire container is protected by authenticted encryption.
-------------------
The receiver would have to rebuild the signed data (after decryption of the PII-data),
in order to verify the signature.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment