def runTest(self): key = b"0" * 16 data = b"\x00\x01\x02" # Data and key can be a bytearray (during initialization) key_ba = bytearray(key) data_ba = bytearray(data) h1 = CMAC.new(key, data, ciphermod=AES) h2 = CMAC.new(key_ba, data_ba, ciphermod=AES) key_ba[:1] = b'\xFF' data_ba[:1] = b'\xFF' self.assertEqual(h1.digest(), h2.digest()) # Data can be a bytearray (during operation) key_ba = bytearray(key) data_ba = bytearray(data) h1 = CMAC.new(key, ciphermod=AES) h2 = CMAC.new(key, ciphermod=AES) h1.update(data) h2.update(data_ba) data_ba[:1] = b'\xFF' self.assertEqual(h1.digest(), h2.digest())
def calculate_sdmmac(sdm_file_read_key: bytes, picc_data: bytes, enc_file_data: Optional[bytes] = None) -> bytes: """ Calculate SDMMAC for NTAG 424 DNA :param sdm_file_read_key: MAC calculation key (K_SDMFileReadKey) :param picc_data: [ UID ][ SDMReadCtr ] :param enc_file_data: SDMEncFileData (if used) :return: calculated SDMMAC (8 bytes) """ sv2stream = io.BytesIO() sv2stream.write(b"\x3C\xC3\x00\x01\x00\x80") sv2stream.write(picc_data) while sv2stream.getbuffer().nbytes % AES.block_size != 0: # zero padding till the end of the block sv2stream.write(b"\x00") c2 = CMAC.new(sdm_file_read_key, ciphermod=AES) c2.update(sv2stream.getvalue()) sdmmac = CMAC.new(c2.digest(), ciphermod=AES) if enc_file_data: sdmmac_param_text = "&{}=".format(config.SDMMAC_PARAM) if not config.SDMMAC_PARAM: sdmmac_param_text = "" sdmmac.update(enc_file_data.hex().upper().encode('ascii') + sdmmac_param_text.encode('ascii')) return bytes( bytearray([sdmmac.digest()[i] for i in range(16) if i % 2 == 1]))
def kirk1_encrypt_cmac(data, salt=b'', aes_key=None, cmac_key=None): if aes_key is None: aes_key = Random.get_random_bytes(16) if cmac_key is None: cmac_key = Random.get_random_bytes(16) # pad to 16 byte boundary if required padding = b'' if len(data) % 16: for i in range(15, len(data) % 16-1, -1): padding += bytes([i << 4 | i]) # encrypt the data aes = AES.new(aes_key, AES.MODE_CBC, iv=b'\x00'*16) enc_data = aes.encrypt(data + padding) # cmac the header header = struct.pack('<II8xII8x16x', 1, 0, len(data), len(salt)) cmac = CMAC.new(cmac_key, ciphermod=AES) cmac.update(header) header_mac = cmac.digest() # cmac the data block = header + salt + enc_data cmac = CMAC.new(cmac_key, ciphermod=AES) cmac.update(block) data_mac = cmac.digest() # encrypt keys and return result k1_aes = AES.new(bytes.fromhex(_k1_key), AES.MODE_CBC, iv=b'\x00'*16) return k1_aes.encrypt(aes_key + cmac_key) + header_mac + data_mac + b'\x00'*0x20 + block
def _verify_cmac(key, block, size, offset): cobj = CMAC.new(key, ciphermod=AES) cobj.update(block[0x60:0x60+0x30]) cobj.verify(block[0x20:0x30]) cobj = CMAC.new(key, ciphermod=AES) cobj.update(block[0x60:0x90+size+offset]) cobj.verify(block[0x30:0x40])
def runTest(self): key = b"0" * 16 data = b"\x00\x01\x02" def get_mv_ro(data): return memoryview(data) def get_mv_rw(data): return memoryview(bytearray(data)) for get_mv in (get_mv_ro, get_mv_rw): # Data and key can be a memoryview (during initialization) key_mv = get_mv(key) data_mv = get_mv(data) h1 = CMAC.new(key, data, ciphermod=AES) h2 = CMAC.new(key_mv, data_mv, ciphermod=AES) if not data_mv.readonly: key_mv[:1] = b'\xFF' data_mv[:1] = b'\xFF' self.assertEqual(h1.digest(), h2.digest()) # Data can be a memoryview (during operation) data_mv = get_mv(data) h1 = CMAC.new(key, ciphermod=AES) h2 = CMAC.new(key, ciphermod=AES) h1.update(data) h2.update(data_mv) if not data_mv.readonly: data_mv[:1] = b'\xFF' self.assertEqual(h1.digest(), h2.digest())
def main(argc, argv): with open(sys.argv[1], 'rb') as f: data = f.read() data1 = data[0x4E0:0x500] data2 = data[0x500:0x520] data3 = data[0x520:0x540] data4 = data[0x540:0x560] eid1 = data[0x10:0x290] hash = data[0x290:0x2A0] cmac1= CMAC.new(uhx(EID1KEYS[0]), ciphermod=AES) cmac1.update(eid1) print(hx(hash)) print(cmac1.hexdigest()) sexy = aes_decrypt_cbc(uhx(EID1KEYS[0]), uhx(ZEROS128[0]), eid1) keyseed = sexy[0x150:0x160] pck1 = aes_encrypt_cbc(uhx(TIMEKEYS[0]), uhx(ZEROS128[0]), keyseed) pck2 = aes_encrypt_cbc(uhx(TIMEKEYS[1]), uhx(ZEROS128[0]), keyseed) pck3 = aes_encrypt_cbc(uhx(TIMEKEYS[2]), uhx(ZEROS128[0]), keyseed) pck4 = aes_encrypt_cbc(uhx(TIMEKEYS[3]), uhx(ZEROS128[0]), keyseed) data1_stage1 = aes_decrypt_ecb(pck1,data1) data1_body = data1_stage1[:0x10] data1_stage2 = aes_decrypt_ecb(uhx(TIMEFINALS[0]),data1_stage1)[:0x10] data1_omac = data1_stage1[0x10:] cmac2= CMAC.new(uhx(TIMEFINALS[0]), ciphermod=AES) cmac2.update(data1_body) print(hx(data1_omac)) print(cmac2.hexdigest()) with open(sys.argv[1] + '.eid1.dec.bin', 'wb') as g: g.write(sexy) with open(sys.argv[1] + '.time1.dec.bin', 'wb') as g: g.write(data1_stage2)
def CKDFMEIExpand(NoncePRK): constant = b"\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88" cobj = CMAC.new(NoncePRK, ciphermod=AES) cobj.update(constant + b"\x00" + constant + b"\x01") T1 = cobj.hexdigest() cobj = CMAC.new(NoncePRK, ciphermod=AES) cobj.update(T1.decode("hex") + constant + b"\x02") T2 = cobj.hexdigest() return (T1 + T2).decode("hex")
def k2(n, p): salt = s1(b'smk2') t = CMAC.new(salt, ciphermod=AES).update(n).digest() t0 = b'' t1 = CMAC.new(t, ciphermod=AES).update(t0 + p + b'\x01').digest() t2 = CMAC.new(t, ciphermod=AES).update(t1 + p + b'\x02').digest() t3 = CMAC.new(t, ciphermod=AES).update(t2 + p + b'\x03').digest() result = bytearray((t1 + t2 + t3)[-33:]) result[0] = result[0] & 0x7F return bytes(result)
def part2(self, part2_resp: bytes) -> 'CryptoComm': """ Validate final R-APDU and create secure messaging object :param part2_resp: final R-APDU :return: CryptoComm object """ require("R-APDU length", len(part2_resp) == 34) require("status code 9100", part2_resp[-2:] == b"\x91\x00") enc = part2_resp[:32] cipher = AES.new(self.auth_key, AES.MODE_CBC, IV=b"\x00" * 16) resp = cipher.decrypt(enc) resp_s = io.BytesIO(resp) ti = resp_s.read(4) rnda_p = resp_s.read(16) pdcap2 = resp_s.read(6) pcdcap2 = resp_s.read(6) recv_rnda = byte_rot_right(rnda_p) require("generated RndA == decrypted RndA", recv_rnda == self.rnda) stream = io.BytesIO() # they are counting from right to left :D stream.write(self.rnda[0:2]) # [RndA[15:14] stream.write(strxor(self.rnda[2:8], self.rndb[0:6])) # [ (RndA[13:8] ⊕ RndB[15:10]) ] stream.write(self.rndb[-10:]) # [RndB[9:0] stream.write(self.rnda[-8:]) # RndA[7:0] # just took me an hour or two to brute force it from the examples sv1stream = io.BytesIO() sv1stream.write(b"\xA5\x5A\x00\x01\x00\x80") sv1stream.write(stream.getvalue()) sv1 = sv1stream.getvalue() sv2stream = io.BytesIO() sv2stream.write(b"\x5A\xA5\x00\x01\x00\x80") sv2stream.write(stream.getvalue()) sv2 = sv2stream.getvalue() c = CMAC.new(self.auth_key, ciphermod=AES) c.update(sv1) k_ses_auth_enc = c.digest() c = CMAC.new(self.auth_key, ciphermod=AES) c.update(sv2) k_ses_auth_mac = c.digest() return CryptoComm(k_ses_auth_mac, k_ses_auth_enc, ti=ti, pdcap2=pdcap2, pcdcap2=pcdcap2)
def CKDFTempExpand(key): constant = b"\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88" cobj = CMAC.new(key, ciphermod=AES) cobj.update(constant + b"\x01") TempKeyCCM = cobj.hexdigest() cobj = CMAC.new(key, ciphermod=AES) cobj.update(TempKeyCCM.decode("hex") + constant + b"\x02") T2 = cobj.hexdigest() cobj = CMAC.new(key, ciphermod=AES) cobj.update(T2.decode("hex") + constant + b"\x03") T3 = cobj.hexdigest() temp_personalisation_string = T1 + T2 return (TempKeyCCM.decode("hex"), (temp_personalisation_string).decode("hex"))
def decrypt_btl(data: bytes, *args, **kwargs) -> bytes: assert (isinstance(data, bytes)) assert (len(data) == 0x1c000) stream: io.BytesIO = io.BytesIO(data) encrypted: bytes = stream.read(0x1bfd0) footer: io.BytesIO = io.BytesIO(stream.read(0x30)) iv: bytes = footer.read(0x10) seed: bytes = footer.read(0x10) cmac: bytes = footer.read(0x10) context: tuple = struct.unpack_from('<IIII', footer.getvalue(), 0x10) random: Random = Random(*context) key: bytes = crypto.create_key(random, keytables.btl, 0x10) aes: _mode_cbc.CbcMode = AES.new(key, AES.MODE_CBC, iv) decrypted: bytes = aes.decrypt(encrypted) key: bytes = crypto.create_key(random, keytables.btl, 0x10) mac: CMAC.CMAC = CMAC.new(key, ciphermod=AES) mac.update(decrypted) mac.verify(cmac) return decrypted
def encrypt_bcd(data: bytes, *args, **kwargs) -> bytes: assert (isinstance(data, bytes)) assert (len(data) == 0x5bfc0) stream: io.BytesIO = io.BytesIO(data) header: io.BytesIO = io.BytesIO() decrypted: bytes = stream.read(0x5bfc0) header.write( struct.pack('<I', 0x1) + struct.pack('<H', 0x10) + struct.pack('<H', 0x0) + struct.pack('<I', zlib.crc32(decrypted)) + 'SCDL'.encode('utf-8')) seed: bytes = get_random_bytes(0x10) context: tuple = struct.unpack_from('<IIII', seed) random: Random = Random(*context) key: bytes = crypto.create_key(random, keytables.bcd, 0x10) aes: _mode_cbc.CbcMode = AES.new(key, AES.MODE_CBC, get_random_bytes(0x10)) encrypted: bytes = aes.encrypt(decrypted) key: bytes = crypto.create_key(random, keytables.bcd, 0x10) mac: CMAC.CMAC = CMAC.new(key, ciphermod=AES) mac.update(decrypted) return header.getvalue() + encrypted + aes.iv + seed + mac.digest()
def encrypt(self): self.stream = streams.StreamIn(self.data) self.header = streams.StreamOut() self.decrypted = self.stream.read(0x5BFC0) self.header.write(struct.pack("<I", 0x1)) self.header.write(struct.pack("<H", 0x10)) self.header.write(struct.pack("<H", 0x0)) self.header.write(struct.pack("<I", zlib.crc32(self.decrypted))) self.header.write("SCDL".encode("utf-8")) self.randomState = Random.get_random_bytes(0x10) self.context = struct.unpack("<IIII", self.randomState) self.rand = random.Random(*self.context) self.key = crypto.create_key(self.rand, keytables.course, 0x10) self.aes = AES.new(self.key, AES.MODE_CBC, Random.get_random_bytes(0x10)) self.encrypted = self.aes.encrypt(self.decrypted) self.key = crypto.create_key(self.rand, keytables.course, 0x10) self.mac = CMAC.new(self.key, ciphermod=AES) self.mac.update(self.decrypted) self.mac.digest() self.data = self.header.data( ) + self.encrypted + self.aes.iv + self.randomState + self.mac.digest( ) return None
def compute_mac(key: bytes, data: bytes, alg: str) -> bytes: """ Calculate message authentication code (mac) of data using key according to IEC_9797-1 MAC algorithm 3 https://en.wikipedia.org/wiki/ISO/IEC_9797-1 MAC algorithm 3\n http://www.devinvenable.com/mediawiki/index.php/ISO_9797_algorithm_3 key -- DES key to compute the mac with, 16 bytes data -- data to calculate the mac of alg -- which algorithm to use for mac (choices "DES", "AES-CMAC") :returns: mac of data """ if alg == "DES": m_cipher1 = DES.new(key[:8], DES.MODE_ECB) m_cipher2 = DES.new(key[-8:], DES.MODE_ECB) h = m_cipher1.encrypt(data[:8]) for i in range(1, len(data) // 8): h = m_cipher1.encrypt(strxor(h, data[8 * i:8 * (i + 1)])) mac_x = m_cipher1.encrypt(m_cipher2.decrypt(h)) return mac_x elif alg == "AES-CMAC": mac_x = CMAC.new(key, ciphermod=AES, msg=data, mac_len=8).digest() return mac_x else: raise ValueError("[-] Unsupported MAC algorithm")
def test_calcmic(): joinreqtype = b'\x00' joineui = b'\xa0\x00\x00\x00\x00\x00\x00\x00' deveui = b'\xd0\x00\x00\x00\x00\x00\x00\x00' # 0c00000000005bdfb3018001184f84e85684b85e84886684586e84004cc63b75 # 4cc63b75 nwkKey = bytes.fromhex('ee000000000000000000000000000000') jsintkeymsg = b'\x06' + deveui[::-1] + b'\x00\x00\x00\x00\x00\x00\x00' assert len(jsintkeymsg) == 16 cryptor = AES.new(nwkKey, AES.MODE_ECB) jsintkey = cryptor.encrypt(jsintkeymsg) devnonce = struct.pack('<H', 14) mhdr = b'\x20' joinnonce = b'\x00\x00\x0c' netid = b'\x00\x00\x00' #devaddr = b'\x01\x87\x34\x23' devaddr = b'\x01\xb3\xdf\x5b' dlsettings = b'\x80' rxdelay = b'\x01' cflist = bytes.fromhex('184f84e85684b85e84886684586e8400') msg = joinreqtype +\ joineui[::-1] +\ devnonce[::-1]+\ mhdr+\ joinnonce[::-1]+\ netid[::-1]+\ devaddr[::-1]+\ dlsettings+\ rxdelay+\ cflist print(msg.hex()) cobj = CMAC.new(jsintkey, ciphermod=AES) cobj.update(msg) rmic = bytes.fromhex('4cc63b75') print(rmic.hex(), cobj.digest()[:4].hex())
def CKDFTempExtract(secret, pub_a, pub_b): # Constant serves as CMAC key constant = b"\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33" cobj = CMAC.new(constant, ciphermod=AES) cobj.update(secret + pub_a + pub_b) out = cobj.hexdigest() return out.decode("hex")
def decrypt(self): self.stream = streams.StreamIn(self.data) self.header = self.stream.substream(0x10) self.encrypted = self.stream.read(0x5BFC0) self.cryptoConfig = self.stream.substream(0x30) self.header.skip(0x4) self.filetype = self.header.read(0x2) self.header.skip(0x2) self.crc32 = self.header.read(0x4) self.magic = self.header.read(0x4) self.iv = self.cryptoConfig.read(0x10) self.randomState = self.cryptoConfig.read(0x10) self.cmac = self.cryptoConfig.read(0x10) self.context = struct.unpack_from("<IIII", self.cryptoConfig.data, 0x10) self.rand = random.Random(*self.context) self.key = crypto.create_key(self.rand, keytables.course, 0x10) self.aes = AES.new(self.key, AES.MODE_CBC, self.iv) self.decrypted = self.aes.decrypt(self.encrypted) self.key = crypto.create_key(self.rand, keytables.course, 0x10) self.mac = CMAC.new(self.key, ciphermod=AES) self.mac.update(self.decrypted) self.mac.verify(self.cmac) self.data = self.decrypted return None
def getContentKey(self, lic_request_data): license = license_protocol_pb2.License() requestMessage = license_protocol_pb2.SignedMessage() responseMessage = license_protocol_pb2.SignedMessage() resp = requests.post(self.license_url, lic_request_data, headers=self.header, proxies=self.proxies) requestMessage.ParseFromString(lic_request_data) responseMessage.ParseFromString(resp.content) pubkey = RSA.importKey(self.pub_key) verifier = pss.new(pubkey) h = SHA1.new(requestMessage.msg) verifier.verify(h, requestMessage.signature) session_key = responseMessage.session_key license.ParseFromString(responseMessage.msg) rsakey = RSA.importKey(self.private_key) cipher = PKCS1_OAEP.new(rsakey) sessionKey = cipher.decrypt(session_key) context_enc = '\x01' + 'ENCRYPTION' + '\x00' + requestMessage.msg + '\x00' * 3 + chr( 128) cobj = CMAC.new(sessionKey, ciphermod=AES) encryptKey = cobj.update(context_enc).digest() k = license.key[1] keyId = k.id.encode('hex') keyData = k.key[0:16] keyIv = k.iv[0:16] mode = AES.MODE_CBC cryptos = AES.new(encryptKey, mode, keyIv) dkey = cryptos.decrypt(keyData) print "KID:", keyId, "KEY:", dkey.encode('hex')
def mic_cal(key, micField): fmt = '>s8s8s2s' msg = struct.pack(fmt, micField['MHDR'], micField['AppEUI'], micField['DevEUI'], micField['DevNonce']) cobj = CMAC.new(bytearray.fromhex(key), ciphermod=AES) cobj.update(msg) return cobj.hexdigest()[:8]
def TestOneInput(data): fdp = atheris.FuzzedDataProvider(data) hashes = [ SHA224, SHA256, SHA384, SHA512, MD2, MD4, MD5, RIPEMD160 ] for f in hashes: h = f.new() h.update(data) h.digest h = HMAC.new(fdp.ConsumeBytes(9)) h.update(data) h.digest try: cobj = CMAC.new(fdp.ConsumeBytes(16), ciphermod=AES) cobj.update(data) except ValueError as e: if "Key cannot be the null string" not in str(e): raise e
def update(self, item): """Pass the next component of the vector. The maximum number of components you can pass is equal to the block length of the cipher (in bits) minus 1. :Parameters: item : byte string The next component of the vector. :Raise TypeError: when the limit on the number of components has been reached. :Raise ValueError: when the component is empty """ if not item: raise ValueError("A component cannot be empty") if self._n_updates==0: raise TypeError("Too many components passed to S2V") self._n_updates -= 1 mac = CMAC.new(self._key, msg=self._last_string, ciphermod=self._ciphermod, cipher_params=self._cipher_params) self._cache = strxor(self._double(self._cache), mac.digest()) self._last_string = item
def runTest(self): data_to_mac = get_tag_random("data_to_mac", 128) key = get_tag_random("key", 16) ref_mac = CMAC.new(key, msg=data_to_mac, ciphermod=AES).digest() # Break up in chunks of different length # The result must always be the same for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: chunks = [data_to_mac[i : i + chunk_length] for i in range(0, len(data_to_mac), chunk_length)] mac = CMAC.new(key, ciphermod=AES) for chunk in chunks: mac.update(chunk) self.assertEqual(ref_mac, mac.digest())
def decrypt_file_data(sdm_file_read_key: bytes, picc_data: bytes, read_ctr: bytes, enc_file_data: bytes) -> bytes: """ Decrypt SDMEncFileData for NTAG 424 DNA :param sdm_file_read_key: SUN decryption key (K_SDMFileReadKey) :param picc_data: PICCDataTag [ || UID ][ || SDMReadCtr ]] :param read_ctr: SDMReadCtr :param enc_file_data: SDMEncFileData :return: decrypted file data (bytes) """ sv1stream = io.BytesIO() sv1stream.write(b"\xC3\x3C\x00\x01\x00\x80") sv1stream.write(picc_data) while sv1stream.getbuffer().nbytes % AES.block_size != 0: # zero padding till the end of the block sv1stream.write(b"\x00") cm = CMAC.new(sdm_file_read_key, ciphermod=AES) cm.update(sv1stream.getvalue()) k_ses_sdm_file_read_enc = cm.digest() ive = AES.new(k_ses_sdm_file_read_enc, AES.MODE_ECB) \ .encrypt(read_ctr + b"\x00" * 13) # in datasheet it is written that KSDMMetaReadKey should be used, # but actually seems to be KSesSDMFileReadENC return AES.new(k_ses_sdm_file_read_enc, AES.MODE_CBC, IV=ive) \ .decrypt(enc_file_data)
def _start_eax(self, factory, key, *args, **kwargs): self.nonce = _getParameter('nonce', 1, args, kwargs) if not self.nonce: raise TypeError("MODE_EAX requires a nonce") # Allowed transitions after initialization self._next = [self.update, self.encrypt, self.decrypt, self.digest, self.verify] self._mac_len = kwargs.get('mac_len', self.block_size) if not (self._mac_len and 4 <= self._mac_len <= self.block_size): raise ValueError("Parameter 'mac_len' must not be larger than %d" % self.block_size) self._omac = [ CMAC.new(key, bchr(0) * (self.block_size - 1) + bchr(i), ciphermod=factory) for i in xrange(0, 3) ] # Compute MAC of nonce self._omac[0].update(self.nonce) self._cipherMAC = self._omac[1] # MAC of the nonce is also the initial counter for CTR encryption counter_int = bytes_to_long(self._omac[0].digest()) counter_obj = Crypto.Util.Counter.new( self.block_size * 8, initial_value=counter_int, allow_wraparound=True) self._cipher = factory.new(key, MODE_CTR, counter=counter_obj)
def _start_eax(self, factory, key, *args, **kwargs): self.nonce = _getParameter('nonce', 1, args, kwargs) if not self.nonce: raise TypeError("MODE_EAX requires a nonce") # Allowed transitions after initialization self._next = [ self.update, self.encrypt, self.decrypt, self.digest, self.verify ] self._mac_len = kwargs.get('mac_len', self.block_size) if not (self._mac_len and 4 <= self._mac_len <= self.block_size): raise ValueError("Parameter 'mac_len' must not be larger than %d" % self.block_size) self._omac = [ CMAC.new(key, bchr(0) * (self.block_size - 1) + bchr(i), ciphermod=factory) for i in xrange(0, 3) ] # Compute MAC of nonce self._omac[0].update(self.nonce) self._cipherMAC = self._omac[1] # MAC of the nonce is also the initial counter for CTR encryption counter_int = bytes_to_long(self._omac[0].digest()) counter_obj = Crypto.Util.Counter.new(self.block_size * 8, initial_value=counter_int, allow_wraparound=True) self._cipher = factory.new(key, MODE_CTR, counter=counter_obj)
def checkMIC(NwSKey, devAddr, packet): if packet["Type"] != "Uplink": #only deal with uplinks for now return False #calculate the MIC and compare to the payload of the packet # Msg = MHDR | FHDR | FPort | FRMPayload #B0 = (0x49 | 4*0x00 | Dir | DevAddr | FCntUp or FCntDown | 0x00 | len(msg) ) #mac = aes128_cmac(NwkSKey, B0 | msg) #MIC = mac[0..3] #Dir=0 for uplink, 1 for downlink #assuming uplink packets only for now. #devAddr needs to be little-endian #FCNT needs to be 4 bytes - add 2 bytes of 00s to assume 32 bits. May also need to be Little Endian? need to insert fcnt manually again # print packet["FullPayload"] # print packet["FullPayload"][:-8] msg = packet["FullPayload"][:-8].decode( "hex" ) #changed to -9 as was giving an error, though - worked before... some sort of off by one only triggered when fcnt!=0? # print "FCnt="+packet["FCnt"] #fcnt needs to be little-endian - and possibly guess MSBs! take off two of those following \x00s and update the decryption method too! B = '\x49\x00\x00\x00\x00\x00' + devAddr.decode( "hex") + packet["FCnt"][2:4].decode( "hex") + packet["FCnt"][0:2].decode("hex") + "\x00\x00\x00" + chr( len(msg)) msg = B + msg # print msg.encode("hex") cobj = CMAC.new(NwSKey.decode("hex"), ciphermod=AES) cobj.update(msg) MICcalc = cobj.hexdigest() # print MICcalc[0:8] # print packet["MIC"] if MICcalc[0:8].lower() == packet["MIC"].lower(): return True # print MICcalc[0:8].lower() +"!="+ packet["MIC"].lower() return False
def test_update_after_digest(self): msg = b"rrrrttt" key = b"4" * 16 # Normally, update() cannot be done after digest() h = CMAC.new(key, msg[:4], ciphermod=AES) dig1 = h.digest() self.assertRaises(TypeError, h.update, msg[4:]) dig2 = CMAC.new(key, msg, ciphermod=AES).digest() # With the proper flag, it is allowed h2 = CMAC.new(key, msg[:4], ciphermod=AES, update_after_digest=True) self.assertEquals(h2.digest(), dig1) # ... and the subsequent digest applies to the entire message # up to that point h2.update(msg[4:]) self.assertEquals(h2.digest(), dig2)
def derive(self): if len(self._last_string) >= 16: final = self._last_string[:-16] + strxor(self._last_string[-16:], self._cache) else: padded = (self._last_string + bchr(128) + bchr(0) * 15)[:16] final = strxor(padded, self._double(self._cache)) mac = CMAC.new(self._key, msg=final, ciphermod=self._ciphermod) return mac.digest()
def s1(m): if isinstance(m, str): m = bytes.fromhex(str) elif isinstance(m, bytearray): m = bytes(m) cipher = CMAC.new(bytes(16), ciphermod=AES).update(m) return cipher.digest()
def aes_cmac_verify(key, plain, compare): ctx = CMAC.new(key, ciphermod=AES) ctx.update(plain) result = ctx.hexdigest() if result != compare: print("AES-CMAC failed !") else: print("AES-CMAC ok !")
def verify_cmac(key, msg, digest): cmac = CMAC.new(key, ciphermod=AES) cmac.update(msg) try: cmac.verify(digest) return True except ValueError: return False
def runTest(self): data_to_mac = get_tag_random("data_to_mac", 128) key = get_tag_random("key", 16) ref_mac = CMAC.new(key, msg=data_to_mac, ciphermod=AES).digest() # Break up in chunks of different length # The result must always be the same for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: chunks = [data_to_mac[i:i+chunk_length] for i in range(0, len(data_to_mac), chunk_length)] mac = CMAC.new(key, ciphermod=AES) for chunk in chunks: mac.update(chunk) self.assertEqual(ref_mac, mac.digest())
def test_internal_caching(self): """Verify that internal caching is implemented correctly""" data_to_mac = get_tag_random("data_to_mac", 128) key = get_tag_random("key", 16) ref_mac = CMAC.new(key, msg=data_to_mac, ciphermod=AES).digest() # Break up in chunks of different length # The result must always be the same for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: chunks = [data_to_mac[i:i+chunk_length] for i in range(0, len(data_to_mac), chunk_length)] mac = CMAC.new(key, ciphermod=AES) for chunk in chunks: mac.update(chunk) self.assertEqual(ref_mac, mac.digest())
def derive(self): """"Derive a secret from the vector of components. :Return: a byte string, as long as the block length of the cipher. """ if len(self._last_string) >= 16: final = self._last_string[:-16] + strxor(self._last_string[-16:], self._cache) else: padded = (self._last_string + bchr(128) + bchr(0) * 15)[:16] final = strxor(padded, self._double(self._cache)) mac = CMAC.new(self._key, msg=final, ciphermod=self._ciphermod) return mac.digest()
def test_create_mac(self, tv): self._id = "Wycheproof MAC creation Test #" + str(tv.id) try: tag = CMAC.new(tv.key, tv.msg, ciphermod=AES, mac_len=tv.tag_size).digest() except ValueError as e: if len(tv.key) not in (16, 24, 32) and "key length" in str(e): return raise e if tv.valid: self.assertEqual(tag, tv.tag) self.warn(tv)
def cal_mic(key, typ='normal', **kwargs): if typ == 'normal': msg = '{MHDR}{FHDR}{FPort}{FRMPayload}'.format(**kwargs) msg_bytes = bytearray.fromhex(msg) msg_length = '{:0>2x}'.format(len(msg_bytes)) B0 = DeviceOp._B0(msg_length=msg_length, **kwargs) obj_msg = B0 + msg obj_msg = bytearray.fromhex(obj_msg) else: msg = '{MHDR}{AppEUI}{DevEUI}{DevNonce}'.format(**kwargs) obj_msg = bytearray.fromhex(msg) cobj = CMAC.new(key, ciphermod=AES) cobj.update(obj_msg) return cobj.hexdigest()[:8]
def test_verify_mac(self, tv): self._id = "Wycheproof MAC verification Test #" + str(tv.id) try: mac = CMAC.new(tv.key, tv.msg, ciphermod=AES, mac_len=tv.tag_size) except ValueError as e: if len(tv.key) not in (16, 24, 32) and "key length" in str(e): return raise e try: mac.verify(tv.tag) except ValueError: assert not tv.valid else: assert tv.valid self.warn(tv)
def __init__(self, factory, key, nonce, mac_len, cipher_params): """EAX cipher mode""" self.block_size = factory.block_size """The block size of the underlying cipher, in bytes.""" self.nonce = nonce """The nonce originally used to create the object.""" self._mac_len = mac_len self._mac_tag = None # Cache for MAC tag # Allowed transitions after initialization self._next = [self.update, self.encrypt, self.decrypt, self.digest, self.verify] # MAC tag length if not (4 <= self._mac_len <= self.block_size): raise ValueError("Parameter 'mac_len' must not be larger than %d" % self.block_size) # Nonce cannot be empty and must be a byte string if len(nonce) == 0: raise ValueError("Nonce cannot be empty in EAX mode") if not byte_string(nonce): raise TypeError("Nonce must be a byte string") self._omac = [ CMAC.new(key, bchr(0) * (self.block_size - 1) + bchr(i), ciphermod=factory, cipher_params=cipher_params) for i in range(0, 3) ] # Compute MAC of nonce self._omac[0].update(nonce) self._signer = self._omac[1] # MAC of the nonce is also the initial counter for CTR encryption counter_int = bytes_to_long(self._omac[0].digest()) self._cipher = factory.new(key, factory.MODE_CTR, initial_value=counter_int, nonce=b(""), **cipher_params)
def derive(self): """"Derive a secret from the vector of components. :Return: a byte string, as long as the block length of the cipher. """ if len(self._last_string) >= 16: # xorend final = self._last_string[:-16] + strxor(self._last_string[-16:], self._cache) else: # zero-pad & xor padded = (self._last_string + b'\x80' + b'\x00' * 15)[:16] final = strxor(padded, self._double(self._cache)) mac = CMAC.new(self._key, msg=final, ciphermod=self._ciphermod, cipher_params=self._cipher_params) return mac.digest()