예제 #1
0
 def test_authentication(self):
     if self._auth > 2:
         return 1
     #
     # prepare dummy 128 bits auth challenge
     if not hasattr(self, 'RAND'):
         self.RAND = 16*b'\x44'
     if not hasattr(self, 'SQN'):
         # default SQN is 0, coded on 48 bits
         self.SQN = 0
     # management field, unneeded, left blank
     AMF = b'\0\0'
     #
     # compute Milenage functions
     XRES, CK, IK, AK = self.Milenage.f2345( self.K, self.RAND )
     MAC_A = self.Milenage.f1(self.K, self.RAND, sqn_to_str(self.SQN), AMF)
     AUTN = xor_buf(sqn_to_str(self.SQN), AK) + AMF + MAC_A
     #
     # run auth data on the USIM
     self.U = USIM()
     ret = self.U.authenticate(stringToByte(self.RAND), stringToByte(AUTN), '3G')
     self.U.disconnect()
     self._auth += 1
     #
     # check results (and pray)
     if ret == None:
         print('[-] authenticate() failed, something wrong happened')
         del self.RAND
         return 1
     #
     elif len(ret) == 1:
         print('[-] sync failure during authenticate() with SQN %i, unmasking counter' % self.SQN)
         auts = byteToString(ret[0])
         ak = self.Milenage.f5star(self.K, self.RAND)
         self.SQN = str_to_sqn(xor_buf(auts, ak)[:6])
         print('[+] SQN counter value in USIM: %i' % self.SQN)
         self.SQN += 1<<5
         print('[+] retrying authenticate() with SQN: %i' % self.SQN)
         del self.RAND
         return self.test_authentication()
     #
     elif len(ret) in (3, 4):
         # RES, CK, IK(, Kc)
         if ret[0:3] == map(stringToByte, [XRES, CK, IK]):
             print('[+] 3G auth successful with SQN: %i\nincrement it from now' % self.SQN)
             print('[+] USIM secrets:\nOPc: %s\nK: %s' % (hexlify(self.OPc), hexlify(self.K)))
         else:
             print('[-] 3G auth accepted on the USIM, but not matching auth vector generated: strange!')
             print('card returned:\n%s' % ret)
         del self.RAND
         return 0
     #
     else:
         print('[-] undefined auth error')
         del self.RAND
         return 1
예제 #2
0
 def test_authentication(self):
     if self._auth > 2:
         return 1
     #
     # prepare dummy 128 bits auth challenge
     if not hasattr(self, 'RAND'):
         self.RAND = 16*b'\x44'
     if not hasattr(self, 'SQN'):
         # default SQN is 0, coded on 48 bits
         self.SQN = 0
     # management field, unneeded, left blank
     AMF = b'\0\0'
     #
     # compute Milenage functions
     XRES, CK, IK, AK = self.Milenage.f2345( self.K, self.RAND )
     MAC_A = self.Milenage.f1(self.K, self.RAND, sqn_to_str(self.SQN), AMF)
     AUTN = xor_buf(sqn_to_str(self.SQN), AK) + AMF + MAC_A
     #
     # run auth data on the USIM
     self.U = USIM()
     ret = self.U.authenticate(stringToByte(self.RAND), stringToByte(AUTN), '3G')
     self.U.disconnect()
     self._auth += 1
     #
     # check results (and pray)
     if ret == None:
         print('[-] authenticate() failed, something wrong happened')
         del self.RAND
         return 1
     #
     elif len(ret) == 1:
         print('[-] sync failure during authenticate() with SQN %i, unmasking counter' % self.SQN)
         auts = byteToString(ret[0])
         ak = self.Milenage.f5star(self.K, self.RAND)
         self.SQN = str_to_sqn(xor_buf(auts, ak)[:6])
         print('[+] SQN counter value in USIM: %i' % self.SQN)
         self.SQN += 1<<5
         print('[+] retrying authenticate() with SQN: %i' % self.SQN)
         del self.RAND
         return self.test_authentication()
     #
     elif len(ret) in (3, 4):
         # RES, CK, IK(, Kc)
         if ret[0:3] == map(stringToByte, [XRES, CK, IK]):
             print('[+] 3G auth successful with SQN: %i\nincrement it from now' % self.SQN)
             print('[+] USIM secrets:\nOPc: %s\nK: %s' % (hexlify(self.OPc), hexlify(self.K)))
         else:
             print('[-] 3G auth accepted on the USIM, but not matching auth vector generated: strange!')
             print('card returned:\n%s' % ret)
         del self.RAND
         return 0
     #
     else:
         print('[-] undefined auth error')
         del self.RAND
         return 1
예제 #3
0
def milenage_generate(opc: bytes, amf: bytes, k: bytes, sqn: bytes,
                      rand: bytes) -> Dict[str, bytes]:
    """Generate an MILENAGE Authentication Tuple."""
    m = Milenage(None)
    m.set_opc(opc)
    mac_a = m.f1(k, rand, sqn, amf)
    res, ck, ik, ak = m.f2345(k, rand)

    # AUTN = (SQN ^ AK) || AMF || MAC
    sqn_ak = xor_buf(sqn, ak)
    autn = b''.join([sqn_ak, amf, mac_a])

    return {'res': res, 'ck': ck, 'ik': ik, 'autn': autn}
예제 #4
0
def milenage_auts(opc: bytes, k: bytes, rand: bytes,
                  auts: bytes) -> Optional[bytes]:
    """Validate AUTS. If successful, returns SQN_MS"""
    amf = b'\x00\x00'  # TS 33.102 Section 6.3.3
    m = Milenage(None)
    m.set_opc(opc)
    ak = m.f5star(k, rand)

    sqn_ak = auts[:6]
    sqn = xor_buf(sqn_ak, ak[:6])

    mac_s = m.f1star(k, rand, sqn, amf)
    if mac_s == auts[6:14]:
        return sqn
    else:
        return False
예제 #5
0
 def synch_sqn(self, IMSI, RAND, AUTS):
     """
     synchronize the local counter SQN with AUTS provided by the USIM
     in response to a given 3G or 4G authentication challenge (RAND, AMF)
     
     return 0 on successful synch, 1 on unsuccessful synch due to invalid AUTS
     or None if the IMSI is not defined in the db
     """
     # lookup db for authentication Key and counter for IMSI
     try:
         K_ALG_SQN_OP = self.db[IMSI]
     except Exception:
         self._log('WNG', '[synch_sqn] IMSI %s not present in AuC.db' % IMSI)
         return None
     if len(K_ALG_SQN_OP) == 4:
         K, ALG, SQN, OP = K_ALG_SQN_OP
     else:
         K, ALG, SQN = K_ALG_SQN_OP
         OP = None
     #
     if ALG not in (0, 4):
         # Milenage not supported
         self._log('WNG', '[make_3g_vector] IMSI %s does not support Milenage or TUAK' % IMSI)
         return None
     #
     # 33.102, section 6.3.3, for resynch, AMF is always null (0x0000)
     AMF = b'\0\0'
     #
     if ALG == 0:
         # compute Milenage functions
         if OP is not None:
             AK      = self.Milenage.f5star( K, RAND, OP )
             SQN_MS  = xor_buf( AUTS[0:6], AK )
             MAC_S   = self.Milenage.f1star( K, RAND, SQN_MS, AMF, OP )
         else:
             AK      = self.Milenage.f5star( K, RAND )
             SQN_MS  = xor_buf( AUTS[0:6], AK )
             MAC_S   = self.Milenage.f1star( K, RAND, SQN_MS, AMF )
     else:
         # ALG == 4, compute TUAK functions
         if OP is not None:
             AK      = self.TUAK.f5star( K, RAND, OP )
             SQN_MS  = xor_buf( AUTS[0:6], AK )
             MAC_S   = self.TUAK.f1star( K, RAND, SQN_MS, AMF, OP )
         else:
             AK      = self.TUAK.f5star( K, RAND )
             SQN_MS  = xor_buf( AUTS[0:6], AK )
             MAC_S   = self.TUAK.f1star( K, RAND, SQN_MS, AMF )
     #
     # unmask SQN
     SQN_MSi = unpack('>Q', b'\0\0' + SQN_MS)[0]
     #
     self._log('DBG', '[synch_sqn] USIM resynchronization, SQN_MS %i, MAC_S %s'\
               % (SQN_MSi, hexlify(MAC_S).decode('ascii')))
     #
     # authenticate the USIM
     if MAC_S != AUTS[6:14]:
         self._log('WNG', '[synch_sqn] IMSI %s, USIM authentication failure' % IMSI)
         return 1
     #
     # resynchronize local SQN value
     K_ALG_SQN_OP[2] = SQN_MSi + self.SQN_SYNCH_STEP
     self._save_required = True
     self._log('DBG', '[synch_sqn] IMSI %s, SQN resynchronized to %i' % (IMSI, K_ALG_SQN_OP[2]))
     return 0
예제 #6
0
 def make_5g_vector(self, IMSI, SNName, AMF=b'\x80\x00', RAND=None):
     """
     return a 5G authentication vector "quadruplet":
     RAND [16 bytes], XRES* [8 bytes], AUTN [16 bytes], KAUSF [32 bytes]
     or None if the IMSI is not defined in the db or does not support Milenage or TUAK
     or SNName is invalid or not allowed
     
     SNName is the serving network name, ascii-encoded bytes buffer
     RAND can be passed as argument
     """
     if not isinstance(SNName, bytes_types) or not 32 <= len(SNName) <= 255:
         self._log('WNG', '[make_5g_vector] SNName invalid, %s' % SNName.decode('ascii'))
         return None
     elif self.PLMN_FILTER is not None:
         # extract MCC, MNC from SNName (e.g. "5G:mnc012.mcc345.3gppnetwork.org")
         snname_parts = SNName.split(':')[1].split('.')
         mcc, mnc =  snname_parts[1][3:], snname_parts[0][3:]
         if mcc + mnc not in self.PLMN_FILTER:
             self._log('WNG', '[make_5g_vector] SNName not allowed, %s' % SNName.decode('ascii'))
             return None
     #
     # lookup db for authentication Key and counter for IMSI
     try:
         K_ALG_SQN_OP = self.db[IMSI]
     except Exception:
         self._log('WNG', '[make_5g_vector] IMSI %s not present in AuC.db' % IMSI)
         return None
     if len(K_ALG_SQN_OP) == 4:
         K, ALG, SQN, OP = K_ALG_SQN_OP
     else:
         K, ALG, SQN = K_ALG_SQN_OP
         OP = None
     #
     if ALG not in (0, 4):
         # Milenage / TUAK not supported
         self._log('WNG', '[make_4g_vector] IMSI %s does not support Milenage or TUAK' % IMSI)
         return None
     #
     # increment SQN counter in the db
     if SQN >= 0:
         K_ALG_SQN_OP[2] += 1
         self._save_required = True
     #
     # pack SQN from integer to a 48-bit buffer
     SQNb = pack('>Q', SQN)[2:]
     #
     # generate challenge
     if RAND is None:
         RAND = genrand(16)
     #
     if ALG == 0:
         # compute Milenage functions
         if OP is not None:
             XRES, CK, IK, AK = self.Milenage.f2345( K, RAND, OP )
             MAC_A            = self.Milenage.f1( K, RAND, SQNb, AMF, OP )
         else:
             XRES, CK, IK, AK = self.Milenage.f2345( K, RAND )
             MAC_A            = self.Milenage.f1( K, RAND, SQNb, AMF )
     else:
         # ALG == 4, compute TUAK functions
         if OP is not None:
             XRES, CK, IK, AK = self.TUAK.f2345( K, RAND, OP )
             MAC_A            = self.TUAK.f1( K, RAND, SQNb, AMF, OP )
         else:
             XRES, CK, IK, AK = self.TUAK.f2345( K, RAND )
             MAC_A            = self.TUAK.f1( K, RAND, SQNb, AMF )
     #
     SQN_X_AK = xor_buf( SQNb, AK )
     AUTN = SQN_X_AK + AMF + MAC_A
     # convert to AUSF master key
     KAUSF = conv_501_A2(CK, IK, SNName, SQN_X_AK)
     XRESstar = conv_501_A4(CK, IK, SNName, RAND, XRES)
     #
     # return auth vector
     self._log('DBG', '[make_4g_vector] IMSI %s, SQN %i, SNName %s: RAND %s, XRES* %s, AUTN %s, KASME %s'\
               % (IMSI, SQN, hexlify(SNName).decode('ascii'), hexlify(RAND).decode('ascii'), 
                  hexlify(XRESstar).decode('ascii'), hexlify(AUTN).decode('ascii'), 
                  hexlify(KAUSF).decode('ascii')))
     return RAND, XRESstar, AUTN, KAUSF
예제 #7
0
 def make_4g_vector(self, IMSI, SN_ID, AMF=b'\x80\x00', RAND=None):
     """
     return a 4G authentication vector "quadruplet":
     RAND [16 bytes], XRES [8 bytes], AUTN [16 bytes], KASME [32 bytes]
     or None if the IMSI is not defined in the db or does not support Milenage or TUAK
     or SN_ID is invalid or not allowed
     
     SN_ID is the serving network identity, bcd-encoded buffer
     RAND can be passed as argument
     """
     if not isinstance(SN_ID, bytes_types) or len(SN_ID) != 3:
         self._log('WNG', '[make_4g_vector] SN_ID invalid, %s' % hexlify(SN_ID).decode('ascii'))
         return None
     elif self.PLMN_FILTER is not None and SN_ID not in self.PLMN_FILTER:
         self._log('WNG', '[make_4g_vector] SN_ID not allowed, %s' % hexlify(SN_ID).decode('ascii'))
         return None
     #
     # lookup db for authentication Key and counter for IMSI
     try:
         K_ALG_SQN_OP = self.db[IMSI]
     except Exception:
         self._log('WNG', '[make_4g_vector] IMSI %s not present in AuC.db' % IMSI)
         return None
     if len(K_ALG_SQN_OP) == 4:
         K, ALG, SQN, OP = K_ALG_SQN_OP
     else:
         K, ALG, SQN = K_ALG_SQN_OP
         OP = None
     #
     if ALG not in (0, 4):
         # Milenage / TUAK not supported
         self._log('WNG', '[make_4g_vector] IMSI %s does not support Milenage or TUAK' % IMSI)
         return None
     #
     # increment SQN counter in the db
     if SQN >= 0:
         K_ALG_SQN_OP[2] += 1
         self._save_required = True
     #
     # pack SQN from integer to a 48-bit buffer
     SQNb = pack('>Q', SQN)[2:]
     #
     # generate challenge
     if RAND is None:
         RAND = genrand(16)
     #
     if ALG == 0:
         # compute Milenage functions
         if OP is not None:
             XRES, CK, IK, AK = self.Milenage.f2345( K, RAND, OP )
             MAC_A            = self.Milenage.f1( K, RAND, SQNb, AMF, OP )
         else:
             XRES, CK, IK, AK = self.Milenage.f2345( K, RAND )
             MAC_A            = self.Milenage.f1( K, RAND, SQNb, AMF )
     else:
         # ALG == 4, compute TUAK functions
         if OP is not None:
             XRES, CK, IK, AK = self.TUAK.f2345( K, RAND, OP )
             MAC_A            = self.TUAK.f1( K, RAND, SQNb, AMF, OP )
         else:
             XRES, CK, IK, AK = self.TUAK.f2345( K, RAND )
             MAC_A            = self.TUAK.f1( K, RAND, SQNb, AMF )
     #
     SQN_X_AK = xor_buf( SQNb, AK )
     AUTN = SQN_X_AK + AMF + MAC_A
     # convert to LTE master key
     KASME = conv_401_A2(CK, IK, SN_ID, SQN_X_AK)
     #
     # return auth vector
     self._log('DBG', '[make_4g_vector] IMSI %s, SQN %i, SN_ID %s: RAND %s, XRES %s, AUTN %s, KASME %s'\
               % (IMSI, SQN, hexlify(SN_ID).decode('ascii'), hexlify(RAND).decode('ascii'), 
                  hexlify(XRES).decode('ascii'), hexlify(AUTN).decode('ascii'), 
                  hexlify(KASME).decode('ascii')))
     return RAND, XRES, AUTN, KASME
예제 #8
0
 def make_3g_vector(self, IMSI, AMF=b'\0\0', RAND=None):
     '''
     return a 3G authentication vector "quintuplet":
     RAND [16 bytes], XRES [8 bytes], AUTN [16 bytes], CK [16 bytes], IK [16 bytes]
     or None if the IMSI is not defined in the db or does not support Milenage or TUAK
     
     RAND can be passed as argument
     '''
     # lookup db for authentication Key and counter for IMSI
     try:
         K_ALG_SQN_OP = self.db[IMSI]
     except Exception:
         self._log('WNG', '[make_3g_vector] IMSI %s not present in AuC.db' % IMSI)
         return None
     if len(K_ALG_SQN_OP) == 4:
         K, ALG, SQN, OP = K_ALG_SQN_OP
     else:
         K, ALG, SQN = K_ALG_SQN_OP
         OP = None
     #
     if SQN == -1:
         # Milenage / TUAK not supported
         self._log('WNG', '[make_3g_vector] IMSI %s does not support Milenage / TUAK' % IMSI)
         return None
     #
     # increment SQN counter in the db
     K_ALG_SQN_OP[2] += 1
     self._save_required = True
     #
     # pack SQN from integer to a 48-bit buffer
     SQNb = pack('>Q', SQN)[2:]
     #
     # generate challenge if necessary
     if RAND is None:
         RAND = genrand(16)
     #
     if ALG == 0:
         # compute Milenage functions
         if OP is not None:
             XRES, CK, IK, AK = self.Milenage.f2345( K, RAND, OP )
             MAC_A            = self.Milenage.f1( K, RAND, SQNb, AMF, OP )
         else:
             XRES, CK, IK, AK = self.Milenage.f2345( K, RAND )
             MAC_A            = self.Milenage.f1( K, RAND, SQNb, AMF )
     elif ALG == 4:
         # compute TUAK functions
         if OP is not None:
             XRES, CK, IK, AK = self.TUAK.f2345( K, RAND, OP )
             MAC_A            = self.TUAK.f1( K, RAND, SQNb, AMF, OP )
         else:
             XRES, CK, IK, AK = self.TUAK.f2345( K, RAND )
             MAC_A            = self.TUAK.f1( K, RAND, SQNb, AMF )
     else:
         # invalid ALG
         return None
     #
     AUTN = xor_buf( SQNb, AK ) + AMF + MAC_A
     #
     # return auth vector
     self._log('DBG', '[make_3g_vector] IMSI %s, SQN %i: RAND %s, XRES %s, AUTN %s, CK %s, IK %s'\
               % (IMSI, SQN, hexlify(RAND).decode('ascii'), hexlify(XRES).decode('ascii'),
                  hexlify(AUTN).decode('ascii'), hexlify(CK).decode('ascii'), 
                  hexlify(IK).decode('ascii')))
     return RAND, XRES, AUTN, CK, IK