设计安全数字收据协议(DRP)及派生身份、AES-GCM 与 Ed25519 签名
发布: (2025年12月4日 GMT+8 13:43)
4 min read
原文: Dev.to
Source: Dev.to
引言
当今的数字收据存在碎片化问题:商户、发行方、收单方和卡网络使用不同的模式、格式和隐私模型。
数字收据协议(DRP)旨在引入一种统一的、基于同意、端到端加密、可验证、用户可控的行项目收据可移植性标准。
本文提出了 DRP 胶囊(Capsule)架构,包括:
- 派生身份
- AES‑GCM 加密
- Ed25519 完整性保护
- 与 NIST SP 800‑171 Rev.3 和 PCI DSS v4.0 的强对齐
- 完整的 Python 参考实现
架构原则
- 用户持有长期根密钥。
- 为每个商户创建一个伪匿名身份。
- 为每张收据使用唯一的对称密钥加密。
这些措施确保了不可关联性、隐私性和密码学隔离。
DRP 胶囊结构
DRP 胶囊由以下部分组成:
- Header – 公共元数据,无敏感数据,受完整性保护。
- Ciphertext – 使用 AES‑256‑GCM 加密的声明。
- Signature – 对确定性摘要进行的 Ed25519 发行者签名。
合规对齐
实现中包含注释,将密码学操作映射到:
-
NIST 800‑171 Rev.3 控制
- SC‑13(密码保护)
- SC‑28(静止数据)
- IA‑5(认证器/密钥管理)
- AU‑2 / AU‑3(可审计性)
-
PCI DSS v4.0 控制
- Req.3(保护存储的 PAN 数据)
- Req.4(加密传输)
- Req.6.4.3(安全密码设计)
完整的 Python 实现
"""
This implementation is for EDUCATIONAL PURPOSES ONLY.
Compliance-oriented inline notes reference:
NIST SP 800-171 Rev.3 (SC-13, SC-28, IA-5, AU-2, AU-3)
PCI DSS v4.0 (Req.3, Req.4, Req.6.4.3)
Goal:
Derived Identities
AES-256-GCM
Ed25519 issuer signatures
"""
from dataclasses import dataclass, asdict
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives.asymmetric.ed25519 import (
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes, serialization
@dataclass
class DerivedIdentityWallet:
def __init__(self, root_secret: bytes):
self._root_secret = root_secret
def derive_user_key(self, merchant_context: str) -> bytes:
"""AES-256 key derivation using HKDF."""
hkdf = HKDF(
algorithm=hashes.SHA256(),
length=32,
salt=None,
info=merchant_context.encode(),
)
return hkdf.derive(self._root_secret)
def derive_user_pseudonym(self, merchant_context: str) -> str:
"""Privacy-preserving pseudonymous ID."""
hkdf = HKDF(
algorithm=hashes.SHA256(),
length=32,
salt=None,
info=(merchant_context + "|pseudonym").encode(),
)
raw = hkdf.derive(self._root_secret)
digest = hashes.Hash(hashes.SHA256())
digest.update(raw)
return base64.urlsafe_b64encode(digest.finalize()).decode()
def encrypt_receipt_claims(claims: ReceiptClaims, key: bytes):
...
def generate_issuer_keypair() -> Ed25519PrivateKey:
...
def export_public_key_pem(pk: Ed25519PublicKey) -> str:
...
def sign_capsule_digest(priv: Ed25519PrivateKey, header, nonce_b64, ciphertext_b64):
h = hashes.Hash(hashes.SHA256())
h.update(capsule)
digest = h.finalize()
return priv.sign(digest)
def verify_drp_capsule(capsule: DRPCapsule, pub: Ed25519PublicKey):
h = hashes.Hash(hashes.SHA256())
h.update(data)
digest = h.finalize()
sig = base64.b64decode(capsule.issuer_signature)
try:
pub.verify(sig, digest)
return True
except Exception:
return False
def decrypt_drp_capsule(capsule: DRPCapsule, key: bytes) -> ReceiptClaims:
items = [LineItem(**it) for it in raw["line_items"]]
return ReceiptClaims(**{**raw, "line_items": items})
def issue_drp_capsule(claims, wallet, issuer_priv):
nonce, ciphertext = encrypt_receipt_claims(claims, key)
nonce_b64 = base64.b64encode(nonce).decode()
ct_b64 = base64.b64encode(ciphertext).decode()
header = DRPHeader(
drp_version="1.0.0",
capsule_id=base64.b32encode(os.urandom(10)).decode().rstrip("="),
issuer_id=claims.merchant_id,
schema_id="DRP-RECEIPT-V1",
country_code=claims.country_code,
)
sig = sign_capsule_digest(issuer_priv, header, nonce_b64, ct_b64)
return DRPCapsule(
header=header,
ciphertext=ct_b64,
nonce=nonce_b64,
issuer_signature=base64.b64encode(sig).decode(),
)
if __name__ == "__main__":
issuer_priv = generate_issuer_keypair()
issuer_pub = issuer_priv.public_key()
items = [
LineItem("SKU1", "Coffee 1kg", 1, 15.99, 0.07),
LineItem("SKU2", "Cup", 2, 8.50, 0.07),
]
subtotal = sum(i.unit_price * i.quantity for i in items)
tax = sum(i.unit_price * i.quantity * i.tax_rate for i in items)
claims = ReceiptClaims(
merchant_id="MRC-001",
terminal_id="POS-01",
country_code="US",
currency="USD",
total_amount=round(subtotal + tax, 2),
tax_amount=round(tax, 2),
timestamp_utc=int(time.time()),
card_network="VISA",
network_profile="VISA-US-2025",
pan_token="tok_visa_4242",
auth_code="AUTH123",
line_items=items,
)
capsule = issue_drp_capsule(claims, wallet, issuer_priv)
print("VALID SIGNATURE:", verify_drp_capsule(capsule, issuer_pub))
key = wallet.derive_user_key("MRC-001|VISA-US-2025")
recovered = decrypt_drp_capsule(capsule, key)
print(json.dumps(asdict(recovered), indent=2))
图示
图 1 – DRP 胶囊架构
Integrity-protected via Ed25519 signature
│
Confidentiality + Integrity (AEAD)
│
Issuer authentication & non-repudiation
图 2 – 派生身份钱包(密钥层次结构)
Root Secret (32 bytes)
(Never leaves secure enclave)
│
▼
HKDF (merchant_context = "merchant_id | network_profile")
│
├─ Derived User Key
├─ Derived Pseudonym
└─ Derived Identifier (optional)
图 3 – 发放流程(商户 → 用户钱包)
(示意流程,代码中未展示)
图 4 – 验证与解密流程
Wallet Derives Key via HKDF
│
▼
AES‑GCM Decryption
│
▼
Reconstruct Receipt Claims
│
▼
Decrypted Receipt (Plain)