mirror of
https://github.com/malmeloo/FindMy.py.git
synced 2026-04-18 11:54:12 +02:00
107 lines
3.2 KiB
Python
107 lines
3.2 KiB
Python
"""Pure-python NIST P-224 Elliptic Curve cryptography. Used for some Apple algorithms."""
|
|
|
|
from cryptography.hazmat.primitives import hashes
|
|
from cryptography.hazmat.primitives.asymmetric import ec
|
|
from cryptography.hazmat.primitives.kdf.x963kdf import X963KDF
|
|
|
|
ECPoint = tuple[float, float]
|
|
|
|
P224_A = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE
|
|
P224_N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D
|
|
P224_G = (
|
|
0xB70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21,
|
|
0xBD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34,
|
|
)
|
|
P224_P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001
|
|
|
|
|
|
# Old code. Remove if replacement is confirmed to be working.
|
|
# ruff: noqa: ERA001
|
|
#
|
|
# def _ec_add_points(p1: ECPoint, p2: ECPoint) -> ECPoint:
|
|
# """
|
|
# Add two points on a P-224 elliptic curve. (0, 0) is identity.
|
|
#
|
|
# https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Point_addition
|
|
# """
|
|
# (x1, y1), (x2, y2) = p1, p2
|
|
#
|
|
# if p1 == (0, 0): # identity case 1
|
|
# return p2
|
|
# if p2 == (0, 0): # identity case 2
|
|
# return p1
|
|
# if x1 == x2 and y1 == -1 * y2: # additive inverse
|
|
# return 0, 0
|
|
#
|
|
# if p1 == p2: # point doubling using limit
|
|
# slope = (3 * x1 ** 2 + P224_A) / (2 * y1)
|
|
# else:
|
|
# slope = (y2 - y1) / (x2 - x1)
|
|
#
|
|
# x = slope ** 2 - x1 - x2
|
|
# y = slope * (x1 - x) - y1
|
|
#
|
|
# return x, y
|
|
#
|
|
#
|
|
# def _ec_scalar_mul(scalar: int, p: ECPoint) -> ECPoint:
|
|
# """
|
|
# Scalar multiplication on a point on a P-224 elliptic curve.
|
|
#
|
|
# https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Double-and-add
|
|
# """
|
|
# res = (0, 0)
|
|
# cur = p
|
|
# while scalar > 0:
|
|
# if scalar & 1:
|
|
# res = _ec_add_points(res, cur)
|
|
# cur = _ec_add_points(cur, cur)
|
|
# scalar >>= 1
|
|
# return res
|
|
#
|
|
#
|
|
# def derive_ps_key(pubkey: ECPoint, sk: bytes) -> ECPoint:
|
|
# at = _x963_kdf(sk, b"diversify", 72)
|
|
# u = int.from_bytes(at[:36], "big") % (P224_N - 1) + 1
|
|
# v = int.from_bytes(at[36:], "big") % (P224_N - 1) + 1
|
|
#
|
|
# return _ec_add_points(_ec_scalar_mul(u, pubkey), _ec_scalar_mul(v, P224_G))
|
|
|
|
|
|
def x963_kdf(value: bytes, si: bytes, length: int) -> bytes:
|
|
"""Single pass of X9.63 KDF with SHA1."""
|
|
return X963KDF(
|
|
algorithm=hashes.SHA256(),
|
|
sharedinfo=si,
|
|
length=length,
|
|
).derive(value)
|
|
|
|
|
|
def bytes_to_int(value: bytes) -> int:
|
|
"""Convert bytes in big-endian format to int."""
|
|
return int.from_bytes(value, "big")
|
|
|
|
|
|
def derive_ps_key(privkey: bytes, sk: bytes) -> bytes:
|
|
"""
|
|
Derive a primary or secondary key used by an accessory.
|
|
|
|
:param privkey: Private key generated during pairing
|
|
:param sk: Current secret key for this time period.
|
|
Use SKN to derive the primary key, SKS for secondary.
|
|
"""
|
|
priv_int = bytes_to_int(privkey)
|
|
|
|
at = x963_kdf(sk, b"diversify", 72)
|
|
u = bytes_to_int(at[:36]) % (P224_N - 1) + 1
|
|
v = bytes_to_int(at[36:]) % (P224_N - 1) + 1
|
|
|
|
key = (u * priv_int + v) % P224_N
|
|
return key.to_bytes(28, "big")
|
|
|
|
|
|
def _get_pubkey(privkey: int) -> ECPoint:
|
|
key = ec.derive_private_key(privkey, ec.SECP224R1())
|
|
pubkey = key.public_key().public_numbers()
|
|
return pubkey.x, pubkey.y
|