ECDH-ES verwendet einen Schlüssel, der durch Ableiten eines von ECDH gemeinsam genutzten Geheimnisses mit Concat KDF als gemeinsam genutzten Schlüssel erstellt wurde. Verwenden Sie diesen Schlüssel[192|384|512]Umschließen und Übergeben des zufällig generierten gemeinsam genutzten Schlüssels des Bits Es sieht aus wie ECDH-ES + AnnnWK.
Überprüfung der EDCH-Schlüsselableitung von JWAs Anhang.C.
def test_ecdh(self):
'''
https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-23#appendix-C
'''
v_stc_material = {
"kty": "EC",
"crv": "P-256",
"x": "gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0",
"y": "SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps",
"d": "0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo"
}
u_epk_material = {
"kty": "EC",
"crv": "P-256",
"x": "weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ",
"y": "e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck",
"d": "VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw"
}
#Konvertierung des Schlüsselmaterialformats
import re
from jose.utils import base64
_to_pub = lambda km: (
int(re.search(r"P-(\d+)$", "P-256").group(1)),
(base64.long_from_b64(km['x']),
base64.long_from_b64(km['y']))
)
_to_pri = lambda km: (
int(re.search(r"P-(\d+)$", "P-256").group(1)),
base64.long_from_b64(km['d'])
)
# Party V(Empfänger)Persistenter Schlüssel und PartyU(Absender)Temporäre Schlüsselerstellung
from ecc.Key import Key
v_stc = Key(
public_key=_to_pub(v_stc_material),
private_key=_to_pri(v_stc_material)
)
#Geben Sie es PartyU als öffentlichen Schlüssel
v_pub = Key.decode(v_stc.encode())
u_epk = Key(
public_key=_to_pub(u_epk_material),
private_key=_to_pri(u_epk_material)
)
#Von NIST definierte Kurvenparameter: Getting NIST Curve
from ecc.curves import get_curve
_curve = lambda bits: dict(
zip(('bits', 'p', 'N', 'a', 'b', 'G'),
get_curve(bits)))
u_crv = _curve(u_epk._priv[0])
Mit dem generierten temporären privaten Schlüssel und dem öffentlichen permanenten öffentlichen Schlüssel des Ziels:
# ECDH :
from ecc.elliptic import mulp
_dhZ = lambda crv, pub, pri: mulp(
crv['a'], crv['b'], crv['p'], pub, pri)[0]
#Geheime Berechnung des Absenders
shared_secret_u = _dhZ(u_crv, v_pub._pub[1], u_epk._priv[1])
from Crypto.Util.number import long_to_bytes
from math import ceil
#Byte-String nach Blockgröße
block_size = int(ceil(u_epk._priv[0] / 8.0))
Zu = long_to_bytes(shared_secret_u, block_size)
Z_jwa = [158, 86, 217, 29, 129, 113, 53,
211, 114, 131, 66, 131, 191, 132,
38, 156, 251, 49, 110, 163, 218,
128, 106, 72, 246, 218, 167, 121,
140, 254, 144, 196]
#Technische Daten und Bestätigung: OK
self.assertEqual([ord(i) for i in Zu], Z_jwa)
#Generierung von Partyinformationen:So etwas wie Salz
# Other Information used in Concat KDF
# AlgorithmID || PartyUInfo || PartyVInfo || SuppPubInfo
from struct import pack
_otherInfo = lambda alg, pu, pv, klen: ''.join([
pack("!I", len(alg)),
alg,
pack("!I", len(pu)),
pu,
pack("!I", len(pv)),
pv,
pack("!I", klen),
])
oi_u = _otherInfo(
"A128GCM",
"Alice",
"Bob",
16 * 8, # A128GCM
)
oi_jwa = [
0, 0, 0, 7,
65, 49, 50, 56, 71, 67, 77,
0, 0, 0, 5,
65, 108, 105, 99, 101,
0, 0, 0, 3,
66, 111, 98,
0, 0, 0, 128]
#Technische Daten und Bestätigung: OK
self.assertEqual([ord(i) for i in oi_u], oi_jwa)
# Concat KDF : NIST SP-800-56a 5.8.1
#Übergeben Sie die Partyinformationen und das Geheimnis an diese Funktion, um den Schlüssel abzuleiten
from Crypto.Hash import SHA256
def _ConcatKDF(Z, dkLen, otherInfo,
digest_method=SHA256):
_src = lambda counter_bytes: "".join([
counter_bytes, Z, otherInfo])
from math import ceil
from struct import pack
dkm = b'' # Derived Key Material
counter = 0
klen = int(ceil(dkLen / 8.0))
while len(dkm) < klen:
counter += 1
counter_b = pack("!I", counter)
dkm += digest_method.new(_src(counter_b)).digest()
return dkm[:klen]
_derived_key_u = _ConcatKDF(Zu, 16 * 8, oi_u)
Mit dem temporären öffentlichen Schlüssel, den Sie erhalten haben, und Ihrem permanenten privaten Schlüssel:
# Party V :Holen Sie sich einen temporären öffentlichen Schlüssel
v_epk = Key.decode(u_epk.encode())
Zv = long_to_bytes(
_dhZ(u_crv, v_epk._pub[1], v_stc._priv[1]),
block_size)
_derived_key_v = _ConcatKDF(Zv, 16 * 8, oi_u)
self.assertEqual(_derived_key_u, _derived_key_v)
kd_jwa = [
86, 170, 141, 234, 248, 35, 109, 32,
92, 34, 40, 205, 113, 167, 16, 26]
#Technische Daten und Bestätigung: OK
self.assertEqual([ord(i) for i in _derived_key_u], kd_jwa)
self.assertEqual("VqqN6vgjbSBcIijNcacQGg",
base64.base64url_encode(_derived_key_u))