
    iЌ                        d Z ddlZddlZddlZddlZddlZddlmZ ddlm	Z	m
Z
mZmZmZmZmZ ddlT ddlmZmZ  ede          Z ede          Zeeef         Zd	efd
Zdede	e         fdZdedefdZdedefdZdeeef         defdZdededefdZdede fdZ!dedefdZ"dedefdZ#dedefdZ$dedefdZ%dede
e         fdZ&dedeeef         fdZ'dede fd Z(d!ed"edefd#Z)defd$Z*d%efd&Z+d	ede	e         fd'Z,dTd	ed)e-de	e         fd*Z.d+ed,ed-edefd.Z/dUd+ed,ed-edefd0Z0dVdefd1Z1d2 Z2d3ed4ede-fd5Z3	 	 dWd:ed;ed<ed=e-def
d>Z4d? Z5dXdAZ6dBe7defdCZ8dD Z9dE Z: G dF dGej;                  Z< G dH dIe<          Z= G dJ dK          Z> G dL dMe>          Z? G dN dO          Z@ G dP dQ          ZA G dR dS          ZBdS )Yz pySim: various utilities
    N)BytesIO)OptionalListDictAnyTupleNewTypeUnion)*)bertlv_encode_tagbertlv_encode_lenSwHexstr
SwMatchstrimsic           	          t          t          |           dz             }t          |           dz  }d|z  t          d|dz  dz  t          | d          fz            z   }|S )z7Converts a string IMSI into the encoded value of the EF   %02xz%01x%s      )half_round_uplenswap_nibblesrpad)r   loeeis       ;/home/jenkins/workspace/simtester-sanitize/./pySim/utils.pyenc_imsir   5   sb    D		A	 	A	TQB	!l8a1}d4nn.M#MNN	NBI    efreturnc                 v   t          |           dk     rdS t          | dd         d          dz  }|dz
  }t          | dd                                       d          }t          |          dk     rdS t          |d                   dz	  dz  }|s|dz
  }|t          |          dz
  k    rdS |dd         }|S )	z6Converts an EF value to the IMSI string representation   Nr         r   fr   )r   intr   rstrip)r    r   swappedr   r   s        r   dec_imsir*   >   s    
2ww{{tBqsGR1A	AA2abb6""))#..G
7||at
gaj//Q
!	#B aCCLL1t122;DKr   c                 F    t          |                               d          S )Nr&   )r   strip)r    s    r   	dec_iccidr-   Q   s    !!#&&&r   iccidc                 <    t          t          | d                    S )N   )r   r   r.   s    r   	enc_iccidr2   U   s    UB(((r   c                    t          |           } t          |           dk     rt          d          t          |           dk    rt          d          t          |           dk    r| t          t          |                     z  } t          |           dk    rt	          |            t          |           dk    r@	 t	          |            n/# t          $ r" | t          t          |                     z  } Y nw xY w| S )N   z,ICCID input value must be at least 18 digitsr0   z+ICCID input value must be at most 20 digits   )strr   
ValueErrorcalculate_luhnverify_luhnr1   s    r   sanitize_iccidr:   X   s    JJE
5zzBGHHH
5zzBFGGG
5zzR^E**+++
5zzR 	E
5zzR	0 	0 	0 	0S..///EEE	0 Ls   <C )C87C8mccmncc                    |                                  } |                                 }t          |          dk    rd}n4t          |          dk    r	d|z   dz   }nt          |          dk    r|dz  }t          |           dk    rd} n1t          |           dk    rd| z   } nt          |           dk    rd| z   } | d         | d         z   |d         | d         z   z   |d         |d         z   z   S )z,Converts integer MCC/MNC into 3 bytes for EFr   FFFr   0Fr$   00)r,   r   r;   r<   s     r   enc_plmnrC   q   s    
 ))++C
))++C 3xx1}}	SQCi#o	SQs

3xx1}}	SQSj	SQCiFSVOAQ0CFSVODDr   threehexbytesc                 v    ddd}t          |            t          |           |d<   t          |           |d<   |S )Nr?   rB   r;   r<   dec_mcc_from_plmn_strdec_mnc_from_plmn_str)rD   ress     r   dec_plmnrJ      sD    c
"
"C-(((&}55CJ&}55CJJr   plmnc                     t          |           }|d         dz  }|d         dz  dz	  }|d         dz  }|dk    r|dk    r|dk    rdS t          |||          S )Nr   r      r#   r     )h2i
derive_mccrK   iadigit1digit2digit3s        r   dec_mcc_from_plmnrV      si    	TBUT\Fedlq FUT\F}}36S==ufff---r   c                     | d         }| d         }| d         }||z   |z   }|                                                     d          S )Nr   r   r   r@   upperr,   rK   rS   rT   rU   rI   s        r   rG   rG      G    !WF!WF!WF
6/F
"C99;;S!!!r   c                     t          |           }|d         dz  }|d         dz  dz	  }|d         dz  dz	  }|dk    r|dk    r|dk    rdS t          |||          S )Nr$   r   rM   r#   r   rN   )rO   
derive_mncrQ   s        r   dec_mnc_from_plmnr^      sn    	TBUT\Fedlq Fedlq F}}36S==ufff---r   c                     | d         }| d         }| d         }||z   |z   }|                                                     d          S )N   r#   r$   r@   rX   rZ   s        r   rH   rH      r[   r   twohexbytesc                    ddddddddddd	dd
ddg}t          |           }|d         dz  |d         z  }t                      }|D ]+}|d|d         z  z  r|                    |d                    ,|dz  }|dv r+|                    d           |                    d           n7|dk    r|                    d           n|dk    r|                    d           |dz  }|dv r+|                    d           |                    d           n=|dz  dk    r|                    d           n|dz  dk    r|                    d           t          t	          |                    S )Nr   UTRAN)bitname   zNG-RAN   zGSM COMPACTr`   zcdma2000 HRPDr#   zcdma2000 1xRTTr      r   rd   re    p  )i @  ri   zE-UTRAN WB-S1zE-UTRAN NB-S1i P  i `     )   rj   GSMz
EC-GSM-IoT      )rO   setaddsortedlist)ra   act_listrR   u16tselaeutran_bitsgsm_bitss           r   dec_actry      s   G$$H%%M**O,,,--H 
[		BqEQJ"Q%D
%%C  1%=! 	GGAfI-K&&&       			    			   f}H###	&	 	 	&	 	 $s))r   fivehexbytesc                     ddg d}d}d}| d |         }| |||z            }t          |          |d<   t          |          |d<   t          |          |d<   |S )Nr?   r;   r<   actrg   r#   r;   r<   r}   )rG   rH   ry   )rz   rI   
plmn_chars	act_charsplmn_stract_strs         r   dec_xplmn_w_actr      su    c"
-
-CJIKZK(H:j9&<<=G&x00CJ&x00CJ!!CJJr   c                 r    ddg d}d}| d |         }t          |          |d<   t          |          |d<   |S )Nr   r|   rg   r;   r<   rF   )rD   rI   r~   r   s       r   	dec_xplmnr      sK    Ab
)
)CJ[j[)H&x00CJ&x00CJJr   ki_hexop_hexc                    ddl m} ddlm} t	          t          |                     }t	          t          |                    }|                    ||j                  }|                    |          }t           |||                    S )zD
    Run the milenage algorithm to calculate OPC from Ki and OP
    r   )AES)strxor)
Cryptodome.Cipherr   Cryptodome.Util.strxorr   bytesh2bnewMODE_ECBencryptb2h)r   r   r   r   ki_bytesop_bytesaes	opc_bytess           r   derive_milenage_opcr      s     &%%%%%------ S[[!!HS[[!!H
''(CL
)
)CH%%Ivvi**+++r   c           	          t          t          t          t          |                               }dt	          |ddd         d |ddd         D             z             dz  z
  }|dk    rdn|S )z=
    Calculate Luhn checksum used in e.g. ICCID and IMEI
    
   Nc                 N    g | ]"}t          t          |d z  d                    #S )r$   r   )sumdivmod).0ds     r   
<listcomp>z"calculate_luhn.<locals>.<listcomp>  s>     */ */ */  +.fQUB.?.?*@*@ */ */ */r   r   )rr   mapr'   r6   r   )ccnumcheck_digits      r   r8   r8     s     s3B  
!
!Cs3rv2v; */ */$'"I*/ */ */ / 0 0245 5Kr!!11{2r   digitsc                     t          | dd                   }t          |          | d         k    r(t          dt          |          d| d                   dS )zBVerify the Luhn check digit; raises ValueError if it is incorrect.Nz%Luhn check digit mismatch: should be z but is )r8   r6   r7   )r   cds     r   r9   r9     sc    	ss	$	$B
2ww&*jPSTVPWPWPWPWY_`bYcYcdeee r   c                 H    | dS t          |           dk    r
| dd         S dS )zU
    Derive the MCC (Mobile Country Code) from the first three digits of an IMSI
    Nr   r   )r   s    r   mcc_from_imsir     s/     |t
4yy1}}BQBxtr   Flongc                 `    | dS t          |           dk    r|r
| dd         S | dd         S dS )zS
    Derive the MNC (Mobile Country Code) from the 4th to 6th digit of an IMSI
    Nr   rg   r`   r   )r   r   s     r   mnc_from_imsir   #  sF     |t
4yy1}} 	!9!9tr   rS   rT   rU   c                 X    d}| dk    r|| dz  z  }|dk    r||dz  z  }|dk    r||z  }|S )ze
    Derive decimal representation of the MCC (Mobile Country Code)
    from three given digits.
    r   r   d   r    )rS   rT   rU   r;   s       r   rP   rP   3  sN     C~~v|~~v{~~vJr   r   c                 j    d}|dk    rt          | ||          S | dk    r|| dz  z  }|dk    r||z  }|S )zy
    Derive decimal representation of the MNC (Mobile Network Code)
    from two or (optionally) three given digits.
    r   r   r   )rP   )rS   rT   rU   r<   s       r   r]   r]   E  sT     C ~~&&&111~~v{~~vJr   c                 `   | Rt          |           dk    r0d                    d | D                       } t          | d          } nt          d          |Wt          |          dk    r5|} 	 t	          |           }n1# t          $ r}t          d          |d}~ww xY wt          d          | S )	a  
    The ADM pin can be supplied either in its hexadecimal form or as
    ascii string. This function checks the supplied opts parameter and
    returns the pin_adm as hex encoded string, regardless in which form
    it was originally supplied by the user
    Nrh    c                 2    g | ]}d t          |          z  S )r   )ordr   xs     r   r   z$sanitize_pin_adm.<locals>.<listcomp>c  s#    BBBQvQ0BBBr   r%   z&PIN-ADM needs to be <=8 digits (ascii)z1PIN-ADM needs to be hex encoded using this optionz3PIN-ADM needs to be exactly 16 digits (hex encoded))r   joinr   r7   r   )pin_admpin_adm_hex
try_encodeexcs       r   sanitize_pin_admr   Y  s     w<<1ggBB'BBBCCG7B''GG EFFF{r!!!G_ \\

 _ _ _ !TUU[^^_ RSSSNs   -A= =
BBBc                    t          |           dk    rdS |                     d          }	 ddl}|                    |           }|j        dk    rdS |j        dk    rdS n:# t
          $ r- d}|D ] }ddl}|                    d	|          sd
} n!|rY dS Y nw xY wd}|D ] }ddl}|                    d|          sd
} n!|rdS dS )z
    Validates the given address and returns it's type (FQDN or IPv4 or IPv6)
    Return: 0x00 (FQDN), 0x01 (IPv4), 0x02 (IPv6), None (Bad address argument given)

    TODO: Handle IPv6
    r   N.r#   r   rg   r$   Tz	^[0-9_]+$Fz ^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)?$)r   split	ipaddress
ip_addressversion	Exceptionrematch)addr	addr_listr   ipainvalid_ipv4ir   	fqdn_flags           r   get_addr_typer   w  sG    4yyA~~t

3I""4((;!4[A4     	 	A III88K++ $  	44	 	 I  			xx:A>> 	IE	
  t4s   $A  A   1BBswpatternc                     |                                  }d}t          dd          D ]1}||         dk    r|dz   }||         dk    r|dz   }&|||         z   }2||k    S )z%Match given SW against given pattern.r   r   r#   ?r   )lowerrange)r   r   sw_lower	sw_maskedr   s        r   sw_matchr     s|     xxzzHI1a[[ 0 01:!CIIQZ3!CII!HQK/IIr   O   r$   r   Twidthhspacelspace
align_leftc                    | dS t          |           dk    rdS t          | t                     }t          |          |z   }||z  }t          |           dz
  |z  dz   }g }	t          t          |                    D ]V}
| |
d|         }|rd}nd}||z  t          |          z  }d|z  |z   }|	                    |t          |          z             Wd	                    |	          S )
aZ  Pretty print a list of strings into a tabulated form.

    Args:
            width : total width in characters per line
            space : horizontal space between cells
            lspace : number of spaces before row
            align_lef : Align text to the left side
    Returns:
            multi-line string containing formatted table
    Nr   r   )keyr   z%%-%dsz%%%ds 
)r   maxiterr   appendtupler   )str_listr   r   r   r   longest_strcellwithcolsrowstabler   str_list_rowformat_str_cellformat_str_rows                 r   tabulate_str_listr     s    r
8}}rhC(((K;&(HHDMMA$&*DE%++ ; ;4( 	&&OO%O)H4L8I8II,.8^eL&9&99::::99Ur   c                 `   |                      d          dk    rk|                     d          }|dk    r| |dz
           }n| |dz            }|dz  t          |           dz
  z
  }|dk    r| S |                     d||z            S |                      d          dk    rt          |           dz  r| S |                     d          }|dz  r| S |dk    r| |dz
  |         }n| |dz   |dz            }|dz  t          |           dz
  z
  }|dk    r| S |                     d||dz  z            S | S )ap  Expand a given hexstring to a specified length by replacing "." or ".."
       with a filler that is derived from the neighboring nibbles respective
       bytes. Usually this will be the nibble respective byte before "." or
       "..", except when the string begins with "." or "..", then the nibble
       respective byte after "." or ".." is used.". In case the string cannot
       be expanded for some reason, the input string is returned unmodified.

    Args:
            hexstring : hexstring to expand
            length : desired length of the resulting hexstring.
    Returns:
            expanded hexstring
    r   r   r   r$   z..r#   )countindexr   replace)	hexstringlengthposfillermissings        r   
expand_hexr     sm     sq  ooc""77sQw'FFsQw'F1*I 23a<<  fw&6777 
		!	#	#y>>A 	ood##7 	77sQws{+FFsQws1u}-F1*I 23a<<  vA'>??? r   P   c                     t          |           |dz
  k    rt          |           dz   }d|z  }dt          |dz
            z   dz   }||| z  z  }|d|z  z  }|S )z0Generate a string that contains a boxed heading.r#   #z
# %-zs #
)r   r6   )headingr   rI   fstrs       r   boxed_heading_strr     sm     7||eaiGq 
+Cc%!)nn$w.D47C3;CJr   apduc                 H   t          |           dk    rd}d}d}d|||fS t          |           dk    rd}| d         }|dk    rd}d}d|||fS t          |           dk    r| d         }|dk    rd}| d|dz            }t          |           d|z   k    rd}d|||fS t          |           d|z   dz   k    r| d|z            }|dk    rd}d|||fS t          d	t          |           ||t          | dd
                   fz            t          dt          |           z            )a*  Parse a given command APDU and return case (see also ISO/IEC 7816-3, Table 12 and Figure 26),
    lc, le and the data field.

    Args:
            apdu : hexstring that contains the command APDU
    Returns:
            tuple containing case, lc and le values of the APDU (case, lc, le, data)
    r#   r   r   r   r`      r$   r   zRinvalid APDU (%s), Lc=0x%02x (%d) does not match the length (%d) of the data fieldNzinvalid APDU (%s), too short!)r   r7   r   )r   lcledatas       r   parse_command_apdur    sm    4yyA~~2r4  	Ta!W77B2r4  	TQ!W77BAbdF|t99BBr2t$$YY!b&1*$$a"fBQwwr2t$$q #D		2r3tABBx==AB C C C 83t99DEEEr   c                 b   |                      dd          } |                      dd          } g }t          |           dk    r<| dd         | dd         } }|                    |           t          |           dk    <t          |           dk    rt          d| z            d |D             } | S )	aK  Transform an ATR in list of integers.
    valid input formats are
    "3B A7 00 40 18 80 65 A2 08 01 01 52"
    "3B:A7:00:40:18:80:65:A2:08:01:01:52"

    Args:
        atr: string
    Returns:
        list of bytes

    >>> normalize("3B:A7:00:40:18:80:65:A2:08:01:01:52")
    [59, 167, 0, 64, 24, 128, 101, 162, 8, 1, 1, 82]
    :r   r   r$   Nr   z"warning: odd string, remainder: %rc                 .    g | ]}t          |d           S )r%   )r'   r   s     r   r   z normalizeATR.<locals>.<listcomp>f  s     
#
#
#!3q"::
#
#
#r   )r   r   r   r7   )atrrI   bytes      r   normalizeATRr
  N  s     ++c2

C
++c2

C
C
c((a--GSWc

4 c((a-- 3xx!||=CDDD
#
#s
#
#
#CJr   c                    d}t          |           } i }| |d<   d| d         i|d<   | d         }d|i|d<   |dz  }d}d}|dz  |d<   |t          |           k     r|d	z  d
k    r!|dz  }d|vri |d<   d| |         i|d         |<   |dz  d
k    r!|dz  }d|vri |d<   d| |         i|d         |<   |dz  d
k    r!|dz  }d|vri |d<   d| |         i|d         |<   |dz  d
k    r7|dz  }d|vri |d<   | |         }d|i|d         |<   |dz  |k    rd|d<   |dz  }nn|t          |           k     d| |dz   |dz   |z            i|d<   |dz   |z   }d|v r+	 d| |         i|d<   n# t          $ r
 ddi|d<   Y nw xY w|dz  }t          |           |k    r| |d         |d<   t          |d         d                   |k     r:|t          |d         d                   z
  }|dk    rd\  }	}
nd\  }	}
d||	|
fz  |d<   |S )a   Decompose the ATR in elementary fields

        Args:
            atr_txt: ATR as a hex bytes string
        Returns:
            dictionary of field and values

        >>> decomposeATR("3B A7 00 40 18 80 65 A2 08 01 01 52")
    { 'T0': {'value': 167},
      'TB': {1: {'value': 0}},
      'TC': {2: {'value': 24}},
      'TD': {1: {'value': 64}},
      'TS': {'value': 59},
      'atr': [59, 167, 0, 64, 24, 128, 101, 162, 8, 1, 1, 82],
      'hb': {'value': [128, 101, 162, 8, 1, 1, 82]},
      'hbn': 7}
    r   r  valueTSr   T0r   hbn      TA   TB   TC   TDTTCKhbr   Nextra)sare)r   isz&ATR is truncated: %d byte%s %s missingwarning)r
  r   
IndexError)atr_txtATR_PROTOCOL_TYPE_T0r  TDi	hb_lengthpointerpnlastr   t1t2s              r   decomposeATRr*  k  s   $ 7##G
C CJ '!*%CI
!*C#CIbIG	
B sCJ
CLL
 
 $J4qLG3D	$gg&67CIbM $J4qLG3D	$gg&67CIbM $J4qLG3D	$gg&67CIbM $J4qLG3D	'"C$cNCIbMd
333!E
!GBBC CLL
 
 H ''A+!i0G"GHICI Q;"D||	'!74=1CJJ 	' 	' 	'!2CJJJ	'	
7||dtuu~G
3t9W**c#d)G"4555Q;;#HR!HRAWbRTDUUIJs   E E21E2c                      e Zd ZdZddedee         dee         fdZd Zdefd	Z	ddZ
ddZdefdZdefdZej        defd            Zej        defd            ZdedefdZdefdZdedeeef         fdZdefdZdS )
DataObjecta`  A DataObject (DO) in the sense of ISO 7816-4.  Contrary to 'normal' TLVs where one
    simply has any number of different TLVs that may occur in any order at any point, ISO 7816
    has the habit of specifying TLV data but with very specific ordering, or specific choices of
    tags at specific points in a stream.  This class tries to represent this.Nre   desctagc                 L    || _         || _        || _        d| _        d| _        dS )z
        Args:
            name: A brief, all-lowercase, underscore separated string identifier
            desc: A human-readable description of what this DO represents
            tag : The tag associated with this DO
        N)re   r-  r.  decodedencoded)selfre   r-  r.  s       r   __init__zDataObject.__init__  s+     		r   c                     | j         S Nre   r2  s    r   __str__zDataObject.__str__  
    yr   r!   c                 &    | j         d| j        dS )N())	__class__re   r7  s    r   __repr__zDataObject.__repr__  s    >>>499955r   DataObjectChoicec                 `    t          |t                    rt          d| |g          S t          )z7OR-ing DataObjects together renders a DataObjectChoice.Nmembers)
isinstancer,  r?  	TypeErrorr2  others     r   __or__zDataObject.__or__  s0    eZ(( 	#D4-@@@@Or   DataObjectCollectionc                 `    t          |t                    rt          d| |g          S t          )z<ADD-ing DataObjects together renders a DataObjectCollection.NrA  )rC  r,  rH  rD  rE  s     r   __add__zDataObject.__add__  s0    eZ(( 	'tUmDDDDOr   c                     | j         S )z>Compute the tag (sometimes the tag encodes part of the value).r.  r7  s    r   _compute_tagzDataObject._compute_tag  s	    xr   c                     | j         | j        iS )z,Return a dict in form "name: decoded_value" )re   r0  r7  s    r   to_dictzDataObject.to_dict  s    	4<((r   doc                     dS )zParse the value part of the DO into the internal state of this instance.
        Args:
            do : binary encoded bytes
        Nr   )r2  rP  s     r   
from_byteszDataObject.from_bytes        r   c                     dS )zEncode the internal state of this instance into the TLV value part.
        Returns:
            binary bytes encoding the internal state
        Nr   r7  s    r   to_byteszDataObject.to_bytes  rS  r   c                     |d         | j         k    rt          d| | j         fz            |d         }|dd|z            }|                     |           |d|z   d         S )aS  Parse binary TLV representation into internal state.  The resulting decoded
        representation is _not_ returned, but just internalized in the object instance!
        Args:
            do : input bytes containing TLV-encoded representation
        Returns:
            bytes remaining at end of 'do' after parsing one TLV/DO.
        r   z%s: Can only decode tag 0x%02xr   r$   N)r.  r7   rR  )r2  rP  r   vals       r   from_tlvzDataObject.from_tlv  sw     a5DH="DH-. / / /A1V8n!F())}r   c                     |                                  }t          |                                           t          t	          |                    z   |z   S )zpEncode internal representation to binary TLV.
        Returns:
            bytes encoded in TLV format.
        )rU  r   rM  r   r   )r2  rW  s     r   to_tlvzDataObject.to_tlv  sE    
 mmoo !2!2!4!4558I#c((8S8SSVYYYr   binaryc                     |d         }|| j         k    rt          d| ||| j         fz            |                     |          }|                                 |fS )zDecode a single DOs from the input data.
        Args:
            binary : binary bytes of encoded data
        Returns:
            tuple of (decoded_result, binary_remainder)
        r   z-%s: Unknown Tag 0x%02x in %s; expected 0x%02x)r.  r7   rX  rO  )r2  r[  r.  	remainders       r   decodezDataObject.decode&  sd     Qi$(??L"C:; < < <MM&))		**r   c                 *    |                                  S r5  )rZ  r7  s    r   encodezDataObject.encode5  s    {{}}r   NNr!   r?  r!   rH  )__name__
__module____qualname____doc__r6   r   r'   r3  r8  r>  rG  rJ  rM  dictrO  abcabstractmethodr   rR  rU  rX  rZ  r   r^  r`  r   r   r   r,  r,    s       Q Q
 S  8C=      6# 6 6 6 6      c    ) ) ) ) ) 	U     	%    5 U    "Z Z Z Z Z+U +uT5['9 + + + +      r   r,  c                   J     e Zd ZdZddededef fdZdefdZd	efd
Z	 xZ
S )TL0_DataObjectz2Data Object that has Tag, Len=0 and no Value part.Nre   r-  r.  c                 \    t                                          |||           || _        d S r5  )superr3  rW  )r2  re   r-  r.  rW  r=  s        r   r3  zTL0_DataObject.__init__<  s*    tS)))r   r[  c                 R    t          |          dk    rt          | j        | _        d S Nr   )r   r7   rW  r0  )r2  r[  s     r   rR  zTL0_DataObject.from_bytes@  s&    v;;!xr   r!   c                     dS )Nr   r   r7  s    r   rU  zTL0_DataObject.to_bytesE  s    sr   r5  )rd  re  rf  rg  r6   r'   r3  r   rR  rU  __classcell__)r=  s   @r   rl  rl  9  s        << S  #               
%        r   rl  c                   |    e Zd ZdZddedee         fdZdefdZdefdZdd	Z	d
e
deee
f         fdZde
fdZdS )rH  zA DataObjectCollection consists of multiple Data Objects identified by their tags.
    A given encoded DO may contain any of them in any order, and may contain multiple instances
    of each DO.Nre   r-  c                     || _         || _        |pg | _        i | _        i | _        d |D             | _        d |D             | _        d S )Nc                     i | ]
}|j         |S r   rL  r   ms     r   
<dictcomp>z1DataObjectCollection.__init__.<locals>.<dictcomp>T  s    999Aqua999r   c                     i | ]
}|j         |S r   r6  rv  s     r   rx  z1DataObjectCollection.__init__.<locals>.<dictcomp>U  s    ;;;a;;;r   )re   r-  rB  members_by_tagmembers_by_name)r2  re   r-  rB  s       r   r3  zDataObjectCollection.__init__N  s]    		}" !99999;;7;;;r   r!   c                 d    d | j         D             }| j        dd                    |          dS )Nc                 ,    g | ]}t          |          S r   r6   r   s     r   r   z0DataObjectCollection.__str__.<locals>.<listcomp>X  s    444!s1vv444r   r;  ,r<  )rB  re   r   r2  member_strss     r   r8  zDataObjectCollection.__str__W  s:    44t|444999chh{&;&;&;&;<<r   c                 d    d | j         D             }| j        dd                    |          dS )Nc                 ,    g | ]}t          |          S r   reprr   s     r   r   z1DataObjectCollection.__repr__.<locals>.<listcomp>\  s    5551tAww555r   r;  r  r<  )rB  r=  r   r  s     r   r>  zDataObjectCollection.__repr__[  s:    55555>>>388K+@+@+@+@AAr   c                     t          |t                    r*| j        |j        z   }t          | j        | j        |          S t          |t
                    r$t          | j        | j        | j        |gz             S t          )zDExtending DataCollections with other DataCollections or DataObjects.)rC  rH  rB  re   r-  r,  rD  r2  rF  rB  s      r   rJ  zDataObjectCollection.__add___  so    e122 	lU]2G'	49gFFFz** 	'	49dleW>TUUUOr   r[  c                 p   g }|}t          |          r|d         }|dk    r||fS || j        vr-t          d| ||| j                                        fz            | j        |         }|                    |          }|                    |                                           t          |          ||fS )a  Decode any number of DOs from the collection until the end of the input data,
        or uninitialized memory (0xFF) is found.
        Args:
            binary : binary bytes of encoded data
        Returns:
            tuple of (decoded_result, binary_remainder)
        r   r  )%s: Unknown Tag 0x%02x in %s; expected %s)r   rz  r7   keysrX  r   rO  )r2  r[  rI   r]  r.  objs         r   r^  zDataObjectCollection.decodel  s     	)nn 	&A,Cd{{Y''$--- !L"&Y8K8P8P8R8R!S"T U U U%c*CY//IJJs{{}}%%% )nn 	& Yr   c                     t                      }|D ]D}|                     |d                   }|                    |                                           E|S rp  )	bytearrayr{  r   rZ  )r2  r0  rI   r   r  s        r   r`  zDataObjectCollection.encode  sS    kk 	% 	%A&&qt,,CJJszz||$$$$
r   ra  rc  )rd  re  rf  rg  r6   r   r3  r8  r>  rJ  r   r   r   r^  r`  r   r   r   rH  rH  I  s         < <S < < < < <= = = = =B# B B B B
 
 
 
 U  uT5['9        4      r   rH  c                   L    e Zd ZdZd Zd	dZdedeeef         fdZ	defdZ
dS )
r?  zOne Data Object from within a choice, identified by its tag.
    This means that exactly one member of the choice must occur, and which one occurs depends
    on the tag.c                     t           )zRWe overload the add operator here to avoid inheriting it from DataObjecCollection.)rD  rE  s     r   rJ  zDataObjectChoice.__add__  s    r   r!   c                     t          |t                    r*| j        |j        z   }t          | j        | j        |          S t          |t
                    r$t          | j        | j        | j        |gz             S t          )zROR-ing a Choice to another choice extends the choice, as does OR-ing a DataObject.)rC  r?  rB  re   r-  r,  rD  r  s      r   rG  zDataObjectChoice.__or__  so    e-.. 	lU]2G#DIty'BBBz** 	#DIty$,%:PQQQOr   r[  c                    |d         }|dk    rd|fS || j         vr-t          d| ||| j                                         fz            | j         |         }|                    |          }|                                |fS )zDecode a single DOs from the choice based on the tag.
        Args:
            binary : binary bytes of encoded data
        Returns:
            tuple of (decoded_result, binary_remainder)
        r   r  Nr  )rz  r7   r  rX  rO  )r2  r[  r.  r  r]  s        r   r^  zDataObjectChoice.decode  s     Qi$;;&>!d)))H"C1D1I1I1K1KLM N N N!#&LL((	y))r   c                     | j         t          |          d                  }t          |                                          d         |_        |                                S rp  )r{  rr   valuesr0  rZ  )r2  r0  r  s      r   r`  zDataObjectChoice.encode  sF    "4==#347>>++,,Q/zz||r   Nrb  )rd  re  rf  rg  rJ  rG  r   r   rh  r^  r`  r   r   r   r?  r?    s           
 
 
 
*U *uT5['9 * * * *$      r   r?  c                       e Zd ZdZddedee         fdZdefdZdefdZdd	Z	d
e
deee
f         fdZde
deee
f         fdZde
fdZde
fdZdS )DataObjectSequenceaD  A sequence of DataObjects or DataObjectChoices. This allows us to express a certain
       ordered sequence of DOs or choices of DOs that have to appear as per the specification.
       By wrapping them into this formal DataObjectSequence, we can offer convenience methods
       for encoding or decoding an entire sequence.Nre   r-  c                 4    |pg | _         || _        || _        d S r5  )sequencere   r-  )r2  re   r-  r  s       r   r3  zDataObjectSequence.__init__  s     B				r   r!   c                 d    d | j         D             }| j        dd                    |          dS )Nc                 ,    g | ]}t          |          S r   r~  r   s     r   r   z.DataObjectSequence.__str__.<locals>.<listcomp>  s    555!s1vv555r   r;  r  r<  )r  re   r   r  s     r   r8  zDataObjectSequence.__str__  s:    55t}555999chh{&;&;&;&;<<r   c                 d    d | j         D             }| j        dd                    |          dS )Nc                 ,    g | ]}t          |          S r   r  r   s     r   r   z/DataObjectSequence.__repr__.<locals>.<listcomp>  s    6661tAww666r   r;  r  r<  )r  r=  r   r  s     r   r>  zDataObjectSequence.__repr__  s:    66666>>>388K+@+@+@+@AAr   c                 F   t          |d          r$t          | j        | j        | j        |gz             S t          |d          r$t          | j        | j        | j        |gz             S t          |d          r(t          | j        | j        | j        |j        z             S dS )z>Add (append) a DataObject or DataObjectChoice to the sequence.r,  r?  r  N)rC  r  re   r-  r  rE  s     r   rJ  zDataObjectSequence.__add__  s    e\** 	\%diDMUG<STTT122 	\%diDMUG<STTT344 	\%diDMEN<Z[[[	\ 	\r   r[  c                     |}g }| j         D ]1}|                    |          \  }}|r|                    |           2||fS )zDecode a sequence by calling the decoder of each element in the sequence.
        Args:
            binary : binary bytes of encoded data
        Returns:
            tuple of (decoded_result, binary_remainder)
        )r  r^  r   )r2  r[  r]  rI   ers         r   r^  zDataObjectSequence.decode  sW     	 	 	AXXi00NQ	 

1Yr   rP  c                     |}g }t          |          rd|                     |          \  }}|r|                    |           t          |          t          |          k     r|}n|}nt          |          d||fS )zDecode multiple occurrences of the sequence from the binary input data.
        Args:
            do : binary input data to be decoded
        Returns:
            list of results of the decoder of this sequences
        )r   r^  r   )r2  rP  r]  rI   r  
remainder2s         r   decode_multizDataObjectSequence.decode_multi  s     	)nn 	"kk)44OQ
 

1:Y//&		&	 )nn 	 Yr   c                     t                      }d}| j        D ]%}||                    ||                   z  }|dz  }&|S )zIEncode a sequence by calling the encoder of each element in the sequence.r   r   )r  r  r`  )r2  r0  r1  r   r  s        r   r`  zDataObjectSequence.encode  sK    ++ 	 	Aqxx
+++GFAAr   c                 \    t                      }|D ]}||                     |          z  }|S )zEncode multiple occurrences of the sequence from the decoded input data.
        Args:
            decoded : list of json-serializable input data; one sequence per list item
        Returns:
            binary encoded output data
        )r  r`  )r2  r0  r1  r   s       r   encode_multizDataObjectSequence.encode_multi  s7     ++ 	& 	&At{{1~~%GGr   ra  )r!   r  )rd  re  rf  rg  r6   r   r3  r8  r>  rJ  r   r   rr   r^  r  r`  r  r   r   r   r  r    s(       7 7
 S     
= = = = =B# B B B B\ \ \ \ U  uT5['9          u  tU{);        *    
u 
 
 
 
 
 
r   r  c                   ,    e Zd ZdZddZd Zd Zd ZdS )CardCommandz$A single card command / instruction.Nc                 n    || _         || _        |pg | _        d | j        D             | _        || _        d S )Nc                 6    g | ]}|                                 S r   )r   r   s     r   r   z(CardCommand.__init__.<locals>.<listcomp>  s     :::q:::r   )re   inscla_listr-  )r2  re   r  r  r-  s        r   r3  zCardCommand.__init__  s=    	 B::DM:::			r   c                     | j         S r5  r6  r7  s    r   r8  zCardCommand.__str__  r9  r   c                 0    d| j         | j        | j        fz  S )Nz%s(INS=%02x,CLA=%s))re   r  r  r7  s    r   r>  zCardCommand.__repr__!  s    $	48T]'KKKr   c                     t          |t                    sd|z  }|                                }| j        D ]=}d}t	          dd          D ]}||         dk    r|dz  }|||         z  } ||k    r dS >dS )z6Does the given CLA match the CLA list of the command?.z%02ur   r   r$   r   TF)rC  r6   r   r  r   )r2  cla	cla_match
cla_maskedr   s        r   	match_clazCardCommand.match_cla$  s    #s## 	3,Ciikk 	 	IJ1a[[ ) )Q<3&&#%JJ#a&(JJY&&tt 'ur   ra  )rd  re  rf  rg  r3  r8  r>  r  r   r   r   r  r    s^        ..     L L L    r   r  c                   6    e Zd ZdZg fdZd Zd Zd ZddZdS )	CardCommandSetz@A set of card instructions, typically specified within one spec.c                 6    || _         d |D             | _        d S )Nc                     i | ]
}|j         |S r   )r  )r   cs     r   rx  z+CardCommandSet.__init__.<locals>.<dictcomp>:  s    ,,,!QUA,,,r   )re   cmds)r2  re   r  s      r   r3  zCardCommandSet.__init__8  s"    	,,t,,,			r   c                     | j         S r5  r6  r7  s    r   r8  zCardCommandSet.__str__<  r9  r   c                     | j         |         S r5  )r  )r2  idxs     r   __getitem__zCardCommandSet.__getitem__?  s    y~r   c                 v   t          |t                    rI|j        | j        v r*t	          d| |j        | j        |j                 fz            || j        |j        <   d S t          |t
                    r3|j                                        D ]}|j        |         | j        |<   d S t	          | d|          )Nz"%s: INS 0x%02x already defined: %sz$: Unsupported type to add operator: )rC  r  r  r  r7   r  r  )r2  rF  r  s      r   rJ  zCardCommandSet.__add__B  s    e[)) 
	LyDI%% !E"&	49UY3G!H"I J J J#(DIei   ~.. 	LZ__&& - -$z!}	!- - >BddEEJL L Lr   Nc                     t          |          }|| j        vrdS | j        |         }|r|                    |          sdS |S )z*look-up the command within the CommandSet.N)r'   r  r  )r2  r  r  cmds       r   lookupzCardCommandSet.lookupO  sO    #hhdi4in 	s}}S)) 	4
r   r5  )	rd  re  rf  rg  r3  r8  r  rJ  r  r   r   r   r  r  5  su        JJ"$ - - - -    L L L     r   r  )F)r   r5  )r   r$   r   T)r   )Crg  jsonri  stringdatetimeargparseior   typingr   r   r   r   r   r	   r
   osmocom.utilsosmocom.tlvr   r   r6   r   r   HexstrResTupler   r*   r-   r2   r'   r:   rC   rh  rJ   rV   rG   r^   rH   ry   r   r   r   r8   r9   r   boolr   rP   r]   r   r   r   r   r   r   r   r  r
  r*  ABCr,  rl  rH  r?  r  r  r  r   r   r   <module>r     sT     



          C C C C C C C C C C C C C C C C C C     < < < < < < < <F 7:s##W\3''
!"3     HSM    &'& 'S ' ' ' ')S )V ) ) ) )%S/ c    2E& Ev E& E E E E6F t    .F .s . . . ." "3 " " " ".F .s . . . ." "3 " " " "! !DI ! ! ! !H& T#s(^    V     , , ,6 , , , , 3# 3 3 3 3f f f f f
 
 
 
 
 
  4 HSM     s C      $ s C      ( 6    <1 1 1h   s  t          QR)- s  # "&25   B3 3 3l
 
 
 
+FU +Fs +F +F +F +F^  :_ _ _Di i i i i i i iX    Z    B B B B B B B BJ+ + + + ++ + + +\U U U U U U U Up       B" " " " " " " " " "r   