o
    l>jo9                     @   sN  U d dl Z d dlmZ d dlmZmZ d dlmZmZm	Z	m
Z
mZmZ d dlmZmZ d dlmZ d dlmZ d dlmZmZ d	d
lmZ 	 eddG dd dZdedddiZeeef ed< dedefddZdededefddZ de
de
de
fddZ!eG d d! d!Z"eG d"d# d#Z#eG d$d% d%Z$eG d&d' d'Z%dS )(    N)	dataclass)SequenceTuple)ECDHEllipticCurveEllipticCurvePrivateKeyEllipticCurvePublicKeyEllipticCurvePublicNumbersderive_private_key)HashHashAlgorithm)HMAC)HKDF)EncodingPublicFormat   )	bytes2intT)frozenc                   @   s"   e Zd ZU dZeed< eed< dS )_CurveParamsz:Weierstrass curve parameters needed for EC point addition.primeaN)__name__
__module____qualname____doc__int__annotations__ r   r   ?/home/thesage/.local/lib/python3.10/site-packages/fido2/arkg.pyr   8   s   
 r   	secp256r1l   ?               @ l   ?               @ )r   r   _CURVE_PARAMScurvereturnc                 C   s,   zt | j W S  ty   td| j w )zELook up curve parameters, or raise ValueError for unsupported curves.zUnsupported curve: )r    nameKeyError
ValueError)r!   r   r   r   _params_for_curveH   s
   r&   r   bc                    s    t  fddtt D S )Nc                 3   s     | ]} | | A V  qd S )Nr   ).0ir   r'   r   r   	<genexpr>Q   s    z_strxor.<locals>.<genexpr>)bytesrangelenr*   r   r*   r   _strxorP   s    r/   p1p2c                 C   s   | j j|j jkrtdt| j }|  }| }|j|j}}|j|j}}|j}	||krF||krFd| | |j t	d| d|	 |	 }
n|| t	|| d|	 |	 }
|
|
 | | |	 }|
||  | |	 }t
||| j  S )zCAdd two EC points. Both points must be on the same supported curve.z'Cannot add points from different curves      )r!   r#   r%   r&   public_numbersxyr   r   powr	   
public_key)r0   r1   paramsn1n2x1y1x2y2plamx3y3r   r   r   
_point_addT   s   
(rE   c                   @   s^   e Zd ZU dZeed< eed< eed< eed< dedefdd	Zded
ede	e fddZ
dS )_HTFa/  
    hash_to_field(msg, count)

    Parameters:
    - DST, a domain separation tag (see Section 3.1).
    - F, a finite field of characteristic p and order q = p^m.
    - p, the characteristic of F (see immediately above).
    - m, the extension degree of F, m >= 1 (see immediately above).
    - L = ceil((ceil(log2(p)) + k) / 8), where k is the security
      parameter of the suite (e.g., k = 128).
    - expand_message, a function that expands a byte string and
      domain separation tag into a uniformly random byte string
      (see Section 5.3).
    DSTrA   Lr   msglen_in_bytesc                 C   s  | j j}| |  }|dks|dkst| jdkrtd| jtdt| j }| j jdus1J d| j j }td|}|| | d | }t | j }	|	| |		 }
|
}t
 }td|d D ]"}t | j }	|	|td| |  |		 }|| t|
|}qat|d| S )	a}  
        expand_message_xmd(msg, DST, len_in_bytes)

        Parameters:
        - H, a hash function (see requirements above).
        - b_in_bytes, b / 8 for b the output size of H in bits.
          For example, for b = 256, b_in_bytes = 32.
        - s_in_bytes, the input block size of H, measured in bytes (see
          discussion above). For example, for SHA-256, s_in_bytes = 64.

        Input:
        - msg, a byte string.
        - DST, a byte string of at most 255 bytes.
          See below for information on using longer DSTs.
        - len_in_bytes, the length of the requested output in bytes,
          not greater than the lesser of (255 * b_in_bytes) or 2^16-1.

        Output:
        - uniform_bytes, a byte string.

        Steps:
        1.  ell = ceil(len_in_bytes / b_in_bytes)
        2.  ABORT if ell > 255 or len_in_bytes > 65535 or len(DST) > 255
        3.  DST_prime = DST || I2OSP(len(DST), 1)
        4.  Z_pad = I2OSP(0, s_in_bytes)
        5.  l_i_b_str = I2OSP(len_in_bytes, 2)
        6.  msg_prime = Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime
        7.  b_0 = H(msg_prime)
        8.  b_1 = H(b_0 || I2OSP(1, 1) || DST_prime)
        9.  for i in (2, ..., ell):
        10.    b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime)
        11. uniform_bytes = b_1 || ... || b_ell
        12. return substr(uniform_bytes, 0, len_in_bytes)
           i  zInvalid size of input/output>BN    z>Hr   )r   digest_sizer.   rG   r%   structpack
block_sizeupdatefinalize	bytearrayr-   extendr/   r,   )selfrI   rJ   
b_in_bytesell	dst_primez_pad	l_i_b_str	msg_primedb_0b_xoruniform_bytesr)   b_ir   r   r   expand_message_xmd   s*   #



z_HTF.expand_message_xmdcountr"   c           	      C   s^   |  ||| j }t }t|D ]}| j| }|||| j  }t|| j }|| q|S )a  
        hash_to_field(msg, count)

        Input:
        - msg, a byte string containing the message to hash.
        - count, the number of elements of F to output.

        Output:
        - (u_0, ..., u_(count - 1)), a list of field elements.

        Steps:
        1. len_in_bytes = count * m * L
        2. uniform_bytes = expand_message(msg, DST, len_in_bytes)
        3. for i in (0, ..., count - 1):
        4.   for j in (0, ..., m - 1):
        5.     elm_offset = L * (j + i * m)
        6.     tv = substr(uniform_bytes, elm_offset, L)
        7.     e_j = OS2IP(tv) mod p
        8.   u_i = (e_0, ..., e_(m - 1))
        9. return (u_0, ..., u_(count - 1))
        )rb   rH   listr-   r   rA   append)	rV   rI   rc   r`   elementsr)   offsettve_jr   r   r   hash_to_field   s   
z_HTF.hash_to_fieldN)r   r   r   r   r,   r   r   r   rb   r   rj   r   r   r   r   rF   m   s   
 <rF   c                   @   sR   e Zd ZU eed< eed< eed< dededefddZd	e	d
ede	fddZ
dS )_BLcrvr   DST_extikm_tauctxr"   c                 C   s6   d| j  | }t|| jjd| j}||dd }|S )a  
        BL-PRF(ikm_tau, ctx) -> tau

            DST_tau = 'ARKG-BL-EC.' || DST_ext || ctx
            tau = hash_to_field(tau, 1) with the parameters:
                DST: DST_tau
                F: GF(N), the scalar field
                   of the prime order subgroup of crv
                p: N
                m: 1
                L: The L defined in hash-to-crv-suite
                expand_message: The expand_message function
                                defined in hash-to-crv-suite
        s   ARKG-BL-EC.0   r   r   )rm   rF   rl   group_orderr   rj   )rV   rn   ro   dst_tauhtftaur   r   r   prf   s   z_BL.prfpkrt   c                 C   s   t || j }t||S )z[
        BL-Blind-Public-Key(pk, tau) -> pk_tau

            pk_tau = pk + tau * G
        )r
   rl   r9   rE   )rV   rv   rt   tau_gr   r   r   blind_public_key   s   
z_BL.blind_public_keyN)r   r   r   r   r   r   r,   r   ru   r   rx   r   r   r   r   rk      s   
 rk   c                
   @   s|   e Zd ZU eed< eed< eed< dedefddZde	ded	ede
eef fd
dZde	ded	ede
eef fddZdS )_KEMrl   r   rm   ikmr"   c                 C   s6   t d| j | jjd| j}||dd }t|| jS )a  
        Sub-Kem-Derive-Key-Pair(ikm) -> (pk, sk)

            sk = hash_to_field(ikm, 1) with the parameters:
                DST: 'ARKG-KEM-ECDH-KG.' || DST_ext
                F: GF(N), the scalar field
                  of the prime order subgroup of crv
                p: N
                m: 1
                L: The L defined in hash-to-crv-suite
                expand_message: The expand_message function
                                defined in hash-to-crv-suite

            pk = sk * G
        s   ARKG-KEM-ECDH-KG.rp   r   r   )rF   rm   rl   rq   r   rj   r
   )rV   rz   rs   skr   r   r   sub_kem_derive_key_pair  s   z_KEM.sub_kem_derive_key_pairrv   ro   c                 C   s8   |  |}| }|t |}|tjtj}||fS )a  
        ECDH(pk, sk) represents the compact output of ECDH [RFC6090]
        using public key (curve point) pk and private key (exponent) sk.

        G is the generator of the prime order subgroup of crv.

        N is the order of G.

        Sub-Kem-Encaps(pk, ikm, ctx) -> (k, c)

            (pk', sk') = Sub-Kem-Derive-Key-Pair(ikm)

            k = ECDH(pk, sk')
            c = Elliptic-Curve-Point-to-Octet-String(pk')
        )	r|   r9   exchanger   public_bytesr   X962r   UncompressedPoint)rV   rv   rz   ro   sk_primepk_primekcr   r   r   sub_kem_encaps*  s
   
z_KEM.sub_kem_encapsc                 C   s   d| j  | }| |||\}}t| j| jjdd| j  | |}t|| j}|| | dd }	t| jt	|dd| j  | |}
|	| }|
|fS )a  
        KEM-Encaps(pk, ikm, ctx) -> (k, c)

            ctx_sub = 'ARKG-KEM-HMAC.' || DST_ext || ctx
            (k', c') = Sub-Kem-Encaps(pk, ikm, ctx_sub)

            prk = HKDF-Extract with the arguments:
                Hash: Hash
                salt: not set
                IKM: k'

            mk = HKDF-Expand with the arguments:
                Hash: Hash
                PRK: prk
                info: 'ARKG-KEM-HMAC-mac.' || DST_ext || ctx
                L: L
            t = HMAC-Hash-128(K=mk, text=c')

            k = HKDF-Expand with the arguments:
                Hash: Hash
                PRK: prk
                info: 'ARKG-KEM-HMAC-shared.' || DST_ext || ctx
                L: The length of k' in octets.
            c = t || c'
        s   ARKG-KEM-HMAC.Ns   ARKG-KEM-HMAC-mac.   s   ARKG-KEM-HMAC-shared.)
rm   r   r   r   rN   deriver   rR   rS   r.   )rV   rv   rz   ro   ctx_subk_primec_primemkhmactr   r   r   r   r   encapsD  s.   
z_KEM.encapsN)r   r   r   r   r   r   r,   r   r|   r   r   r   r   r   r   r   r   ry   
  s.   
 


ry   c                   @   sH   e Zd ZU dZeed< eed< dedededede	eef f
d	d
Z
dS )_ARKGz}
    ARKG instance parameters:
        BL        A key blinding scheme.
        KEM       A key encapsulation mechanism.
    blkempk_blpk_kemrz   ro   r"   c                 C   st   t |dkr
tdtdt || }d| }d| }| j|||\}}	| j||}
| j||
}|	}||fS )a&  
        ARKG-Derive-Public-Key((pk_bl, pk_kem), ikm, ctx) -> (pk', kh)
            ARKG instance parameters:
                BL        A key blinding scheme.
                KEM       A key encapsulation mechanism.

            Inputs:
                pk_bl     A key blinding public key.
                pk_kem    A key encapsulation public key.
                ikm       Input entropy for KEM encapsulation.
                ctx       An octet string of length at most 64,
                            containing optional context and
                            application specific information
                            (can be a zero-length string).

            Output:
                pk'       A blinded public key.
                kh        A key handle for deriving the blinded
                            private key sk' corresponding to pk'.

            The output (pk', kh) is calculated as follows:

            if LEN(ctx) > 64:
                Abort with an error.

            ctx'    = I2OSP(LEN(ctx), 1) || ctx
            ctx_bl  = 'ARKG-Derive-Key-BL.'  || ctx'
            ctx_kem = 'ARKG-Derive-Key-KEM.' || ctx'

            (ikm_tau, c) = KEM-Encaps(pk_kem, ikm, ctx_kem)
            tau = BL-PRF(ikm_tau, ctx_bl)
            pk' = BL-Blind-Public-Key(pk_bl, tau)

            kh = c
        @   z,Context too long, should be at most 64 bytesrL   s   ARKG-Derive-Key-BL.s   ARKG-Derive-Key-KEM.)	r.   r%   rO   rP   r   r   r   ru   rx   )rV   r   r   rz   ro   	ctx_primectx_blctx_kemrn   r   rt   r   khr   r   r   derive_public_key  s   *z_ARKG.derive_public_keyN)r   r   r   r   rk   r   ry   r   r,   r   r   r   r   r   r   r   {  s   
 
r   )&rO   dataclassesr   typingr   r   ,cryptography.hazmat.primitives.asymmetric.ecr   r   r   r   r	   r
   %cryptography.hazmat.primitives.hashesr   r   #cryptography.hazmat.primitives.hmacr   'cryptography.hazmat.primitives.kdf.hkdfr   ,cryptography.hazmat.primitives.serializationr   r   utilsr   r   r    dictstrr   r&   r,   r/   rE   rF   rk   ry   r   r   r   r   r   <module>   sD   
 	
u&p