1*cfb92d14SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*cfb92d14SAndroid Build Coastguard Worker# 3*cfb92d14SAndroid Build Coastguard Worker# Copyright (c) 2016, The OpenThread Authors. 4*cfb92d14SAndroid Build Coastguard Worker# All rights reserved. 5*cfb92d14SAndroid Build Coastguard Worker# 6*cfb92d14SAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without 7*cfb92d14SAndroid Build Coastguard Worker# modification, are permitted provided that the following conditions are met: 8*cfb92d14SAndroid Build Coastguard Worker# 1. Redistributions of source code must retain the above copyright 9*cfb92d14SAndroid Build Coastguard Worker# notice, this list of conditions and the following disclaimer. 10*cfb92d14SAndroid Build Coastguard Worker# 2. Redistributions in binary form must reproduce the above copyright 11*cfb92d14SAndroid Build Coastguard Worker# notice, this list of conditions and the following disclaimer in the 12*cfb92d14SAndroid Build Coastguard Worker# documentation and/or other materials provided with the distribution. 13*cfb92d14SAndroid Build Coastguard Worker# 3. Neither the name of the copyright holder nor the 14*cfb92d14SAndroid Build Coastguard Worker# names of its contributors may be used to endorse or promote products 15*cfb92d14SAndroid Build Coastguard Worker# derived from this software without specific prior written permission. 16*cfb92d14SAndroid Build Coastguard Worker# 17*cfb92d14SAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18*cfb92d14SAndroid Build Coastguard Worker# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*cfb92d14SAndroid Build Coastguard Worker# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*cfb92d14SAndroid Build Coastguard Worker# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21*cfb92d14SAndroid Build Coastguard Worker# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22*cfb92d14SAndroid Build Coastguard Worker# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23*cfb92d14SAndroid Build Coastguard Worker# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24*cfb92d14SAndroid Build Coastguard Worker# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25*cfb92d14SAndroid Build Coastguard Worker# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26*cfb92d14SAndroid Build Coastguard Worker# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27*cfb92d14SAndroid Build Coastguard Worker# POSSIBILITY OF SUCH DAMAGE. 28*cfb92d14SAndroid Build Coastguard Worker# 29*cfb92d14SAndroid Build Coastguard Worker 30*cfb92d14SAndroid Build Coastguard Workerimport hmac 31*cfb92d14SAndroid Build Coastguard Workerimport hashlib 32*cfb92d14SAndroid Build Coastguard Workerimport struct 33*cfb92d14SAndroid Build Coastguard Worker 34*cfb92d14SAndroid Build Coastguard Workerfrom binascii import hexlify 35*cfb92d14SAndroid Build Coastguard Worker 36*cfb92d14SAndroid Build Coastguard Worker 37*cfb92d14SAndroid Build Coastguard Workerclass CryptoEngine: 38*cfb92d14SAndroid Build Coastguard Worker """ Class responsible for encryption and decryption of data. """ 39*cfb92d14SAndroid Build Coastguard Worker 40*cfb92d14SAndroid Build Coastguard Worker def __init__(self, crypto_material_creator): 41*cfb92d14SAndroid Build Coastguard Worker """ 42*cfb92d14SAndroid Build Coastguard Worker Args: 43*cfb92d14SAndroid Build Coastguard Worker network_key (bytearray) 44*cfb92d14SAndroid Build Coastguard Worker 45*cfb92d14SAndroid Build Coastguard Worker """ 46*cfb92d14SAndroid Build Coastguard Worker self._crypto_material_creator = crypto_material_creator 47*cfb92d14SAndroid Build Coastguard Worker 48*cfb92d14SAndroid Build Coastguard Worker @property 49*cfb92d14SAndroid Build Coastguard Worker def mic_length(self): 50*cfb92d14SAndroid Build Coastguard Worker return self._crypto_material_creator.mic_length 51*cfb92d14SAndroid Build Coastguard Worker 52*cfb92d14SAndroid Build Coastguard Worker def encrypt(self, data, message_info): 53*cfb92d14SAndroid Build Coastguard Worker """ Encrypt message. 54*cfb92d14SAndroid Build Coastguard Worker 55*cfb92d14SAndroid Build Coastguard Worker Args: 56*cfb92d14SAndroid Build Coastguard Worker data (bytearray) 57*cfb92d14SAndroid Build Coastguard Worker message_info (MessageInfo) 58*cfb92d14SAndroid Build Coastguard Worker 59*cfb92d14SAndroid Build Coastguard Worker Returns: 60*cfb92d14SAndroid Build Coastguard Worker tuple: Encrypted message (bytearray), MIC (bytearray) 61*cfb92d14SAndroid Build Coastguard Worker 62*cfb92d14SAndroid Build Coastguard Worker """ 63*cfb92d14SAndroid Build Coastguard Worker key, nonce, auth_data = self._crypto_material_creator.create_key_and_nonce_and_authenticated_data(message_info) 64*cfb92d14SAndroid Build Coastguard Worker 65*cfb92d14SAndroid Build Coastguard Worker from Crypto.Cipher import AES 66*cfb92d14SAndroid Build Coastguard Worker 67*cfb92d14SAndroid Build Coastguard Worker cipher = AES.new(key, AES.MODE_CCM, nonce, mac_len=self.mic_length) 68*cfb92d14SAndroid Build Coastguard Worker cipher.update(auth_data) 69*cfb92d14SAndroid Build Coastguard Worker 70*cfb92d14SAndroid Build Coastguard Worker return cipher.encrypt_and_digest(bytes(data)) 71*cfb92d14SAndroid Build Coastguard Worker 72*cfb92d14SAndroid Build Coastguard Worker def decrypt(self, enc_data, mic, message_info): 73*cfb92d14SAndroid Build Coastguard Worker """ Decrypt MLE message. 74*cfb92d14SAndroid Build Coastguard Worker 75*cfb92d14SAndroid Build Coastguard Worker Args: 76*cfb92d14SAndroid Build Coastguard Worker enc_data (bytearray) 77*cfb92d14SAndroid Build Coastguard Worker mic (bytearray) 78*cfb92d14SAndroid Build Coastguard Worker message_info (MessageInfo) 79*cfb92d14SAndroid Build Coastguard Worker 80*cfb92d14SAndroid Build Coastguard Worker Returns: 81*cfb92d14SAndroid Build Coastguard Worker bytearray: Decrypted message. 82*cfb92d14SAndroid Build Coastguard Worker 83*cfb92d14SAndroid Build Coastguard Worker """ 84*cfb92d14SAndroid Build Coastguard Worker key, nonce, auth_data = self._crypto_material_creator.create_key_and_nonce_and_authenticated_data(message_info) 85*cfb92d14SAndroid Build Coastguard Worker 86*cfb92d14SAndroid Build Coastguard Worker from Crypto.Cipher import AES 87*cfb92d14SAndroid Build Coastguard Worker 88*cfb92d14SAndroid Build Coastguard Worker cipher = AES.new(key, AES.MODE_CCM, nonce, mac_len=self.mic_length) 89*cfb92d14SAndroid Build Coastguard Worker cipher.update(auth_data) 90*cfb92d14SAndroid Build Coastguard Worker 91*cfb92d14SAndroid Build Coastguard Worker dec_data = cipher.decrypt_and_verify(bytes(enc_data), bytes(mic)) 92*cfb92d14SAndroid Build Coastguard Worker return bytearray(dec_data) 93*cfb92d14SAndroid Build Coastguard Worker 94*cfb92d14SAndroid Build Coastguard Worker 95*cfb92d14SAndroid Build Coastguard Workerclass CryptoMaterialCreator(object): 96*cfb92d14SAndroid Build Coastguard Worker 97*cfb92d14SAndroid Build Coastguard Worker _salt = b'Thread' 98*cfb92d14SAndroid Build Coastguard Worker 99*cfb92d14SAndroid Build Coastguard Worker def __init__(self, network_key): 100*cfb92d14SAndroid Build Coastguard Worker """ 101*cfb92d14SAndroid Build Coastguard Worker Args: 102*cfb92d14SAndroid Build Coastguard Worker network_key (bytearray) 103*cfb92d14SAndroid Build Coastguard Worker 104*cfb92d14SAndroid Build Coastguard Worker """ 105*cfb92d14SAndroid Build Coastguard Worker self.network_key = network_key 106*cfb92d14SAndroid Build Coastguard Worker 107*cfb92d14SAndroid Build Coastguard Worker def _generate_keys(self, sequence_counter): 108*cfb92d14SAndroid Build Coastguard Worker """ Generate MLE and MAC keys. 109*cfb92d14SAndroid Build Coastguard Worker 110*cfb92d14SAndroid Build Coastguard Worker Read more: 7.1.4. Key Generation - Thread v1.1 Specification Final 111*cfb92d14SAndroid Build Coastguard Worker 112*cfb92d14SAndroid Build Coastguard Worker Args: 113*cfb92d14SAndroid Build Coastguard Worker sequence_counter (int) 114*cfb92d14SAndroid Build Coastguard Worker 115*cfb92d14SAndroid Build Coastguard Worker Returns: 116*cfb92d14SAndroid Build Coastguard Worker tuple: MLE and MAC as bytes 117*cfb92d14SAndroid Build Coastguard Worker 118*cfb92d14SAndroid Build Coastguard Worker """ 119*cfb92d14SAndroid Build Coastguard Worker k = self.network_key 120*cfb92d14SAndroid Build Coastguard Worker s = struct.pack(">L", sequence_counter) + self._salt 121*cfb92d14SAndroid Build Coastguard Worker d = hmac.new(k, s, digestmod=hashlib.sha256).digest() 122*cfb92d14SAndroid Build Coastguard Worker 123*cfb92d14SAndroid Build Coastguard Worker mle = d[:16] 124*cfb92d14SAndroid Build Coastguard Worker mac = d[16:] 125*cfb92d14SAndroid Build Coastguard Worker return mle, mac 126*cfb92d14SAndroid Build Coastguard Worker 127*cfb92d14SAndroid Build Coastguard Worker def create_key_and_nonce_and_authenticated_data(self, message_info): 128*cfb92d14SAndroid Build Coastguard Worker raise NotImplementedError 129*cfb92d14SAndroid Build Coastguard Worker 130*cfb92d14SAndroid Build Coastguard Worker @property 131*cfb92d14SAndroid Build Coastguard Worker def mic_length(self): 132*cfb92d14SAndroid Build Coastguard Worker raise NotImplementedError 133*cfb92d14SAndroid Build Coastguard Worker 134*cfb92d14SAndroid Build Coastguard Worker 135*cfb92d14SAndroid Build Coastguard Workerclass MacCryptoMaterialCreator(CryptoMaterialCreator): 136*cfb92d14SAndroid Build Coastguard Worker 137*cfb92d14SAndroid Build Coastguard Worker def __init__(self, network_key): 138*cfb92d14SAndroid Build Coastguard Worker """ 139*cfb92d14SAndroid Build Coastguard Worker Args: 140*cfb92d14SAndroid Build Coastguard Worker network_key (bytearray) 141*cfb92d14SAndroid Build Coastguard Worker 142*cfb92d14SAndroid Build Coastguard Worker """ 143*cfb92d14SAndroid Build Coastguard Worker super(MacCryptoMaterialCreator, self).__init__(network_key) 144*cfb92d14SAndroid Build Coastguard Worker 145*cfb92d14SAndroid Build Coastguard Worker def _create_nonce(self, eui64, frame_counter, security_level): 146*cfb92d14SAndroid Build Coastguard Worker """ Create CCM Nonce required by AES-128 CCM for encryption and decryption. 147*cfb92d14SAndroid Build Coastguard Worker 148*cfb92d14SAndroid Build Coastguard Worker Read more: 7.6.3.2 CCM Nonce - Std 802.15.4-2006 149*cfb92d14SAndroid Build Coastguard Worker 150*cfb92d14SAndroid Build Coastguard Worker Args: 151*cfb92d14SAndroid Build Coastguard Worker eui64 (bytes) 152*cfb92d14SAndroid Build Coastguard Worker frame_counter (int) 153*cfb92d14SAndroid Build Coastguard Worker security_level (int) 154*cfb92d14SAndroid Build Coastguard Worker 155*cfb92d14SAndroid Build Coastguard Worker Returns: 156*cfb92d14SAndroid Build Coastguard Worker bytes: created Nonce 157*cfb92d14SAndroid Build Coastguard Worker 158*cfb92d14SAndroid Build Coastguard Worker """ 159*cfb92d14SAndroid Build Coastguard Worker return bytes(eui64 + struct.pack(">LB", frame_counter, security_level)) 160*cfb92d14SAndroid Build Coastguard Worker 161*cfb92d14SAndroid Build Coastguard Worker def _create_authenticated_data(self, mhr, auxiliary_security_header, extra_open_fields): 162*cfb92d14SAndroid Build Coastguard Worker """ Create Authenticated Data 163*cfb92d14SAndroid Build Coastguard Worker 164*cfb92d14SAndroid Build Coastguard Worker Read more: 7.6.3.3 CCM prerequisites - Std 802.15.4-2006 165*cfb92d14SAndroid Build Coastguard Worker 166*cfb92d14SAndroid Build Coastguard Worker Args: 167*cfb92d14SAndroid Build Coastguard Worker mhr (bytes) 168*cfb92d14SAndroid Build Coastguard Worker auxiliary_security_header (bytes) 169*cfb92d14SAndroid Build Coastguard Worker extra_open_fields (bytes) 170*cfb92d14SAndroid Build Coastguard Worker 171*cfb92d14SAndroid Build Coastguard Worker Returns: 172*cfb92d14SAndroid Build Coastguard Worker bytes: Authenticated Data 173*cfb92d14SAndroid Build Coastguard Worker 174*cfb92d14SAndroid Build Coastguard Worker """ 175*cfb92d14SAndroid Build Coastguard Worker return bytes(mhr + auxiliary_security_header + extra_open_fields) 176*cfb92d14SAndroid Build Coastguard Worker 177*cfb92d14SAndroid Build Coastguard Worker def create_key_and_nonce_and_authenticated_data(self, message_info): 178*cfb92d14SAndroid Build Coastguard Worker _, mac_key = self._generate_keys(message_info.aux_sec_hdr.sequence_counter) 179*cfb92d14SAndroid Build Coastguard Worker 180*cfb92d14SAndroid Build Coastguard Worker nonce = self._create_nonce( 181*cfb92d14SAndroid Build Coastguard Worker message_info.source_mac_address, 182*cfb92d14SAndroid Build Coastguard Worker message_info.aux_sec_hdr.frame_counter, 183*cfb92d14SAndroid Build Coastguard Worker message_info.aux_sec_hdr.security_level, 184*cfb92d14SAndroid Build Coastguard Worker ) 185*cfb92d14SAndroid Build Coastguard Worker 186*cfb92d14SAndroid Build Coastguard Worker auth_data = self._create_authenticated_data( 187*cfb92d14SAndroid Build Coastguard Worker message_info.mhr_bytes, 188*cfb92d14SAndroid Build Coastguard Worker message_info.aux_sec_hdr_bytes, 189*cfb92d14SAndroid Build Coastguard Worker message_info.extra_open_fields, 190*cfb92d14SAndroid Build Coastguard Worker ) 191*cfb92d14SAndroid Build Coastguard Worker 192*cfb92d14SAndroid Build Coastguard Worker return mac_key, nonce, auth_data 193*cfb92d14SAndroid Build Coastguard Worker 194*cfb92d14SAndroid Build Coastguard Worker @property 195*cfb92d14SAndroid Build Coastguard Worker def mic_length(self): 196*cfb92d14SAndroid Build Coastguard Worker return 4 197*cfb92d14SAndroid Build Coastguard Worker 198*cfb92d14SAndroid Build Coastguard Worker 199*cfb92d14SAndroid Build Coastguard Workerclass MleCryptoMaterialCreator(CryptoMaterialCreator): 200*cfb92d14SAndroid Build Coastguard Worker 201*cfb92d14SAndroid Build Coastguard Worker def __init__(self, network_key): 202*cfb92d14SAndroid Build Coastguard Worker """ 203*cfb92d14SAndroid Build Coastguard Worker Args: 204*cfb92d14SAndroid Build Coastguard Worker network_key (bytearray) 205*cfb92d14SAndroid Build Coastguard Worker 206*cfb92d14SAndroid Build Coastguard Worker """ 207*cfb92d14SAndroid Build Coastguard Worker super(MleCryptoMaterialCreator, self).__init__(network_key) 208*cfb92d14SAndroid Build Coastguard Worker 209*cfb92d14SAndroid Build Coastguard Worker def _create_nonce(self, source_eui64, frame_counter, security_level): 210*cfb92d14SAndroid Build Coastguard Worker """ Create CCM Nonce required by AES-128 CCM for encryption and decryption. 211*cfb92d14SAndroid Build Coastguard Worker 212*cfb92d14SAndroid Build Coastguard Worker Read more: 7.6.3.2 CCM Nonce - Std 802.15.4-2006 213*cfb92d14SAndroid Build Coastguard Worker 214*cfb92d14SAndroid Build Coastguard Worker Args: 215*cfb92d14SAndroid Build Coastguard Worker eui64 (bytearray) 216*cfb92d14SAndroid Build Coastguard Worker frame_counter (int) 217*cfb92d14SAndroid Build Coastguard Worker security_level (int) 218*cfb92d14SAndroid Build Coastguard Worker 219*cfb92d14SAndroid Build Coastguard Worker Returns: 220*cfb92d14SAndroid Build Coastguard Worker bytes: created Nonce 221*cfb92d14SAndroid Build Coastguard Worker 222*cfb92d14SAndroid Build Coastguard Worker """ 223*cfb92d14SAndroid Build Coastguard Worker return bytes(source_eui64[:8] + struct.pack(">LB", frame_counter, security_level)) 224*cfb92d14SAndroid Build Coastguard Worker 225*cfb92d14SAndroid Build Coastguard Worker def _create_authenticated_data(self, source_address, destination_address, auxiliary_security_header): 226*cfb92d14SAndroid Build Coastguard Worker """ Create Authenticated Data 227*cfb92d14SAndroid Build Coastguard Worker 228*cfb92d14SAndroid Build Coastguard Worker Read more: 4.8 - Thread v1.0 Specification 229*cfb92d14SAndroid Build Coastguard Worker 230*cfb92d14SAndroid Build Coastguard Worker Args: 231*cfb92d14SAndroid Build Coastguard Worker source_address (ip_address) 232*cfb92d14SAndroid Build Coastguard Worker destination_address (ip_address) 233*cfb92d14SAndroid Build Coastguard Worker auxiliary_security_header (bytearray) 234*cfb92d14SAndroid Build Coastguard Worker 235*cfb92d14SAndroid Build Coastguard Worker Returns: 236*cfb92d14SAndroid Build Coastguard Worker bytes: Authenticated Data 237*cfb92d14SAndroid Build Coastguard Worker 238*cfb92d14SAndroid Build Coastguard Worker """ 239*cfb92d14SAndroid Build Coastguard Worker return bytes(source_address.packed + destination_address.packed + auxiliary_security_header) 240*cfb92d14SAndroid Build Coastguard Worker 241*cfb92d14SAndroid Build Coastguard Worker def create_key_and_nonce_and_authenticated_data(self, message_info): 242*cfb92d14SAndroid Build Coastguard Worker mle_key, _ = self._generate_keys(message_info.aux_sec_hdr.sequence_counter) 243*cfb92d14SAndroid Build Coastguard Worker 244*cfb92d14SAndroid Build Coastguard Worker nonce = self._create_nonce( 245*cfb92d14SAndroid Build Coastguard Worker message_info.source_mac_address.mac_address, 246*cfb92d14SAndroid Build Coastguard Worker message_info.aux_sec_hdr.frame_counter, 247*cfb92d14SAndroid Build Coastguard Worker message_info.aux_sec_hdr.security_level, 248*cfb92d14SAndroid Build Coastguard Worker ) 249*cfb92d14SAndroid Build Coastguard Worker 250*cfb92d14SAndroid Build Coastguard Worker auth_data = self._create_authenticated_data( 251*cfb92d14SAndroid Build Coastguard Worker message_info.source_ipv6, 252*cfb92d14SAndroid Build Coastguard Worker message_info.destination_ipv6, 253*cfb92d14SAndroid Build Coastguard Worker message_info.aux_sec_hdr_bytes, 254*cfb92d14SAndroid Build Coastguard Worker ) 255*cfb92d14SAndroid Build Coastguard Worker 256*cfb92d14SAndroid Build Coastguard Worker return mle_key, nonce, auth_data 257*cfb92d14SAndroid Build Coastguard Worker 258*cfb92d14SAndroid Build Coastguard Worker @property 259*cfb92d14SAndroid Build Coastguard Worker def mic_length(self): 260*cfb92d14SAndroid Build Coastguard Worker return 4 261*cfb92d14SAndroid Build Coastguard Worker 262*cfb92d14SAndroid Build Coastguard Worker 263*cfb92d14SAndroid Build Coastguard Workerclass AuxiliarySecurityHeader: 264*cfb92d14SAndroid Build Coastguard Worker 265*cfb92d14SAndroid Build Coastguard Worker def __init__( 266*cfb92d14SAndroid Build Coastguard Worker self, 267*cfb92d14SAndroid Build Coastguard Worker key_id_mode, 268*cfb92d14SAndroid Build Coastguard Worker security_level, 269*cfb92d14SAndroid Build Coastguard Worker frame_counter, 270*cfb92d14SAndroid Build Coastguard Worker key_id, 271*cfb92d14SAndroid Build Coastguard Worker big_endian=True, 272*cfb92d14SAndroid Build Coastguard Worker ): 273*cfb92d14SAndroid Build Coastguard Worker """ 274*cfb92d14SAndroid Build Coastguard Worker Args: 275*cfb92d14SAndroid Build Coastguard Worker key_id_mode (int) 276*cfb92d14SAndroid Build Coastguard Worker security_level (int) 277*cfb92d14SAndroid Build Coastguard Worker frame_counter (int) 278*cfb92d14SAndroid Build Coastguard Worker key_id (bytearray) 279*cfb92d14SAndroid Build Coastguard Worker """ 280*cfb92d14SAndroid Build Coastguard Worker self._key_id_mode = key_id_mode 281*cfb92d14SAndroid Build Coastguard Worker self._security_level = security_level 282*cfb92d14SAndroid Build Coastguard Worker self._frame_counter = frame_counter 283*cfb92d14SAndroid Build Coastguard Worker self._key_id = key_id 284*cfb92d14SAndroid Build Coastguard Worker self._big_endian = big_endian 285*cfb92d14SAndroid Build Coastguard Worker 286*cfb92d14SAndroid Build Coastguard Worker @property 287*cfb92d14SAndroid Build Coastguard Worker def sequence_counter(self): 288*cfb92d14SAndroid Build Coastguard Worker """ Compute or extract sequence counter based on currently set Key Index Mode. """ 289*cfb92d14SAndroid Build Coastguard Worker 290*cfb92d14SAndroid Build Coastguard Worker if self.key_id_mode == 0: 291*cfb92d14SAndroid Build Coastguard Worker key_source = self.key_id[:8] 292*cfb92d14SAndroid Build Coastguard Worker format = ">Q" if self._big_endian else "<Q" 293*cfb92d14SAndroid Build Coastguard Worker elif self.key_id_mode == 1: 294*cfb92d14SAndroid Build Coastguard Worker # Try to guess valid Key Sequence Counter based on Key Index. This 295*cfb92d14SAndroid Build Coastguard Worker # one should work for now. 296*cfb92d14SAndroid Build Coastguard Worker return self.key_index - 1 297*cfb92d14SAndroid Build Coastguard Worker elif self.key_id_mode == 2: 298*cfb92d14SAndroid Build Coastguard Worker # In this mode sequence counter is stored on the first four bytes 299*cfb92d14SAndroid Build Coastguard Worker # of Key ID. 300*cfb92d14SAndroid Build Coastguard Worker key_source = self.key_id[:4] 301*cfb92d14SAndroid Build Coastguard Worker format = ">I" if self._big_endian else "<I" 302*cfb92d14SAndroid Build Coastguard Worker else: 303*cfb92d14SAndroid Build Coastguard Worker raise ValueError("Unsupported Key Index Mode: {}".format(self.key_id_mode)) 304*cfb92d14SAndroid Build Coastguard Worker 305*cfb92d14SAndroid Build Coastguard Worker return struct.unpack(format, key_source)[0] 306*cfb92d14SAndroid Build Coastguard Worker 307*cfb92d14SAndroid Build Coastguard Worker @property 308*cfb92d14SAndroid Build Coastguard Worker def key_index(self): 309*cfb92d14SAndroid Build Coastguard Worker return struct.unpack(">B", self.key_id[-1:])[0] 310*cfb92d14SAndroid Build Coastguard Worker 311*cfb92d14SAndroid Build Coastguard Worker @property 312*cfb92d14SAndroid Build Coastguard Worker def key_id_mode(self): 313*cfb92d14SAndroid Build Coastguard Worker return self._key_id_mode 314*cfb92d14SAndroid Build Coastguard Worker 315*cfb92d14SAndroid Build Coastguard Worker @property 316*cfb92d14SAndroid Build Coastguard Worker def security_level(self): 317*cfb92d14SAndroid Build Coastguard Worker return self._security_level 318*cfb92d14SAndroid Build Coastguard Worker 319*cfb92d14SAndroid Build Coastguard Worker @property 320*cfb92d14SAndroid Build Coastguard Worker def frame_counter(self): 321*cfb92d14SAndroid Build Coastguard Worker return self._frame_counter 322*cfb92d14SAndroid Build Coastguard Worker 323*cfb92d14SAndroid Build Coastguard Worker @property 324*cfb92d14SAndroid Build Coastguard Worker def key_id(self): 325*cfb92d14SAndroid Build Coastguard Worker return self._key_id 326*cfb92d14SAndroid Build Coastguard Worker 327*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 328*cfb92d14SAndroid Build Coastguard Worker return "AuxiliarySecurityHeader(key_id_mode={}, security_level={}, frame_counter={}, key_id={})".format( 329*cfb92d14SAndroid Build Coastguard Worker self.key_id_mode, 330*cfb92d14SAndroid Build Coastguard Worker self.security_level, 331*cfb92d14SAndroid Build Coastguard Worker self.frame_counter, 332*cfb92d14SAndroid Build Coastguard Worker hexlify(self.key_id), 333*cfb92d14SAndroid Build Coastguard Worker ) 334*cfb92d14SAndroid Build Coastguard Worker 335*cfb92d14SAndroid Build Coastguard Worker 336*cfb92d14SAndroid Build Coastguard Workerclass AuxiliarySecurityHeaderFactory: 337*cfb92d14SAndroid Build Coastguard Worker 338*cfb92d14SAndroid Build Coastguard Worker _SECURITY_CONTROL_LENGTH = 1 339*cfb92d14SAndroid Build Coastguard Worker _FRAME_COUNTER_LENGTH = 4 340*cfb92d14SAndroid Build Coastguard Worker 341*cfb92d14SAndroid Build Coastguard Worker _KEY_ID_LENGTH_KEY_ID_0 = 0 342*cfb92d14SAndroid Build Coastguard Worker _KEY_ID_LENGTH_KEY_ID_1 = 1 343*cfb92d14SAndroid Build Coastguard Worker _KEY_ID_LENGTH_KEY_ID_2 = 5 344*cfb92d14SAndroid Build Coastguard Worker _KEY_ID_LENGTH_KEY_ID_3 = 9 345*cfb92d14SAndroid Build Coastguard Worker 346*cfb92d14SAndroid Build Coastguard Worker _key_id_lengths = { 347*cfb92d14SAndroid Build Coastguard Worker 0: _KEY_ID_LENGTH_KEY_ID_0, 348*cfb92d14SAndroid Build Coastguard Worker 1: _KEY_ID_LENGTH_KEY_ID_1, 349*cfb92d14SAndroid Build Coastguard Worker 2: _KEY_ID_LENGTH_KEY_ID_2, 350*cfb92d14SAndroid Build Coastguard Worker 3: _KEY_ID_LENGTH_KEY_ID_3, 351*cfb92d14SAndroid Build Coastguard Worker } 352*cfb92d14SAndroid Build Coastguard Worker 353*cfb92d14SAndroid Build Coastguard Worker def _parse_security_control(self, security_control_byte): 354*cfb92d14SAndroid Build Coastguard Worker security_level = security_control_byte & 0x07 355*cfb92d14SAndroid Build Coastguard Worker key_id_mode = (security_control_byte >> 3) & 0x03 356*cfb92d14SAndroid Build Coastguard Worker 357*cfb92d14SAndroid Build Coastguard Worker return security_level, key_id_mode 358*cfb92d14SAndroid Build Coastguard Worker 359*cfb92d14SAndroid Build Coastguard Worker def _parse_frame_counter(self, frame_counter_bytes): 360*cfb92d14SAndroid Build Coastguard Worker return struct.unpack("<I", frame_counter_bytes)[0] 361*cfb92d14SAndroid Build Coastguard Worker 362*cfb92d14SAndroid Build Coastguard Worker def _key_id_length(self, key_id_mode): 363*cfb92d14SAndroid Build Coastguard Worker return self._key_id_lengths[key_id_mode] 364*cfb92d14SAndroid Build Coastguard Worker 365*cfb92d14SAndroid Build Coastguard Worker def parse(self, data, message_info): 366*cfb92d14SAndroid Build Coastguard Worker security_control_bytes = bytearray(data.read(self._SECURITY_CONTROL_LENGTH)) 367*cfb92d14SAndroid Build Coastguard Worker frame_counter_bytes = bytearray(data.read(self._FRAME_COUNTER_LENGTH)) 368*cfb92d14SAndroid Build Coastguard Worker 369*cfb92d14SAndroid Build Coastguard Worker security_level, key_id_mode = self._parse_security_control(security_control_bytes[0]) 370*cfb92d14SAndroid Build Coastguard Worker frame_counter = self._parse_frame_counter(frame_counter_bytes) 371*cfb92d14SAndroid Build Coastguard Worker 372*cfb92d14SAndroid Build Coastguard Worker key_id_length = self._key_id_length(key_id_mode) 373*cfb92d14SAndroid Build Coastguard Worker key_id_bytes = bytearray(data.read(key_id_length)) 374*cfb92d14SAndroid Build Coastguard Worker 375*cfb92d14SAndroid Build Coastguard Worker aux_sec_hdr = AuxiliarySecurityHeader(key_id_mode, security_level, frame_counter, key_id_bytes) 376*cfb92d14SAndroid Build Coastguard Worker 377*cfb92d14SAndroid Build Coastguard Worker message_info.aux_sec_hdr_bytes = (security_control_bytes + frame_counter_bytes + key_id_bytes) 378*cfb92d14SAndroid Build Coastguard Worker message_info.aux_sec_hdr = aux_sec_hdr 379*cfb92d14SAndroid Build Coastguard Worker 380*cfb92d14SAndroid Build Coastguard Worker return aux_sec_hdr 381