mirror of
https://github.com/qtmleap/revkit.git
synced 2026-09-14 07:11:50 +02:00
feat(crypto): 48B HMAC鍵の導出を実装 — SHA384(session_bind[:16])
48B HMAC-SHA384 鍵の生成チェーンが完全に解明: session_check = HMAC-SHA256(PSK, enc_key_0 || sign_key_0) session_bind = HMAC-SHA256(session_check, nonce) 48B_key = SHA384(session_bind[:16]) これにより保存済みセッション鍵があれば Tweak/Frida なしで 全鍵を Python のみで導出可能になった。 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
2f82b34289
commit
b9930226f6
@@ -253,22 +253,50 @@ class NetflixCrypto:
|
||||
|
||||
return new_enc_key, new_sign_key
|
||||
|
||||
# ---- Phase 2: TFIT KDF (初期セッション鍵導出) ----
|
||||
# ---- Phase 2: 初期セッション鍵導出 ----
|
||||
|
||||
@staticmethod
|
||||
def derive_hmac384_key(
|
||||
psk: bytes,
|
||||
enc_key_0: bytes,
|
||||
sign_key_0: bytes,
|
||||
nonce: bytes,
|
||||
) -> bytes:
|
||||
"""Phase 3 KDF の session_bind から 48B HMAC-SHA384 鍵を導出.
|
||||
|
||||
session_check = HMAC-SHA256(PSK, enc_key_0 || sign_key_0)
|
||||
session_bind = HMAC-SHA256(session_check, nonce)
|
||||
48B_key = SHA384(session_bind[:16])
|
||||
|
||||
Args:
|
||||
psk: Pre-Shared Key (16 bytes)
|
||||
enc_key_0: 保存済み暗号化鍵 (16 bytes)
|
||||
sign_key_0: 保存済み署名鍵 (32 bytes)
|
||||
nonce: ハードコード nonce (16 bytes)
|
||||
|
||||
Returns:
|
||||
48 バイトの HMAC-SHA384 鍵
|
||||
"""
|
||||
session_check = hmac_mod.new(psk, enc_key_0 + sign_key_0, hashlib.sha256).digest()
|
||||
session_bind = hmac_mod.new(session_check, nonce, hashlib.sha256).digest()
|
||||
return hashlib.sha384(session_bind[:16]).digest()
|
||||
|
||||
@staticmethod
|
||||
def derive_initial_session_keys(
|
||||
tfit_key: bytes,
|
||||
dh_shared_secret: bytes,
|
||||
) -> tuple[bytes, bytes]:
|
||||
"""Phase 2 初期セッション鍵導出 (TFIT KDF).
|
||||
"""Phase 2 初期セッション鍵導出.
|
||||
|
||||
HMAC-SHA384(TFIT_KEY_48B, 0x00 || DH_SHARED_SECRET_128B) → 48 bytes
|
||||
HMAC-SHA384(48B_KEY, 0x00 || DH_SHARED_SECRET_128B) → 48 bytes
|
||||
enc_key = output[0:16] (AES-128 暗号化鍵)
|
||||
sign_key = output[16:48] (HMAC-SHA256 署名鍵)
|
||||
|
||||
48B_KEY は derive_hmac384_key() で導出するか、直接指定する。
|
||||
|
||||
Args:
|
||||
tfit_key: TFIT ホワイトボックス AES から導出した 48 バイト鍵
|
||||
dh_shared_secret: DH_compute_key から得た 128 バイト生共有秘密
|
||||
tfit_key: 48 バイト HMAC-SHA384 鍵
|
||||
dh_shared_secret: DH_compute_key から得た 128 バイト共有秘密
|
||||
|
||||
Returns:
|
||||
(enc_key, sign_key) — それぞれ 16 bytes, 32 bytes
|
||||
|
||||
@@ -46,8 +46,27 @@ def check(label: str, got: bytes, expected: bytes) -> bool:
|
||||
return ok
|
||||
|
||||
|
||||
ENC_KEY_0 = bytes.fromhex("0817065e29e6d1c8668473af9e13b3c2")
|
||||
SIGN_KEY_0 = bytes.fromhex(
|
||||
"91f752f76d7ab4c2dc6e5b3ec1c0e5a16864421fe449be5457459602e298ebc1"
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
print("=== Phase 2 KDF (TFIT / HMAC-SHA384) ===")
|
||||
print("=== 48B HMAC key 導出 (SHA384) ===")
|
||||
|
||||
# 48B 鍵を保存済みセッション鍵から導出
|
||||
derived_48b = NetflixCrypto.derive_hmac384_key(
|
||||
IOS_KDF_PSK, ENC_KEY_0, SIGN_KEY_0, IOS_KDF_NONCE
|
||||
)
|
||||
ok_48b = derived_48b == TFIT_KEY
|
||||
print(f" [{'PASS' if ok_48b else 'FAIL'}] derive_hmac384_key → 48B key")
|
||||
if not ok_48b:
|
||||
print(f" expected: {TFIT_KEY.hex()}")
|
||||
print(f" got: {derived_48b.hex()}")
|
||||
|
||||
print()
|
||||
print("=== Phase 2 KDF (HMAC-SHA384) ===")
|
||||
|
||||
# 入力長の確認
|
||||
assert len(TFIT_KEY) == 48, f"TFIT_KEY must be 48 bytes, got {len(TFIT_KEY)}"
|
||||
|
||||
Reference in New Issue
Block a user