Exemplo n.º 1
0
def opdata1_decrypt_master_key(data, key, hmac_key, aes_size=C_AES_SIZE, ignore_hmac=False):
    key_size = KEY_SIZE[aes_size]
    bare_key = opdata1_decrypt_item(data, key, hmac_key, aes_size=aes_size, ignore_hmac=ignore_hmac)
    # XXX: got the following step from jeff@agilebits (as opposed to the
    # docs anywhere)
    digest = Hash(SHA512(), backend=_backend)
    digest.update(bare_key)
    hashed_key = digest.finalize()
    return hashed_key[:key_size], hashed_key[key_size:]
Exemplo n.º 2
0
def sha256(message):
    """Generates a SHA256 hash of a message"""
    if isinstance(message, str):
        message = bytes(message, encoding='utf-8')
    elif isinstance(message, bytearray):
        message = bytes(message)
    digest = Hash(SHA256(), backend=default_backend())
    digest.update(message)
    return digest.finalize()
Exemplo n.º 3
0
    def compute_verify_data(self, basekey, handshake_context):
        hash_len = self.hash.digest_size
        finished_key = self.expand_label(basekey, b"finished", b"", hash_len)

        h = Hash(self.hash, backend=default_backend())
        h.update(handshake_context)
        hash_value = h.finalize()

        hm = HMAC(finished_key, self.hash, default_backend())
        hm.update(hash_value)
        return hm.finalize()
Exemplo n.º 4
0
def _generate_property_iv(entity_iv, pk, rk, property_name, isJavaV1):
    '''
    Uses the entity_iv, partition key, and row key to generate and return
    the iv for the specified property.
    '''
    digest = Hash(SHA256(), default_backend())
    if not isJavaV1:
        digest.update(entity_iv +
                      (rk + pk + property_name).encode('utf-8'))
    else:
        digest.update(entity_iv +
                      (pk + rk + property_name).encode('utf-8'))
    propertyIV = digest.finalize()
    return propertyIV[:16]
Exemplo n.º 5
0
def a_decrypt_item(data, key, aes_size=A_AES_SIZE):
    key_size = KEY_SIZE[aes_size]
    if data[:len(SALT_MARKER)] == SALT_MARKER:
        salt = data[len(SALT_MARKER):len(SALT_MARKER) + SALT_SIZE]
        data = data[len(SALT_MARKER) + SALT_SIZE:]
        pb_gen = pbkdf1.PBKDF1(key, salt)
        nkey = pb_gen.read(key_size)
        iv = pb_gen.read(key_size)
    else:
        digest = Hash(MD5(), backend=_backend)
        digest.update(key)
        nkey = digest.finalize()
        iv = '\x00'*key_size

    aes = Cipher(algorithms.AES(nkey), modes.CBC(iv), backend=_backend)
    decryptor = aes.decryptor()
    return padding.pkcs5_unpad(decryptor.update(data) + decryptor.finalize())
Exemplo n.º 6
0
def decrypt(secret, hash, data):
    """
    Decrypt per telegram docs at https://core.telegram.org/passport.

    Args:
        secret (:obj:`str` or :obj:`bytes`): The encryption secret, either as bytes or as a
            base64 encoded string.
        hash (:obj:`str` or :obj:`bytes`): The hash, either as bytes or as a
            base64 encoded string.
        data (:obj:`str` or :obj:`bytes`): The data to decrypt, either as bytes or as a
            base64 encoded string.
        file (:obj:`bool`): Force data to be treated as raw data, instead of trying to
            b64decode it.

    Raises:
        :class:`TelegramDecryptionError`: Given hash does not match hash of decrypted data.

    Returns:
        :obj:`bytes`: The decrypted data as bytes.

    """
    if not CRYPTO_INSTALLED:
        raise RuntimeError(
            'To use Telegram Passports, PTB must be installed via `pip install '
            'python-telegram-bot[passport]`.')
    # Make a SHA512 hash of secret + update
    digest = Hash(SHA512(), backend=default_backend())
    digest.update(secret + hash)
    secret_hash_hash = digest.finalize()
    # First 32 chars is our key, next 16 is the initialisation vector
    key, init_vector = secret_hash_hash[:32], secret_hash_hash[32:32 + 16]
    # Init a AES-CBC cipher and decrypt the data
    cipher = Cipher(AES(key), CBC(init_vector), backend=default_backend())
    decryptor = cipher.decryptor()
    data = decryptor.update(data) + decryptor.finalize()
    # Calculate SHA256 hash of the decrypted data
    digest = Hash(SHA256(), backend=default_backend())
    digest.update(data)
    data_hash = digest.finalize()
    # If the newly calculated hash did not match the one telegram gave us
    if data_hash != hash:
        # Raise a error that is caught inside telegram.PassportData and transformed into a warning
        raise TelegramDecryptionError(
            f"Hashes are not equal! {data_hash} != {hash}")
    # Return data without padding
    return data[data[0]:]
    def create_token(self):
        a_token = {
            'type': 'access_token',
            'client': self.id,
            'scope': self.scope,
        }

        token_ser = tokenserializer.dumps(a_token)

        h = Hash(SHA256(), default_backend())
        h.update(token_ser.encode('utf-8'))

        self.token = h.finalize()

        db.session.add(self)
        db.session.commit()

        return token_ser
Exemplo n.º 8
0
    def _build_index(self):
        index = {}

        for path in get_git_files(self._repository):
            if (self._repository / path).is_file():
                uuid = str(uuid4())

                while index.get(uuid):
                    uuid = str(uuid4())

                hasher = Hash(BLAKE2b(64))

                with open(self._repository / path, 'rb') as file:
                    hasher.update(file.read())

                index[str(path)] = {
                    'path': str(path),
                    'uuid': uuid,
                    'checksum': hasher.finalize().hex()
                }

        for path in (self._repository / '.git').glob('**/*'):
            if path.is_file():
                uuid = str(uuid4())

                while index.get(uuid):
                    uuid = str(uuid4())

                hasher = Hash(BLAKE2b(64))

                with open(path, 'rb') as file:
                    hasher.update(file.read())

                short_path = path.relative_to(self._repository)

                index[str(short_path)] = {
                    'path': str(short_path),
                    'uuid': uuid,
                    'checksum': hasher.finalize().hex()
                }

        return index
Exemplo n.º 9
0
def make_or_ciphers(key):
    backend = _default_backend

    Df = key[1]
    Db = key[2]
    Kf = key[3]
    Kb = key[4]

    initial_counter = "\x00" * 16
    Dffunc = Hash(SHA1(), backend=backend)
    Dbfunc = Hash(SHA1(), backend=backend)
    Kffunc = Cipher(AES(Kf),
                    modes.CTR(initial_counter),
                    backend=_default_backend).encryptor()
    Kbfunc = Cipher(AES(Kb),
                    modes.CTR(initial_counter),
                    backend=_default_backend).encryptor()

    Dffunc.update(Df)
    Dbfunc.update(Db)

    return (Dffunc, Dbfunc, Kffunc, Kbfunc)
Exemplo n.º 10
0
 async def decrypt_stream(
         self, stream: AsyncIterator[bytes]) -> AsyncIterator[bytes]:
     decryptor = self._cipher.decryptor()  # type: ignore
     assert isinstance(decryptor, CipherContext)
     digest = Hash(SHA256())
     skip = None
     async for chunk in stream:
         decrypted = decryptor.update(chunk)
         digest.update(decrypted)
         if skip is None:
             skip = decrypted[0]
         if skip >= len(decrypted):
             skip = skip - len(decrypted)
         else:
             yield decrypted[skip:]
             skip = 0
     decrypted = decryptor.finalize()
     digest.update(decrypted)
     computed_hash = digest.finalize()
     if not bytes_eq(computed_hash, self._data_hash):
         raise RuntimeError('Decryption error')
     yield decrypted[skip:]
Exemplo n.º 11
0
def nc_kep(kep2, kep4) -> bool:
    """
    Check that sha512(kep4[4:] = Kep2.kdf2

    :param kep2: bytes, sent by the dsc
    :param kep4: bytes, sent by the dsc

    :return: bool
    """
    validate_kep2("nc_kep", kep2)
    validate_kep4("nc_kep", kep4)

    kep0 = Hash(SHA512(), backend=default_backend())
    kep0.update(kep4[4:])
    kep0_out = kep0.finalize()

    left = kep0_out
    right = Kep2(kep2).kdf2
    log.debug("nc_kep left : {}, {}".format(left.hex(), len(left.hex())))
    log.debug("nc_kep right: {}, {}".format(right.hex(), len(right.hex())))

    return left == right
Exemplo n.º 12
0
    def decrypt_encryption_key_fallback(self):
        """Decrypts the encryption key using the FALLBACK method. In this method, the
        context string, usually "CredEncryption" or "PSEEncryption", is encrypted using
        a derivation of a fixed key hardcoded in CommonCryptoLib, and used as key to
        encrypt the actual encryption key used in the file with the AES cipher.

        :return: Encryption key decrypted
        :rtype: string
        """
        log_lps.debug("Obtaining encryption key with FALLBACK LPS mode")

        digest = Hash(SHA1(), backend=default_backend())
        digest.update(cred_key_lps_fallback)
        hashed_key = digest.finalize()

        hmac = HMAC(hashed_key, SHA1(), backend=default_backend())
        hmac.update(self.context)
        default_key = hmac.finalize()[:16]

        iv = "\x00" * 16
        decryptor = Cipher(algorithms.AES(default_key), modes.CBC(iv), backend=default_backend()).decryptor()
        encryption_key = decryptor.update(self.encrypted_key) + decryptor.finalize()

        return encryption_key
Exemplo n.º 13
0
    def decrypt_encryption_key_fallback(self):
        """Decrypts the encryption key using the FALLBACK method. In this method, the
        context string, usually "CredEncryption" or "PSEEncryption", is encrypted using
        a derivation of a fixed key hardcoded in CommonCryptoLib, and used as key to
        encrypt the actual encryption key used in the file with the AES cipher.

        :return: Encryption key decrypted
        :rtype: string
        """
        log_lps.debug("Obtaining encryption key with FALLBACK LPS mode")

        digest = Hash(SHA1(), backend=default_backend())
        digest.update(cred_key_lps_fallback)
        hashed_key = digest.finalize()

        hmac = HMAC(hashed_key, SHA1(), backend=default_backend())
        hmac.update(self.context)
        default_key = hmac.finalize()[:16]

        iv = "\x00" * 16
        decryptor = Cipher(algorithms.AES(default_key), modes.CBC(iv), backend=default_backend()).decryptor()
        encryption_key = decryptor.update(self.encrypted_key) + decryptor.finalize()

        return encryption_key
Exemplo n.º 14
0
def get_linekey(lineNum, userKey, fileKey):
    '''
    Get line number specific key by hashing
    userkey, linenum and filekey
    '''
    hasher = Hash(algorithm=SHA256(), backend=default_backend())
    hasher.update(userKey)
    hasher.update(lineNum.to_bytes(4, 'little'))
    hasher.update(fileKey)
    key = base64.urlsafe_b64encode(hasher.finalize())
    #print("linekey:{}:{}:{}={}".format(lineNum, userKey, fileKey, key), file=GERRFILE)
    return key
Exemplo n.º 15
0
 def derive(self, key_material):
     if not isinstance(key_material, bytes):
         raise TypeError("key_material must be bytes.")
     h = Hash(self._algorithm(), backend=self._backend)
     h.update(key_material)
     h.update(self._salt)
     derived_key = h.finalize()
     for i in xrange(self._iterations-1):
         h = Hash(self._algorithm(), backend=self._backend)
         h.update(derived_key)
         derived_key = h.finalize()
     return derived_key
Exemplo n.º 16
0
 def derive(self, key_material):
     if not isinstance(key_material, bytes):
         raise TypeError("key_material must be bytes.")
     h = Hash(self._algorithm(), backend=self._backend)
     h.update(key_material)
     h.update(self._salt)
     derived_key = h.finalize()
     for i in xrange(self._iterations - 1):
         h = Hash(self._algorithm(), backend=self._backend)
         h.update(derived_key)
         derived_key = h.finalize()
     return derived_key
Exemplo n.º 17
0
def hash_password(password: str, salt: str) -> str:
    """ Generates the password hash for the given user

    :param password: The password to hash
    :param salt: The salt(base64) to use in hash
    :return: The password hash
    """
    hash_ = Hash(SHA3_512())
    hash_.update(password.encode('ascii') + b64decode(salt.encode('ascii')))
    digest = hash_.finalize()
    hash_ = Hash(SHA3_512())
    hash_.update(digest)
    digest = hash_.finalize()
    hash_ = Hash(SHA3_512())
    hash_.update(digest + b64decode(salt.encode('ascii')))
    digest = hash_.finalize()
    return b64encode(digest).decode('ascii')
Exemplo n.º 18
0
def gen_key(key: bytes):
    digest = Hash(SHA256())
    digest.update(key)
    hash_bytes = digest.finalize()
    return hash_bytes[:32]
Exemplo n.º 19
0
KDF2_input = b'EAP-NOOB' + base64url_decode(Np2_b64) + base64url_decode(Ns2_b64)
KDF2_out = KDF(algorithm=SHA256(), length=288, otherinfo=KDF2_input,
    backend=default_backend()).derive(Kz)
Kms2 = KDF2_out[224:256]
Kmp2 = KDF2_out[256:288]

# Remove trailing '=' from base64 encoded values
Np_b64 = Np_b64.strip('=')
Ns_b64 = Ns_b64.strip('=')
Np2_b64 = Np2_b64.strip('=')
Ns2_b64 = Ns2_b64.strip('=')
Noob_b64 = Noob_b64.strip('=')

## NoobId
NoobId_input = Hash(SHA256(), backend=default_backend())
NoobId_input.update(b'NoobId')
NoobId_input.update(Noob_b64.encode())
NoobId = NoobId_input.finalize()[:16]
NoobId_b64 = base64url_encode(NoobId).decode().strip('=')

## Hoob
Hoob_values = loads('{"Hoob":[]}', object_pairs_hook=OrderedDict)
Hoob_values['Hoob'] = [Dir, Vers, Verp, PeerId, Cryptosuites, Dirs,
    loads(ServerInfo, object_pairs_hook=OrderedDict), Cryptosuitep, Dirp, Realm,
        loads(PeerInfo, object_pairs_hook=OrderedDict), 0, PKs_full, Ns_b64,
            PKp_full, Np_b64, Noob_b64]
Hoob_input = Hash(SHA256(), backend=default_backend())
Hoob_input.update(dumps(Hoob_values['Hoob'], separators=(',', ':')).encode())
Hoob = Hoob_input.finalize()[:16]
Hoob_b64 = base64url_encode(Hoob).decode().strip('=')
Exemplo n.º 20
0
def sha256(bytes):
    digest = Hash(SHA256(), backend=default_backend())
    digest.update(bytes)
    return digest.finalize()
Exemplo n.º 21
0
 def digest(inp):
     h = Hash(self._algorithm(), backend=self._backend)
     h.update(inp)
     return h.finalize()
Exemplo n.º 22
0
    def test_validate_encryption(self):
        # Arrange 
        entity = self._create_default_entity_for_encryption()
        key_encryption_key = KeyWrapper('key1')
        self.ts.key_encryption_key = key_encryption_key
        self.ts.insert_entity(self.table_name, entity)

        # Act
        self.ts.key_encryption_key = None
        entity = self.ts.get_entity(self.table_name, entity['PartitionKey'], entity['RowKey'])

        # Note the minor discrepancy from the normal decryption process: because the entity was retrieved
        # without being decrypted, the encrypted_properties list is now stored in an EntityProperty object
        # and is already raw bytes.
        encrypted_properties_list = entity['_ClientEncryptionMetadata2'].value
        encryption_data = entity['_ClientEncryptionMetadata1']
        encryption_data = _dict_to_encryption_data(loads(encryption_data))

        content_encryption_key = key_encryption_key.unwrap_key(encryption_data.wrapped_content_key.encrypted_key,
                                                               encryption_data.wrapped_content_key.algorithm)

        digest = Hash(SHA256(), default_backend())
        digest.update(encryption_data.content_encryption_IV +
                      (entity['RowKey'] + entity['PartitionKey'] + '_ClientEncryptionMetadata2').encode('utf-8'))
        metadataIV = digest.finalize()
        metadataIV = metadataIV[:16]

        cipher = _generate_AES_CBC_cipher(content_encryption_key, metadataIV)

        # Decrypt the data.
        decryptor = cipher.decryptor()
        encrypted_properties_list = decryptor.update(encrypted_properties_list) + decryptor.finalize()

        # Unpad the data.
        unpadder = PKCS7(128).unpadder()
        encrypted_properties_list = unpadder.update(encrypted_properties_list) + unpadder.finalize()

        encrypted_properties_list = encrypted_properties_list.decode('utf-8')

        # Strip the square braces from the ends and split string into list.
        encrypted_properties_list = loads(encrypted_properties_list)

        entity_iv, encrypted_properties, content_encryption_key = \
            (encryption_data.content_encryption_IV, encrypted_properties_list, content_encryption_key)

        decrypted_entity = deepcopy(entity)

        for property in encrypted_properties_list:
            value = entity[property]

            digest = Hash(SHA256(), default_backend())
            digest.update(entity_iv +
                          (entity['RowKey'] + entity['PartitionKey'] + property).encode('utf-8'))
            propertyIV = digest.finalize()
            propertyIV = propertyIV[:16]

            cipher = _generate_AES_CBC_cipher(content_encryption_key,
                                              propertyIV)

            # Decrypt the property.
            decryptor = cipher.decryptor()
            decrypted_data = (decryptor.update(value.value) + decryptor.finalize())

            # Unpad the data.
            unpadder = PKCS7(128).unpadder()
            decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize())

            decrypted_data = decrypted_data.decode('utf-8')

            decrypted_entity[property] = decrypted_data

        decrypted_entity.pop('_ClientEncryptionMetadata1')
        decrypted_entity.pop('_ClientEncryptionMetadata2')

        # Assert
        self.assertEqual(decrypted_entity['sex'], 'male')
Exemplo n.º 23
0
def sha256(data):
    hash = Hash(SHA256())
    hash.update(data)
    return hash.finalize().hex()
Exemplo n.º 24
0
def sha256(data: bytes) -> bytes:
    digest = Hash(SHA256())
    digest.update(data)
    return digest.finalize()
Exemplo n.º 25
0
 def derive_secret(self, secret, label, messages):
     h = Hash(self.hash, backend=default_backend())
     h.update(messages)
     hash_messages = h.finalize()
     hash_len = self.hash.digest_size
     return self.expand_label(secret, label, hash_messages, hash_len)
Exemplo n.º 26
0
def gen_nonce_from_timestamp(timestamp: int):
    digest = Hash(SHA256())
    digest.update(str(timestamp).encode("utf-8"))
    hash_bytes = digest.finalize()
    return hash_bytes[:12]
Exemplo n.º 27
0
def sha1_hash(data):
    sha = Hash(SHA1(), backend)
    sha.update(data)
    return sha.finalize()
Exemplo n.º 28
0
def sign(msg):
    digest = Hash(SHA512(), backend=default_backend())
    digest.update(msg.encode())
    signingdata = int.from_bytes(digest.finalize(), "big")
    return pow(signingdata, key.d, key.public_numbers.n)
Exemplo n.º 29
0
 def digest(inp):
     h = Hash(self._algorithm(), backend=self._backend)
     h.update(inp)
     return h.finalize()
    def test_validate_encryption(self):
        # Arrange 
        entity = self._create_default_entity_for_encryption()
        key_encryption_key = KeyWrapper('key1')
        self.ts.key_encryption_key = key_encryption_key
        self.ts.insert_entity(self.table_name, entity)

        # Act
        self.ts.key_encryption_key = None
        entity = self.ts.get_entity(self.table_name, entity['PartitionKey'], entity['RowKey'])

        # Note the minor discrepancy from the normal decryption process: because the entity was retrieved
        # without being decrypted, the encrypted_properties list is now stored in an EntityProperty object
        # and is already raw bytes.
        encrypted_properties_list = entity['_ClientEncryptionMetadata2'].value
        encryption_data = entity['_ClientEncryptionMetadata1']
        encryption_data = _dict_to_encryption_data(loads(encryption_data))

        content_encryption_key = key_encryption_key.unwrap_key(encryption_data.wrapped_content_key.encrypted_key,
                                                           encryption_data.wrapped_content_key.algorithm)

        digest = Hash(SHA256(), default_backend())
        digest.update(encryption_data.content_encryption_IV +
                        (entity['RowKey'] + entity['PartitionKey'] + '_ClientEncryptionMetadata2').encode('utf-8'))
        metadataIV = digest.finalize()
        metadataIV = metadataIV[:16]

        cipher = _generate_AES_CBC_cipher(content_encryption_key, metadataIV)

        # Decrypt the data.
        decryptor = cipher.decryptor()
        encrypted_properties_list = decryptor.update(encrypted_properties_list) + decryptor.finalize()

        # Unpad the data.
        unpadder = PKCS7(128).unpadder()
        encrypted_properties_list = unpadder.update(encrypted_properties_list) + unpadder.finalize()

        encrypted_properties_list = encrypted_properties_list.decode('utf-8')

        # Strip the square braces from the ends and split string into list.
        encrypted_properties_list = loads(encrypted_properties_list)

        entity_iv, encrypted_properties, content_encryption_key = \
            (encryption_data.content_encryption_IV, encrypted_properties_list, content_encryption_key)

        decrypted_entity = deepcopy(entity)

        for property in encrypted_properties_list:
            value = entity[property]

            digest = Hash(SHA256(), default_backend())
            digest.update(entity_iv +
                            (entity['RowKey'] + entity['PartitionKey'] + property).encode('utf-8'))
            propertyIV = digest.finalize()
            propertyIV = propertyIV[:16]

            cipher = _generate_AES_CBC_cipher(content_encryption_key,
                                              propertyIV)

            # Decrypt the property.
            decryptor = cipher.decryptor()
            decrypted_data = (decryptor.update(value.value) + decryptor.finalize())
        
            # Unpad the data.
            unpadder = PKCS7(128).unpadder()
            decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize())

            decrypted_data = decrypted_data.decode('utf-8')
        
            decrypted_entity[property] = decrypted_data

        decrypted_entity.pop('_ClientEncryptionMetadata1')
        decrypted_entity.pop('_ClientEncryptionMetadata2')

        
        # Assert
        self.assertEqual(decrypted_entity['sex'], 'male')
Exemplo n.º 31
0
def sha256(bytestr):
    hash = Hash(SHA256, DEFAULT_BACKEND)
    hash.update(bytestr)
    hash = hash.finalize()

    return hash
Exemplo n.º 32
0
 def generate() -> "SessionKey":
     rs = os.urandom(SessionKey._hash_algo.digest_size)
     h = Hash(SessionKey._hash_algo(), backend=default_backend())
     h.update(rs)
     return SessionKey(h.finalize())
Exemplo n.º 33
0
def setup_hmac_aes(salt, password):
    hash = Hash(SHA256(), default_backend())
    hash.update(salt + bytes(password, 'ascii'))
    hmac = HMAC(hash.finalize()[16:], SHA256(), default_backend())
    return hmac
Exemplo n.º 34
0
def sm3(data):
    hash = Hash(SM3())
    hash.update(data)
    return hash.finalize().hex()
Exemplo n.º 35
0
def sha1(msg):
    sha = Hash(SHA1(), backend=bend)
    sha.update(msg)
    return sha.finalize()
Exemplo n.º 36
0
 def _get_digest(self, data, digest_algorithm):
     hasher = Hash(algorithm=digest_algorithm, backend=default_backend())
     hasher.update(data)
     return ensure_str(b64encode(hasher.finalize()))
Exemplo n.º 37
0
def derive_keyhash_v1(password, salt, iterations):
    derived_key = derive_key_v1(password, salt, iterations)
    hf = Hash(SHA256(), backend=_CRYPTO_BACKEND)
    hf.update(derived_key)
    return hf.finalize()
Exemplo n.º 38
0
def sha1_hash(data):
    sha = Hash(SHA1(), backend)
    sha.update(data)
    return sha.finalize()
Exemplo n.º 39
0
class ntor(object):
    def __init__(self, node):
        # 5.1.4. The "ntor" handshake

        # This handshake uses a set of DH handshakes to compute a set of
        # shared keys which the client knows are shared only with a particular
        # server, and the server knows are shared with whomever sent the
        # original handshake (or with nobody at all).  Here we use the
        # "curve25519" group and representation as specified in "Curve25519:
        # new Diffie-Hellman speed records" by D. J. Bernstein.

        # [The ntor handshake was added in Tor 0.2.4.8-alpha.]

        self.node = node

        # In this section, define:
        #   H(x,t) as HMAC_SHA256 with message x and key t.
        #   H_LENGTH  = 32.
        #   ID_LENGTH = 20.
        #   G_LENGTH  = 32
        #   PROTOID   = "ntor-curve25519-sha256-1"
        #   t_mac     = PROTOID | ":mac"
        #   t_key     = PROTOID | ":key_extract"
        #   t_verify  = PROTOID | ":verify"
        #   MULT(a,b) = the multiplication of the curve25519 point 'a' by the
        #               scalar 'b'.
        #   G         = The preferred base point for curve25519 ([9])
        #   KEYGEN()  = The curve25519 key generation algorithm, returning
        #               a private/public keypair.
        #   m_expand  = PROTOID | ":key_expand"

        # H is defined as hmac()
        # MULT is included in the curve25519 library as get_shared_key()
        # KEYGEN() is curve25519.Private()
        self.protoid = 'ntor-curve25519-sha256-1'
        self.t_mac = self.protoid + ':mac'
        self.t_key = self.protoid + ':key_extract'
        self.t_verify = self.protoid + ':verify'
        self.m_expand = self.protoid + ':key_expand'

        # To perform the handshake, the client needs to know an identity key
        # digest for the server, and an ntor onion key (a curve25519 public
        # key) for that server. Call the ntor onion key "B".  The client
        # generates a temporary keypair:
        #     x,X = KEYGEN()
        self.x = curve25519.Private()
        self.X = self.x.get_public()

        self.B = curve25519.Public(b64decode(self.node['ntor-onion-key']))

        # and generates a client-side handshake with contents:
        #   NODEID      Server identity digest  [ID_LENGTH bytes]
        #   KEYID       KEYID(B)                [H_LENGTH bytes]
        #   CLIENT_PK   X                       [G_LENGTH bytes]
        self.handshake  = b64decode(self.node['identity'])
        self.handshake += self.B.serialize()
        self.handshake += self.X.serialize()

    def complete_handshake(self, Y, auth):
        # The server's handshake reply is:
        # SERVER_PK   Y                       [G_LENGTH bytes]
        # AUTH        H(auth_input, t_mac)    [H_LENGTH bytes]

        # The client then checks Y is in G^* [see NOTE below], and computes

        # secret_input = EXP(Y,x) | EXP(B,x) | ID | B | X | Y | PROTOID
        si  = self.x.get_shared_key(curve25519.Public(Y), hash_func)
        si += self.x.get_shared_key(self.B, hash_func)
        si += b64decode(self.node['identity'])
        si += self.B.serialize()
        si += self.X.serialize()
        si += Y
        si += 'ntor-curve25519-sha256-1'

        # KEY_SEED = H(secret_input, t_key)
        # verify = H(secret_input, t_verify)
        key_seed = hmac(self.t_key, si)
        verify = hmac(self.t_verify, si)

        # auth_input = verify | ID | B | Y | X | PROTOID | "Server"
        ai = verify
        ai += b64decode(self.node['identity'])
        ai += self.B.serialize()
        ai += Y
        ai += self.X.serialize()
        ai += self.protoid
        ai += 'Server'

        # The client verifies that AUTH == H(auth_input, t_mac).
        if auth != hmac(self.t_mac, ai):
            raise NtorError('auth input does not match.')

        # Both parties check that none of the EXP() operations produced the
        # point at infinity. [NOTE: This is an adequate replacement for
        # checking Y for group membership, if the group is curve25519.]

        # Both parties now have a shared value for KEY_SEED.  They expand this
        # into the keys needed for the Tor relay protocol, using the KDF
        # described in 5.2.2 and the tag m_expand.

        # 5.2.2. KDF-RFC5869

        # For newer KDF needs, Tor uses the key derivation function HKDF from
        # RFC5869, instantiated with SHA256.  (This is due to a construction
        # from Krawczyk.)  The generated key material is:

        #     K = K_1 | K_2 | K_3 | ...

        #     Where H(x,t) is HMAC_SHA256 with value x and key t
        #       and K_1     = H(m_expand | INT8(1) , KEY_SEED )
        #       and K_(i+1) = H(K_i | m_expand | INT8(i+1) , KEY_SEED )
        #       and m_expand is an arbitrarily chosen value,
        #       and INT8(i) is a octet with the value "i".

        # In RFC5869's vocabulary, this is HKDF-SHA256 with info == m_expand,
        # salt == t_key, and IKM == secret_input.
        keys = hkdf(key_seed, length=72, info=self.m_expand)

        # When used in the ntor handshake, the first HASH_LEN bytes form the
        # forward digest Df; the next HASH_LEN form the backward digest Db; the
        # next KEY_LEN form Kf, the next KEY_LEN form Kb, and the final
        # DIGEST_LEN bytes are taken as a nonce to use in the place of KH in the
        # hidden service protocol.  Excess bytes from K are discarded.
        Df, Db, Kf, Kb = struct.unpack('>20s20s16s16s', keys)

        # we do what we can with what we've got.
        del self.X
        del self.x
        del self.B
        del key_seed
        del keys
        del verify
        del ai
        del auth
        del si
        del Y

        self.send_digest = Hash(SHA1(), backend=bend)
        self.send_digest.update(Df)
        self.recv_digest = Hash(SHA1(), backend=bend)
        self.recv_digest.update(Db)

        self.encrypt = Cipher(AES(Kf), CTR('\x00' * 16), backend=bend).encryptor()
        self.decrypt = Cipher(AES(Kb), CTR('\x00' * 16), backend=bend).decryptor()

    def get_handshake(self):
        return self.handshake
Exemplo n.º 40
0
def sha_256(ctx, input, output, status):
    digest = Hash(SHA256(), backend=default_backend())
    digest.update(_to_bytes(input))
    data = digest.finalize()
    _write_bytes(output, data)
    return True
Exemplo n.º 41
0
def nc_kdf(shared_secret, kep2, kep3) -> list:
    """
    Return a list of results from the kdf procedure.

    :param shared_secret: bytes
    :param kep2: bytes, sent by the dsc
    :param kep3: bytes, sent by the adv

    :return: list of results

    Kep2 might be containied in a single payload together with Kep1.

    Interesting return values:

        rv[6] = cli2ser_key: dsc (encrypt) --> adv (decrypt)
        rv[8] = ser2cli_key: adv (encrypt) --> dsc (decrypt)
        rv[9] = auth token

    """
    validate_shared_secret("nc_kdf", shared_secret)
    validate_kep2("nc_kdf", kep2)
    validate_kep3("nc_kdf", kep3)

    rv = []

    kdf1 = Hash(SHA256(), backend=default_backend())
    kdf1.update(shared_secret)
    kdf1_out = kdf1.finalize()
    # log.debug("nc_kdf kdf1_out: {}, {}".format(kdf1_out, type(kdf1_out)))
    rv.append(kdf1_out)

    kdf2 = HMAC(NC_STR_UKEY2v1auth, SHA256(), backend=default_backend())
    kdf2.update(kdf1_out)
    kdf2_out = kdf2.finalize()
    # log.debug("nc_kdf kdf2_out: {}, {}".format(kdf2_out, type(kdf2_out)))
    rv.append(kdf2_out)

    kdf3 = HMAC(kdf2_out, SHA256(), backend=default_backend())
    kdf3_inp_hex = kep2[4:].hex() + kep3[4:].hex()
    # log.debug("nc_kdf kdf3_inp_hex: {}, {}".format(kdf3_inp_hex, len(kdf3_inp_hex)))
    kdf3_inp = unhexlify(kdf3_inp_hex)
    # NOTE: heuristic
    assert len(kdf3_inp) == 252 or len(kdf3_inp) == 253 or len(kdf3_inp) == 254
    kdf3.update(kdf3_inp)
    kdf3.update(b'\x01')
    kdf3_out = kdf3.finalize()
    # log.debug("nc_kdf kdf3_out: {}, {}".format(kdf3_out, type(kdf3_out)))
    rv.append(kdf3_out)

    kdf4 = HMAC(NC_STR_UKEY2v1next, SHA256(), backend=default_backend())
    kdf4.update(kdf1_out)
    kdf4_out = kdf4.finalize()
    # log.debug("nc_kdf kdf4_out: {}, {}".format(kdf4_out, type(kdf4_out)))
    rv.append(kdf4_out)

    # NOTE: same inputs of kdf3
    kdf5 = HMAC(kdf4_out, SHA256(), backend=default_backend())
    kdf5.update(kdf3_inp)
    kdf5.update(b'\x01')
    kdf5_out = kdf5.finalize()
    # log.debug("nc_kdf kdf5_out: {}, {}".format(kdf5_out, type(kdf5_out)))
    rv.append(kdf5_out)

    kdf6 = HMAC(NC_KDF_KEY, SHA256(), backend=default_backend())
    kdf6.update(kdf5_out)
    kdf6_out = kdf6.finalize()
    # log.debug("nc_kdf kdf6_out: {}, {}".format(kdf6_out, type(kdf6_out)))
    rv.append(kdf6_out)

    # NOTE: computes cli2ser_key
    kdf7 = HMAC(kdf6_out, SHA256(), backend=default_backend())
    kdf7.update(NC_STR_CLIENT)
    kdf7.update(b'\x01')
    kdf7_out = kdf7.finalize()
    # log.debug("nc_kdf kdf7_out: {}, {}".format(kdf7_out, type(kdf7_out)))
    cli2ser_key = kdf7_out
    log.debug("nc_kdf cli2ser_key: {}, {}".format(kdf7_out, len(kdf7_out)))
    rv.append(kdf7_out)

    # NOTE: same as kdf6
    kdf8 = HMAC(NC_KDF_KEY, SHA256(), backend=default_backend())
    kdf8.update(kdf5_out)
    kdf8_out = kdf8.finalize()
    # log.debug("nc_kdf kdf8_out: {}, {}".format(kdf8_out, type(kdf8_out)))
    rv.append(kdf8_out)

    # NOTE: computes ser2cli_key
    kdf9 = HMAC(kdf8_out, SHA256(), backend=default_backend())
    kdf9.update(NC_STR_SERVER)
    kdf9.update(b'\x01')
    kdf9_out = kdf9.finalize()
    # log.debug("nc_kdf kdf9_out: {}, {}".format(kdf9_out, type(kdf9_out)))
    ser2cli_key = kdf9_out
    log.debug("nc_kdf ser2cli_key: {}, {}".format(kdf9_out, len(kdf9_out)))
    rv.append(kdf9_out)

    # NOTE: computes auth token from kdf3_out
    r_auth_token = b64encode(kdf3_out)[:5]
    auth_token = r_auth_token.decode('utf-8').upper()
    assert len(auth_token) == 5
    log.debug("nc_kdf auth_token: {}, {}".format(auth_token, len(auth_token)))
    rv.append(auth_token)

    return rv
Exemplo n.º 42
0
 def derive_secret(self, secret, label, messages):
     h = Hash(self.hash, backend=default_backend())
     h.update(messages)
     hash_messages = h.finalize()
     hash_len = self.hash.digest_size
     return self.expand_label(secret, label, hash_messages, hash_len)
Exemplo n.º 43
0
               length=288,
               otherinfo=KDF2_input,
               backend=default_backend()).derive(Kz)
Kms2 = KDF2_out[224:256]
Kmp2 = KDF2_out[256:288]

# Remove trailing '=' from base64 encoded values
Np_b64 = Np_b64.strip('=')
Ns_b64 = Ns_b64.strip('=')
Np2_b64 = Np2_b64.strip('=')
Ns2_b64 = Ns2_b64.strip('=')
Noob_b64 = Noob_b64.strip('=')

## NoobId
NoobId_input = Hash(SHA256(), backend=default_backend())
NoobId_input.update(b'NoobId')
NoobId_input.update(Noob_b64.encode())
NoobId = NoobId_input.finalize()[:16]
NoobId_b64 = base64url_encode(NoobId).decode().strip('=')

## Hoob
Hoob_values = loads('{"Hoob":[]}', object_pairs_hook=OrderedDict)
Hoob_values['Hoob'] = [
    Dir, Vers, Verp, PeerId, Cryptosuites, Dirs,
    loads(ServerInfo,
          object_pairs_hook=OrderedDict), Cryptosuitep, Dirp, Realm,
    loads(PeerInfo, object_pairs_hook=OrderedDict), PKs_full, Ns_b64, PKp_full,
    Np_b64, Noob_b64
]
Hoob_input = Hash(SHA256(), backend=default_backend())
Hoob_input.update(dumps(Hoob_values['Hoob'], separators=(',', ':')).encode())
Exemplo n.º 44
0
 def _get_digest(self, data, digest_algorithm):
     hasher = Hash(algorithm=digest_algorithm, backend=default_backend())
     hasher.update(data)
     return ensure_str(b64encode(hasher.finalize()))
Exemplo n.º 45
0
def nc_scapy_pkt(pt_type, fields) -> bytes:
    """
    Generates NC scapy packets,

    :param pt_type: string in NC_PT_TYPES
    :param fields: list content depends on pt_type

    :return: scapy packet

    kep1 fields:
        fields[0]: eid, str
        fields[1]: ncname, str
        fields[2]: strategy, str
        fields[3]: wifi_mode, str

    kep4 fields:
        fields[0]: pri_key, bytes
        fields[1]: pub_key, tuple of bytes

    kep2 fields:
        fields[0]: kep4, bytes

    kep3 fields:
        fields[0]: pri_key, bytes
        fields[1]: pub_key, tuple of bytes

    eka fields:
        fields[0]: key, bytes
        fields[1]: iv, bytes
        fields[2]: count, int

    ewl fields:
        fields[0]: key, bytes
        fields[1]: iv, bytes
        fields[2]: count, int
        fields[3]: ip, list
        fields[4]: tcp_port, bytes

    eha fields:
        fields[0]: key, bytes
        fields[1]: iv, bytes
        fields[2]: count, int
        fields[3]: essid, bytes, 28 or DIRECT-
        fields[4]: password, bytes, 12 or 8
        fields[5]: tcp_port, bytes, 3

    esh fields:
        fields[0]: key, bytes
        fields[1]: iv, bytes
        fields[2]: count, int

    esh2 fields:
        fields[0]: key, bytes
        fields[1]: iv, bytes
        fields[2]: count, int

    pay fields:
        fields[0]: key, bytes
        fields[1]: iv, bytes
        fields[2]: count, int
        fields[3]: pt, bytes
        fields[4]: pid, bytes

    pay2 fields:
        fields[0]: key, bytes
        fields[1]: iv, bytes
        fields[2]: count, int
        fields[3]: pay_len, int
        fields[4]: pid, bytes

    iw fields:
        fields[0]: key, bytes
        fields[1]: iv, bytes
        fields[2]: count, int
        fields[3]: eid, str

    """
    validate_pt_type("nc_scapy_pkt", pt_type)

    rv = b''

    if pt_type == 'kep1':
        eid = fields[0]
        validate_str('nc_scapy_pkt kep1', eid)
        ncname = fields[1]
        validate_str('nc_scapy_pkt kep1', ncname)
        strategy = fields[2]
        validate_strategy('nc_scapy_pkt kep1', strategy)
        wifi_mode = fields[3]
        validate_wifi_mode('nc_scapy_pkt kep1', wifi_mode)

        # NOTE: use only latest version
        if strategy == 'P2P_STAR':
            if wifi_mode == 'hostapd':
                kep1_scapy = SCAPY_KEP1_STAR_HA_TEMPLATE
            elif wifi_mode == 'direct':
                kep1_scapy = SCAPY_KEP1_STAR_WD_TEMPLATE
        elif strategy == 'P2P_CLUSTER':
            kep1_scapy = SCAPY_KEP1_CLUS_TEMPLATE
        kep1_scapy.eid = eid
        kep1_scapy.ncname = ncname
        # NOTE: 4 depends on SCAPY_KEP1_TEMPLATE
        if len(ncname) != 4:
            delta = 4 - len(ncname)
            kep1_scapy.ncname_len = len(ncname)
            kep1_scapy.len1 -= delta
            kep1_scapy.len2 -= delta
            kep1_scapy.len3 -= delta
        # log.debug("nc_scapy_pkt kep1: {}".format(repr(kep1_scapy)))
        # log.debug("nc_scapy_pkt kep1_scapy.name: {}".format(kep1_scapy.name))

        rv = kep1_scapy

    elif pt_type == 'kep4':
        pri_key = fields[0]
        validate_pri_key('nc_scapy_pkt kep4', pri_key)
        pub_key = None
        pub_key = fields[1]

        if pub_key is not None:
            validate_pub_key('nc_scapy_pkt kep4', pub_key)
            # NOTE: not validating if it is in the curve
        else:
            pri_key_int = bytes_to_int(pri_key)
            pub_key_int = scalar_mult(pri_key_int, (EC_XG_INT, EC_YG_INT))
            pub_key = (int_to_bytes(pub_key_int[0]),
                       int_to_bytes(pub_key_int[1]))
            validate_point('nc_scapy_pkt kep4', pub_key)

        xD = pub_key[0]
        yD = pub_key[1]
        # NOTE: preprend \x00 if coordinate starts with 0b1
        if bin(xD[0]).startswith('0b1'):
            xD = b'\x00' + xD
        if bin(yD[0]).startswith('0b1'):
            yD = b'\x00' + yD

        kep4_scapy = SCAPY_KEP4_TEMPLATE
        # NOTE: 32 depends on the SCAPY_KEP4_TEMPLATE
        delta = 32 - len(xD) + 32 - len(yD)
        kep4_scapy.len1 -= delta
        kep4_scapy.len2 -= delta
        kep4_scapy.len3 -= delta
        kep4_scapy.len4 -= delta
        kep4_scapy.xD = xD
        kep4_scapy.xD_len = len(xD)
        kep4_scapy.yD = yD
        kep4_scapy.yD_len = len(yD)
        # log.debug("nc_scapy_pkt kep4_hex: {}".format(raw(kep4_scapy).hex()))

        rv = kep4_scapy

    # NOTE: so far passing constant kdf1 and kdf2
    elif pt_type == 'kep2':
        kep4 = fields[0]
        validate_bytes('nc_scapy_pkt kep2', kep4)

        kep2_scapy = SCAPY_KEP2_TEMPLATE

        kep0 = Hash(SHA512(), backend=default_backend())
        kep0.update(kep4[4:])
        kep2_kdf2 = kep0.finalize()

        kep2_scapy.kdf2 = kep2_kdf2

        rv = kep2_scapy

    elif pt_type == 'kep3':
        pri_key = fields[0]
        validate_pri_key('nc_scapy_pkt kep3', pri_key)
        pub_key = None
        pub_key = fields[1]

        # NOTE: if fields[1] contains a pub_key
        if pub_key is not None:
            validate_pub_key('nc_scapy_pkt kep3', pub_key)
            # NOTE: not validating if it is in the curve
        else:
            pri_key_int = bytes_to_int(pri_key)
            pub_key_int = scalar_mult(pri_key_int, (EC_XG_INT, EC_YG_INT))
            pub_key = (int_to_bytes(pub_key_int[0]),
                       int_to_bytes(pub_key_int[1]))
            validate_point('nc_scapy_pkt kep3', pub_key)

        xA = pub_key[0]
        yA = pub_key[1]
        # NOTE: preprend \x00 if coordinate starts with 0b1
        if bin(xA[0]).startswith('0b1'):
            xA = b'\x00' + xA
        if bin(yA[0]).startswith('0b1'):
            yA = b'\x00' + yA

        # NOTE: kdf field is kept constant so far
        kep3_scapy = SCAPY_KEP3_TEMPLATE
        # NOTE: 32 depends on the SCAPY_KEP3_TEMPLATE
        delta = 32 - len(xA) + 32 - len(yA)
        kep3_scapy.len1 -= delta
        kep3_scapy.len2 -= delta
        kep3_scapy.len3 -= delta
        kep3_scapy.len4 -= delta
        kep3_scapy.xA = xA
        kep3_scapy.xA_len = len(xA)
        kep3_scapy.yA = yA
        kep3_scapy.yA_len = len(yA)
        # log.debug("nc_scapy_pkt kep3_hex: {}".format(raw(kep3_scapy).hex()))

        rv = kep3_scapy

    elif pt_type == 'eka':
        key = fields[0]
        validate_aes256_key("nc_scapy_pkt eka", key)
        iv = fields[1]
        validate_iv("nc_scapy_pkt eka", iv)
        count = fields[2]
        validate_int("nc_scapy_pkt eka", count)

        pt_scapy = SCAPY_KA_TEMPLATE
        pt_scapy.count = count
        pt = raw(pt_scapy)
        # log.debug("nc_scapy_pkt eka pt_hex: {} {}, count {}".format(pt.hex(),
        #     len(pt.hex()), count))
        ct = nc_encrypt(key, pt, iv)[2]
        mac = nc_mac(key, ct, iv, pt_type)[2]

        eka_scapy = SCAPY_EKA_TEMPLATE
        eka_scapy.iv = iv
        eka_scapy.ct = ct
        eka_scapy.mac = mac

        rv = eka_scapy

    elif pt_type == 'ewl':
        key = fields[0]
        validate_aes256_key("nc_scapy_pkt ewl", key)
        iv = fields[1]
        validate_iv("nc_scapy_pkt ewl", iv)
        count = fields[2]
        validate_int("nc_scapy_pkt ewl", count)
        ip = fields[3]
        validate_ip("nc_scapy_pkt ewl", ip)

        wl_scapy = SCAPY_WL_TEMPLATE
        wl_scapy.count = count
        wl_scapy.ip = ip
        if fields[4] == None:
            # NOTE: use the tcp_port from the template
            pass
        else:
            tcp_port = fields[4]
            validate_tcp_port("nc_scapy_pkt ewl", tcp_port)
            wl_scapy.tcp_port = tcp_port
        pt = raw(wl_scapy)
        ct = nc_encrypt(key, pt, iv)[2]
        mac = nc_mac(key, ct, iv, pt_type)[2]

        # NOTE: similar to eka_scapy
        ewl_scapy = SCAPY_EWL_TEMPLATE
        ewl_scapy.iv = iv
        ewl_scapy.ct = ct
        ewl_scapy.mac = mac

        rv = ewl_scapy

    elif pt_type == 'eha':
        key = fields[0]
        validate_aes256_key("nc_scapy_pkt eha", key)
        iv = fields[1]
        validate_iv("nc_scapy_pkt eha", iv)
        count = fields[2]
        validate_int("nc_scapy_pkt eha", count)
        essid = fields[3]
        validate_essid("nc_scapy_pkt eha", essid)
        password = fields[4]
        validate_password("nc_scapy_pkt eha", password)

        ha_scapy = SCAPY_HA_TEMPLATE
        ha_scapy.count = count
        ha_scapy.essid = essid
        ha_scapy.password = password
        if fields[5] == None:
            # NOTE: use the tcp_port from the template
            pass
        else:
            tcp_port = fields[5]
            validate_tcp_port("nc_scapy_pkt eha", tcp_port)
            ha_scapy.tcp_port = tcp_port
        pt = raw(ha_scapy)
        ct = nc_encrypt(key, pt, iv)[2]
        mac = nc_mac(key, ct, iv, pt_type)[2]

        # NOTE: similar to eka_scapy
        eha_scapy = SCAPY_EHA_TEMPLATE
        eha_scapy.iv = iv
        eha_scapy.ct = ct
        eha_scapy.mac = mac

        rv = eha_scapy

    elif pt_type == 'esh':
        key = fields[0]
        validate_aes256_key("nc_scapy_pkt esh", key)
        iv = fields[1]
        validate_iv("nc_scapy_pkt esh", iv)
        count = fields[2]
        validate_int("nc_scapy_pkt esh", count)

        sh_scapy = SCAPY_SH_TEMPLATE
        sh_scapy.count = count
        pt = raw(sh_scapy)
        ct = nc_encrypt(key, pt, iv)[2]
        mac = nc_mac(key, ct, iv, pt_type)[2]

        esh_scapy = SCAPY_EKA_TEMPLATE
        esh_scapy.iv = iv
        esh_scapy.ct = ct
        esh_scapy.mac = mac

        rv = esh_scapy

    elif pt_type == 'esh2':
        key = fields[0]
        validate_aes256_key("nc_scapy_pkt esh2", key)
        iv = fields[1]
        validate_iv("nc_scapy_pkt esh2", iv)
        count = fields[2]
        validate_int("nc_scapy_pkt esh2", count)

        sh2_scapy = SCAPY_SH2_TEMPLATE
        sh2_scapy.count = count
        pt = raw(sh2_scapy)
        ct = nc_encrypt(key, pt, iv)[2]
        mac = nc_mac(key, ct, iv, pt_type)[2]

        esh2_scapy = SCAPY_EKA_TEMPLATE
        esh2_scapy.iv = iv
        esh2_scapy.ct = ct
        esh2_scapy.mac = mac

        rv = esh2_scapy

    elif pt_type == 'pay':
        key = fields[0]
        validate_aes256_key("nc_scapy_pkt pay", key)
        iv = fields[1]
        validate_iv("nc_scapy_pkt pay", iv)
        count = fields[2]
        validate_int("nc_scapy_pkt pay", count)
        pay = fields[3]
        validate_bytes("nc_scapy_pkt pay", pay)
        # pid = fields[4]
        # validate_bytes("nc_scapy_pkt pay", pid)

        # NOTE: uses Pt class
        pt_scapy = SCAPY_PT_TEMPLATE
        # NOTE: 4 depends on SCAPY_PT_TEMPLATE
        if len(pay) != 4:
            delta = 4 - len(pay)
            pt_scapy.len1 -= delta
            pt_scapy.len2 -= delta
            pt_scapy.len3 -= delta
            pt_scapy.pt_len = len(pay)
            pt_scapy.len4 -= delta
            pt_scapy.pay_len = len(pay)
        pt_scapy.pay = pay
        pt_scapy.count = count
        # log.debug("nc_scapy_pkt pt: {}".format(repr(pt_scapy)))

        pt = raw(pt_scapy)
        log.debug("nc_scapy_pkt pt_hex: {}".format(pt.hex()))
        ct = nc_encrypt(key, pt, iv)[2]
        mac = nc_mac(key, ct, iv, pt_type)[2]

        # NOTE: len fields should not be affected by len(Pt)
        pay_scapy = SCAPY_PAY_TEMPLATE
        pay_scapy.iv = iv
        pay_scapy.ct = ct
        pay_scapy.mac = mac

        rv = pay_scapy

    elif pt_type == 'pay2':
        key = fields[0]
        validate_aes256_key("nc_scapy_pkt pay2", key)
        iv = fields[1]
        validate_iv("nc_scapy_pkt pay2", iv)
        count = fields[2]
        validate_int("nc_scapy_pkt pay2", count)
        pay_len = fields[3]  # this is the len of Pt (not Pt2)
        validate_int("nc_scapy_pkt pay2", pay_len)
        # pid = fields[4]
        # validate_bytes("nc_scapy_pkt pay2", pid)

        # NOTE: uses Pt2 class
        pt2_scapy = SCAPY_PT2_TEMPLATE
        if pay_len != 4:
            delta = 4 - pay_len
            pt2_scapy.pt_len = pay_len
            pt2_scapy.pt_len2 = pay_len
        pt2_scapy.count = count
        # log.debug("nc_scapy_pkt pt2: {}".format(repr(pt2_scapy)))

        pt = raw(pt2_scapy)
        log.debug("nc_scapy_pkt pt2_hex: {}".format(pt.hex()))
        # log.debug("nc_scapy_pkt pay pt_hex: {} {}, count {}".format(pt.hex(),
        #     len(pt.hex()), count))
        ct = nc_encrypt(key, pt, iv)[2]
        mac = nc_mac(key, ct, iv, pt_type)[2]

        pay2_scapy = SCAPY_PAY2_TEMPLATE
        pay2_scapy.iv = iv
        pay2_scapy.ct = ct
        pay2_scapy.mac = mac

        rv = pay2_scapy

    # NOTE: not encrypted, key and iv not used
    elif pt_type == 'iw':
        key = fields[0]
        validate_aes256_key("nc_scapy_pkt iw", key)
        iv = fields[1]
        validate_iv("nc_scapy_pkt iw", iv)
        count = fields[2]
        validate_int("nc_scapy_pkt iw", count)
        eid = eid[2]
        validate_str("nc_scapy_pkt iw", eid)

        iw_scapy = SCAPY_IW_TEMPLATE
        iw_scapy.count = count
        iw_scapy.eid = eid
        pt = raw(iw_scapy)
        # log.debug("nc_scapy_pkt iw pt_hex: {} {}, count {}".format(pt.hex(),
        #     len(pt.hex()), count))

        rv = iw_scapy

    else:
        log.error('nc_scapy_pkt: pt_type {} not managed.'.format(pt_type))

    return rv