def test_ciphers(self):
        backend = MultiBackend([
            DummyHashBackend([]),
            DummyCipherBackend([
                (algorithms.AES, modes.CBC),
            ])
        ])
        assert backend.cipher_supported(
            algorithms.AES(b"\x00" * 16), modes.CBC(b"\x00" * 16)
        )

        cipher = Cipher(
            algorithms.AES(b"\x00" * 16),
            modes.CBC(b"\x00" * 16),
            backend=backend
        )
        cipher.encryptor()
        cipher.decryptor()

        cipher = Cipher(
            algorithms.Camellia(b"\x00" * 16),
            modes.CBC(b"\x00" * 16),
            backend=backend
        )
        with pytest.raises(UnsupportedCipher):
            cipher.encryptor()
        with pytest.raises(UnsupportedCipher):
            cipher.decryptor()
Exemple #2
0
    def __init__(self,
                 remote: Node,
                 privkey: datatypes.PrivateKey,
                 reader: asyncio.StreamReader,
                 writer: asyncio.StreamWriter,
                 aes_secret: bytes,
                 mac_secret: bytes,
                 egress_mac: PreImage,
                 ingress_mac: PreImage,
                 chaindb: AsyncChainDB,
                 network_id: int,
                 ) -> None:
        self._finished = asyncio.Event()
        self.remote = remote
        self.privkey = privkey
        self.reader = reader
        self.writer = writer
        self.base_protocol = P2PProtocol(self)
        self.chaindb = chaindb
        self.network_id = network_id
        self.sub_proto_msg_queue = asyncio.Queue()  # type: asyncio.Queue[Tuple[protocol.Command, protocol._DecodedMsgType]]  # noqa: E501
        self.cancel_token = CancelToken('Peer')

        self.egress_mac = egress_mac
        self.ingress_mac = ingress_mac
        # FIXME: Yes, the encryption is insecure, see: https://github.com/ethereum/devp2p/issues/32
        iv = b"\x00" * 16
        aes_cipher = Cipher(algorithms.AES(aes_secret), modes.CTR(iv), default_backend())
        self.aes_enc = aes_cipher.encryptor()
        self.aes_dec = aes_cipher.decryptor()
        mac_cipher = Cipher(algorithms.AES(mac_secret), modes.ECB(), default_backend())
        self.mac_enc = mac_cipher.encryptor().update
    def test_ciphers(self):
        backend = MultiBackend([
            DummyHashBackend([]),
            DummyCipherBackend([
                (algorithms.AES, modes.CBC),
            ])
        ])
        assert backend.cipher_supported(
            algorithms.AES(b"\x00" * 16), modes.CBC(b"\x00" * 16)
        )

        cipher = Cipher(
            algorithms.AES(b"\x00" * 16),
            modes.CBC(b"\x00" * 16),
            backend=backend
        )
        cipher.encryptor()
        cipher.decryptor()

        cipher = Cipher(
            algorithms.Camellia(b"\x00" * 16),
            modes.CBC(b"\x00" * 16),
            backend=backend
        )
        with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER):
            cipher.encryptor()
        with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER):
            cipher.decryptor()
 def test_nonexistent_aead_cipher(self):
     from cryptography.hazmat.backends.commoncrypto.backend import Backend
     b = Backend()
     cipher = Cipher(
         DummyCipher(), GCM(b"fake_iv_here"), backend=b,
     )
     with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER):
         cipher.encryptor()
Exemple #5
0
    def test_nonexistent_cipher(self, backend, mode):
        cipher = Cipher(
            DummyCipher(), mode, backend
        )
        with pytest.raises(UnsupportedCipher):
            cipher.encryptor()

        with pytest.raises(UnsupportedCipher):
            cipher.decryptor()
    def test_nonexistent_cipher(self, backend):
        cipher = Cipher(
            DummyCipher(), object(), backend
        )
        with pytest.raises(UnsupportedAlgorithm):
            cipher.encryptor()

        with pytest.raises(UnsupportedAlgorithm):
            cipher.decryptor()
Exemple #7
0
    def test_nonexistent_cipher(self, backend, mode):
        cipher = Cipher(
            DummyCipherAlgorithm(), mode, backend
        )
        with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER):
            cipher.encryptor()

        with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER):
            cipher.decryptor()
 def test_nonexistent_cipher(self):
     b = Backend()
     b.register_cipher_adapter(
         DummyCipher,
         DummyMode,
         lambda backend, cipher, mode: backend.ffi.NULL
     )
     cipher = Cipher(
         DummyCipher(), DummyMode(), backend=b,
     )
     with pytest.raises(UnsupportedAlgorithm):
         cipher.encryptor()
Exemple #9
0
 def test_nonexistent_cipher(self, mode):
     b = Backend()
     b.register_cipher_adapter(
         DummyCipherAlgorithm,
         type(mode),
         lambda backend, cipher, mode: backend._ffi.NULL
     )
     cipher = Cipher(
         DummyCipherAlgorithm(), mode, backend=b,
     )
     with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER):
         cipher.encryptor()
 def test_nonexistent_cipher(self, mode):
     b = Backend()
     b.register_cipher_adapter(
         DummyCipher,
         type(mode),
         lambda backend, cipher, mode: backend._ffi.NULL
     )
     cipher = Cipher(
         DummyCipher(), mode, backend=b,
     )
     with pytest.raises(UnsupportedCipher):
         cipher.encryptor()
Exemple #11
0
def encrypt_data(data,key,iv=g.aesctr_dfl_iv,desc='data',verify=True):
	vmsg('Encrypting {}'.format(desc))
	c = Cipher(algorithms.AES(key),modes.CTR(iv),backend=default_backend())
	encryptor = c.encryptor()
	enc_data = encryptor.update(data) + encryptor.finalize()

	if verify:
		vmsg_r('Performing a test decryption of the {}...'.format(desc))
		c = Cipher(algorithms.AES(key),modes.CTR(iv),backend=default_backend())
		encryptor = c.encryptor()
		dec_data = encryptor.update(enc_data) + encryptor.finalize()
		if dec_data != data:
			die(2,"ERROR.\nDecrypted {s} doesn't match original {s}".format(s=desc))
		vmsg('done')

	return enc_data
Exemple #12
0
class CipherShim:
    def __init__(self, cipher, mode, block_size, key, iv, initial_bytes):
        if mode:
            mode = mode(iv)

        self._cipher = Cipher(cipher(key), mode, default_backend())
        self._initial_bytes = initial_bytes
        self._encryptor = None
        self._decryptor = None

        self.block_size = block_size

    def encrypt(self, data):
        if not self._encryptor:
            self._encryptor = self._cipher.encryptor()

            if self._initial_bytes:
                self._encryptor.update(self._initial_bytes * b'\0')

        return self._encryptor.update(data)

    def decrypt(self, data):
        if not self._decryptor:
            self._decryptor = self._cipher.decryptor()

            if self._initial_bytes:
                self._decryptor.update(self._initial_bytes * b'\0')

        return self._decryptor.update(data)
Exemple #13
0
def get_cipher(key, method, op, iv):
    if method == 'bypass':
        return bypass()
    if method in ('salsa20', 'chacha20', 'chacha20-ietf'):
        return Salsa20Crypto(method, key, iv, op)
    elif method == 'rc4-md5':
        md5 = hashlib.md5()
        md5.update(key)
        md5.update(iv)
        key = md5.digest()
        method = 'rc4'
    cipher = None

    if method.startswith('rc4'):
        pass
    elif method.endswith('ctr'):
        mode = modes.CTR(iv)
    elif method.endswith('ofb'):
        mode = modes.OFB(iv)
    elif method.endswith('cfb'):
        mode = modes.CFB(iv)
    else:
        raise ValueError('operation mode "%s" not supported!' % method.upper())

    if method.startswith('rc4'):
        cipher = Cipher(algorithms.ARC4(key), None, default_backend())
    elif method.startswith('aes'):
        cipher = Cipher(algorithms.AES(key), mode, default_backend())
    elif method.startswith('camellia'):
        cipher = Cipher(algorithms.Camellia(key), mode, default_backend())
    else:
        raise ValueError('crypto algorithm "%s" not supported!' % method.upper())

    return cipher.encryptor() if op else cipher.decryptor()
 def encryptData(self, dataS, iv):
     self.data = str(dataS).encode()
     self.iv = iv
     cipher = Cipher(algorithms.AES(self.key), modes.CTR(self.iv), backend=self.backend)
     encryptor = cipher.encryptor()
     self.encryptedData = encryptor.update(self.data) + encryptor.finalize()
     return self.encryptedData
Exemple #15
0
 def encyptUsingSymetricKey(self, key, iv, data):
     print "Using shared key to encrypt data"
     backend = default_backend()
     cipher = Cipher(algorithms.AES(key), modes.CFB8(iv), backend=backend)
     encryptor = cipher.encryptor()
     ct = encryptor.update(data) + encryptor.finalize()
     return ct
Exemple #16
0
    def encrypt(self, plaintext):
        '''
        This encrypt constructor takes the plaintext string, sends it to the
        preProcess class to be padded and chunked. The blocks are then
        encrypted using python cryptography library ECB mode. The chaining
        of ciphertexts is done manually.
        '''
        # Send the plaintext string to be padded and chunked
        plaintext = self.preProcess(plaintext)

        # Initilize the python cryptography ECB mode
        backend = default_backend()
        cipher = Cipher(algorithms.AES(self.key), modes.ECB(),
                backend = backend)
        encryptor = cipher.encryptor()
        
        # Loop through the elements, special treatment for block 1
        # https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
        ciphertextList = []
        for i in range(0, len(plaintext)):
            if (i == 0):
                xor = xorData(self.iv, plaintext[i])
                initialXor = xor.getXor() 
                firstElement = encryptor.update(initialXor)
                ciphertextList.append(firstElement)
            elif (i >= 1):
                xor = xorData(ciphertextList[i-1], plaintext[i])
                nElementXor = xor.getXor()
                nEncryption = encryptor.update(nElementXor)
                ciphertextList.append(nEncryption)
        return ''.join(ciphertextList)
Exemple #17
0
def CBC_MAC(key, iv, padded):
    cipher = Cipher(algorithm = algorithms.AES(key), mode = modes.CBC(iv), backend=default_backend())
    enc = cipher.encryptor()

    ciphertext = enc.update(padded) + enc.finalize()
    mac = ciphertext[-16:]
    return mac
Exemple #18
0
    def encrypt_payload(self, key, source_path, chunksize=CHUNKSIZE):
        archive = tarfile.open(self.payload, mode='w:gz')
        archive.add(source_path, arcname=os.path.basename(source_path))
        archive.close()

        iv = b''.join(int2byte(random.randint(0, 0xFF)) for i in range(16))
        backend = default_backend()
        cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
        encryptor = cipher.encryptor()
        origsize = os.path.getsize(self.payload)

        with open(self.payload, 'rb') as infile:
            with open(self.enc_payload, 'wb') as outfile:
                outfile.write(iv)

                # store the file size with the encrypted data
                outfile.write(encryptor.update(struct.pack('<QQ', origsize, 0)))
                while True:
                    chunk = infile.read(chunksize)
                    if len(chunk) == 0:
                        break
                    elif len(chunk) % 16 != 0:
                        chunk += b' ' * (16 - len(chunk) % 16)

                    outfile.write(encryptor.update(chunk))
                outfile.write(encryptor.finalize())
Exemple #19
0
class CommutativeCipher:
    """
    Encryption and decryption using a commutative cipher.
    """
    def __init__(self):
        key = os.urandom(32)
        iv = os.urandom(16)
        self.cipher = Cipher(algorithms.AES(key), modes.OFB(iv), backend=default_backend())


    def encrypt(self, plaintext, base64=False):
        """
        Encrypts a plaintext message and returns base 64 encoded ciphertext.
        If base64 is specified, decodes from base64 first.
        """
        plaintext = plaintext.encode(ENCODING)
        if base64: plaintext = decodebytes(plaintext)

        encryptor = self.cipher.encryptor()
        ciphertext = encryptor.update(plaintext) + encryptor.finalize()
        return encodebytes(ciphertext).decode(ENCODING)

    def decrypt(self, ciphertext, base64=False):
        """
        Decrypts base 64 encoded ciphertext and returns the plaintext message.

        If base64 is specified, provides result base64 encoded.
        """
        ciphertext = decodebytes(ciphertext.encode(ENCODING))

        decryptor = self.cipher.decryptor()
        plaintext = decryptor.update(ciphertext) + decryptor.finalize()

        if base64: plaintext = encodebytes(plaintext)
        return plaintext.decode(ENCODING)
Exemple #20
0
    def encrypt(self, plaintext):
        '''
        This encrypt constructor takes the plaintext string, sends it to the
        preProcess class to be padded and chunked. The blocks are then
        encrypted using python cryptography library ECB mode.
        Note: OFB does not normally use padding. See issue #12.
        '''
        # Send the plaintext string to be padded and chunked
        plaintext = self.preProcess(plaintext)

        # Initilize the python cryptography ECB mode
        backend = default_backend()
        cipher = Cipher(algorithms.AES(self.key), modes.ECB(),
                backend = backend)
        encryptor = cipher.encryptor()

        ciphertextList = []
        tmpBlockList = []
        # Loop through the plaintext elements, return ciphertext string
        for i in range(0, len(plaintext)):
            if (i == 0):
                firstBlock = encryptor.update(self.iv)
                tmpBlockList.append(firstBlock)
                xor = xorData(tmpBlockList[i], plaintext[i])
                firstElement = xor.getXor()
                ciphertextList.append(firstElement)
            elif (i >= 1):
                nBlock = encryptor.update(tmpBlockList[i-1])
                tmpBlockList.append(nBlock)
                xor = xorData(tmpBlockList[i], plaintext[i])
                nElement = xor.getXor()
                ciphertextList.append(nElement)
        return ''.join(ciphertextList)
Exemple #21
0
def cli(filename):
    """Send file over to server"""
    s = socket.socket()

    host = '172.30.7.187'
    port = 4567

    click.echo(click.style('Connecting...', bold = True, fg = 'yellow'))
    try:
        s.connect((host, port))
    except socket.error as msg:
        click.echo(click.style('Error connecting to server: ' + str(msg[1]), bold = True, fg = 'red'))

    pt = b""
    while True:
        chunk = filename.read(100)
        if not chunk:
            break
        pt += chunk

    key = open("key.txt", "rb").read(16)
    cipher = Cipher(algorithms.ARC4(key), mode=None, backend=default_backend())
    encryptor = cipher.encryptor()
    ct = encryptor.update(pt)

    s.send(ct)
    s.close()

    click.echo(click.style('File sent!', bold = True, fg = 'green'))
Exemple #22
0
    def encrypt(self, public_key_unserialized, data):
        self.debug("encrypting data...")
        self.debug("encryption public key is: \n" + str(public_key_unserialized))

        public_key = self.serialize_key(public_key_unserialized, "public")

        hash_length = 16  # length of cryptographic hash in bytes
        symkey = os.urandom(hash_length)  # generate a random symmetric key
        iv = os.urandom(hash_length)  # generate an initialization vector

        # Pad the data then encrypt using 128-bit AES-CBC
        data_padded = self.enpad(data, hash_length)
        cipher = Cipher(algorithms.AES(symkey), modes.CBC(iv), backend=default_backend())
        encryptor = cipher.encryptor()
        data_encrypted = encryptor.update(data_padded) + encryptor.finalize()

        # Encrypt the symmetric key using the public key
        symkey_encrypted = public_key.encrypt(
            symkey + iv, padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), label=None)
        )

        # Append encrypted symmetric key to the encrypted data
        ciphertext = symkey_encrypted + data_encrypted

        # # Sign the data and append signature to ciphertext
        # signature = self.signature_sign(ciphertext, private_key)
        # ciphertext_signed = signature + ciphertext

        self.debug("contents successfully encrypted.")

        return ciphertext
Exemple #23
0
def cryptography_symmetric_encrypt(encrypt_key, plaintext):
    """
    Encrypt the provided plaintext using AES encryption.

    NOTE 1: This function return a string which is fully compatible with Keyczar.Encrypt() method.

    NOTE 2: This function is loosely based on keyczar AESKey.Encrypt() (Apache 2.0 license).

    The final encrypted string value consists of:

    [message bytes][HMAC signature bytes for the message] where message consists of
    [keyczar header plaintext][IV bytes][ciphertext bytes]

    NOTE: Header itself is unused, but it's added so the format is compatible with keyczar format.

    """
    assert isinstance(encrypt_key, AESKey), 'encrypt_key needs to be AESKey class instance'
    assert isinstance(plaintext, (six.text_type, six.string_types, six.binary_type)), \
        'plaintext needs to either be a string/unicode or bytes'

    aes_key_bytes = encrypt_key.aes_key_bytes
    hmac_key_bytes = encrypt_key.hmac_key_bytes

    assert isinstance(aes_key_bytes, six.binary_type)
    assert isinstance(hmac_key_bytes, six.binary_type)

    if isinstance(plaintext, (six.text_type, six.string_types)):
        # Convert data to bytes
        data = plaintext.encode('utf-8')
    else:
        data = plaintext

    # Pad data
    data = pkcs5_pad(data)

    # Generate IV
    iv_bytes = os.urandom(KEYCZAR_AES_BLOCK_SIZE)

    backend = default_backend()
    cipher = Cipher(algorithms.AES(aes_key_bytes), modes.CBC(iv_bytes), backend=backend)
    encryptor = cipher.encryptor()

    # NOTE: We don't care about actual Keyczar header value, we only care about the length (5
    # bytes) so we simply add 5 0's
    header_bytes = b'00000'

    ciphertext_bytes = encryptor.update(data) + encryptor.finalize()
    msg_bytes = header_bytes + iv_bytes + ciphertext_bytes

    # Generate HMAC signature for the message (header + IV + ciphertext)
    h = hmac.HMAC(hmac_key_bytes, hashes.SHA1(), backend=backend)
    h.update(msg_bytes)
    sig_bytes = h.finalize()

    result = msg_bytes + sig_bytes

    # Convert resulting byte string to hex notation ASCII string
    result = binascii.hexlify(result).upper()

    return result
 def test_unknown_error_in_cipher_finalize(self):
     cipher = Cipher(AES(b"\0" * 16), CBC(b"\0" * 16), backend=backend)
     enc = cipher.encryptor()
     enc.update(b"\0")
     backend._lib.ERR_put_error(0, 0, 1, b"test_openssl.py", -1)
     with pytest.raises(InternalError):
         enc.finalize()
Exemple #25
0
		def encrypt_worker(wid):
			ctr_init_val = os.urandom(g.aesctr_iv_len)
			c = Cipher(algorithms.AES(key),modes.CTR(ctr_init_val),backend=default_backend())
			encryptor = c.encryptor()
			while True:
				q2.put(encryptor.update(q1.get()))
				q1.task_done()
Exemple #26
0
def _aes_encrypt(key, iv, data, aead=''):
    backend = default_backend()
    cipher = Cipher(algorithms.AES(key), modes.GCM(iv), backend=backend)
    encryptor = cipher.encryptor()
    if aead:
        encryptor.authenticate_additional_data(aead)
    return encryptor.update(data) + encryptor.finalize(), encryptor.tag
Exemple #27
0
def aead_exception_test(backend, cipher_factory, mode_factory):
    cipher = Cipher(
        cipher_factory(binascii.unhexlify(b"0" * 32)),
        mode_factory(binascii.unhexlify(b"0" * 24)),
        backend
    )
    encryptor = cipher.encryptor()
    encryptor.update(b"a" * 16)
    with pytest.raises(NotYetFinalized):
        encryptor.tag
    with pytest.raises(AlreadyUpdated):
        encryptor.authenticate_additional_data(b"b" * 16)
    encryptor.finalize()
    with pytest.raises(AlreadyFinalized):
        encryptor.authenticate_additional_data(b"b" * 16)
    with pytest.raises(AlreadyFinalized):
        encryptor.update(b"b" * 16)
    with pytest.raises(AlreadyFinalized):
        encryptor.finalize()
    cipher = Cipher(
        cipher_factory(binascii.unhexlify(b"0" * 32)),
        mode_factory(binascii.unhexlify(b"0" * 24), b"0" * 16),
        backend
    )
    decryptor = cipher.decryptor()
    decryptor.update(b"a" * 16)
    with pytest.raises(AttributeError):
        decryptor.tag
Exemple #28
0
    def encrypt(keyBits, plainData, params):
        """
        Encrypt the plainData using the keyBits according the encrypt params.

        :param Blob keyBits: The key value.
        :param Blob plainData: The data to encrypt.
        :param EncryptParams params: This encrypts according to
          params.getAlgorithmType() and other params as needed such as
          params.getInitialVector().
        :return: The encrypted data.
        :rtype: Blob
        """
        # For the cryptography package, we have to do the padding.
        padLength = 16 - (plainData.size() % 16)
        if sys.version_info[0] <= 2:
            pad = chr(padLength) * padLength
        else:
            pad = bytes([padLength]) * padLength

        if params.getAlgorithmType() == EncryptAlgorithmType.AesEcb:
            cipher = Cipher(algorithms.AES(
              keyBits.toBytes()), modes.ECB(), backend = default_backend())
        elif params.getAlgorithmType() == EncryptAlgorithmType.AesCbc:
            cipher = Cipher(algorithms.AES(
              keyBits.toBytes()), modes.CBC(params.getInitialVector().toBytes()),
              backend = default_backend())
        else:
            raise RuntimeError("unsupported encryption mode")

        encryptor = cipher.encryptor()
        return Blob(
          encryptor.update(plainData.toBytes() + pad) + encryptor.finalize(),
          False)
Exemple #29
0
 def test_creates_encryptor(self, backend):
     cipher = Cipher(
         algorithms.AES(binascii.unhexlify(b"0" * 32)),
         modes.CBC(binascii.unhexlify(b"0" * 32)),
         backend
     )
     assert isinstance(cipher.encryptor(), base.CipherContext)
Exemple #30
0
    def encrypt(self, k, a, m):
        """ Encrypt according to the selected encryption and hashing
        functions.

        :param k: Encryption key (optional)
        :param a: Additional Authentication Data
        :param m: Plaintext

        Returns a dictionary with the computed data.
        """
        hkey = k[:self.keysize]
        ekey = k[self.keysize:]

        # encrypt
        iv = os.urandom(self.blocksize // 8)
        cipher = Cipher(algorithms.AES(ekey), modes.CBC(iv),
                        backend=self.backend)
        encryptor = cipher.encryptor()
        padder = PKCS7(self.blocksize).padder()
        padded_data = padder.update(m) + padder.finalize()
        e = encryptor.update(padded_data) + encryptor.finalize()

        # mac
        t = self._mac(hkey, a, iv, e)

        return (iv, e, t)
Exemple #31
0
class GLSecureTemporaryFile(_TemporaryFileWrapper):
    """
    WARNING!
    You can't use this File object like a normal file object,
    check .read and .write!
    """

    last_action = 'init'

    def __init__(self, filedir):
        """
        filedir: dir target to keep GL.
        """

        self.create_key()

        # XXX remind enhance file name with incremental number
        self.filepath = os.path.join(filedir, "%s.aes" % self.key_id)

        log.debug("++ Creating %s filetmp" % self.filepath)

        self.file = open(self.filepath, 'w+b')

        # last argument is 'True' because the file has to be deleted on .close()
        _TemporaryFileWrapper.__init__(self, self.file, self.filepath, True)

    def initialize_cipher(self):
        self.cipher = Cipher(algorithms.AES(self.key),
                             modes.CTR(self.key_counter_nonce),
                             backend=crypto_backend)
        self.encryptor = self.cipher.encryptor()
        self.decryptor = self.cipher.decryptor()

    def create_key(self):
        """
        Create the AES Key to encrypt uploaded file.
        """
        self.key = os.urandom(GLSetting.AES_key_size)

        self.key_id = xeger(GLSetting.AES_key_id_regexp)
        self.keypath = os.path.join(
            GLSetting.ramdisk_path,
            "%s%s" % (GLSetting.AES_keyfile_prefix, self.key_id))

        while os.path.isfile(self.keypath):
            self.key_id = xeger(GLSetting.AES_key_id_regexp)
            self.keypath = os.path.join(
                GLSetting.ramdisk_path,
                "%s%s" % (GLSetting.AES_keyfile_prefix, self.key_id))

        self.key_counter_nonce = os.urandom(GLSetting.AES_counter_nonce)
        self.initialize_cipher()

        saved_struct = {
            'key': self.key,
            'key_counter_nonce': self.key_counter_nonce
        }

        log.debug("Key initialization at %s" % self.keypath)

        with open(self.keypath, 'w') as kf:
            pickle.dump(saved_struct, kf)

        if not os.path.isfile(self.keypath):
            log.err("Unable to write keyfile %s" % self.keypath)
            raise Exception("Unable to write keyfile %s" % self.keypath)

    def avoid_delete(self):
        log.debug("Avoid delete on: %s " % self.filepath)
        self.delete = False

    def write(self, data):
        """
        The last action is kept track because the internal status
        need to track them. read below read()
        """

        assert (self.last_action != 'read'), "you can write after read!"

        self.last_action = 'write'
        try:
            if isinstance(data, unicode):
                data = data.encode('utf-8')

            self.file.write(self.encryptor.update(data))
        except Exception as wer:
            log.err("Unable to write() in GLSecureTemporaryFile: %s" %
                    wer.message)
            raise wer

    def close(self):
        if any(x in self.file.mode for x in 'wa') and not self.close_called:
            self.file.write(self.encryptor.finalize())
        return _TemporaryFileWrapper.close(self)

    def read(self, c=None):
        """
        The first time 'read' is called after a write, is automatically seek(0)
        """
        if self.last_action == 'write':
            self.seek(0, 0)  # this is a trick just to misc write and read
            self.initialize_cipher()
            log.debug("First seek on %s" % self.filepath)
            self.last_action = 'read'

        if c is None:
            return self.decryptor.update(self.file.read())
        else:
            return self.decryptor.update(self.file.read(c))
Exemple #32
0
class QA_TTSBroker(QA_Broker):
    def __init__(self, endpoint="http://127.0.0.1:10092/api", encoding="utf-8", enc_key=None, enc_iv=None):

        self._endpoint = endpoint
        self._encoding = "utf-8"
        if enc_key == None or enc_iv == None:
            self._transport_enc = False
            self._transport_enc_key = None
            self._transport_enc_iv = None
            self._cipher = None
        else:
            self._transport_enc = True
            self._transport_enc_key = enc_key
            self._transport_enc_iv = enc_iv
            backend = default_backend()
            self._cipher = Cipher(algorithms.AES(
                enc_key), modes.CBC(enc_iv), backend=backend)

        self._session = requests.Session()
        self.client_id = 0
        self.gddm_sh = 0 #上海股东代码
        self.gddm_sz = 0 #深圳股东代码

    def call(self, func, params=None):

        json_obj = {
            "func": func
        }

        if params is not None:
            json_obj["params"] = params

        if self._transport_enc:
            data_to_send = self.encrypt(json_obj)
            response = self._session.post(self._endpoint, data=data_to_send)
        else:
            response = self._session.post(self._endpoint, json=json_obj)
        response.encoding = self._encoding
        text = response.text

        if self._transport_enc:
            decoded_text = self.decrypt(text)
            print(decoded_text)
            return json.loads(decoded_text)
        else:
            return json.loads(text)

    def encrypt(self, source_obj):
        encrypter = self._cipher.encryptor()
        source = json.dumps(source_obj)
        source = source.encode(self._encoding)
        need_to_padding = 16 - (len(source) % 16)
        if need_to_padding > 0:
            source = source + b'\x00' * need_to_padding
        enc_data = encrypter.update(source) + encrypter.finalize()
        b64_enc_data = base64.encodebytes(enc_data)
        return urllib.parse.quote(b64_enc_data)

    def decrypt(self, source):
        decrypter = self._cipher.decryptor()
        source = urllib.parse.unquote(source)
        source = base64.decodebytes(source.encode("utf-8"))
        data_bytes = decrypter.update(source) + decrypter.finalize()
        return data_bytes.rstrip(b"\x00").decode(self._encoding)

    def data_to_df(self, result):
        if 'data' in result:
            data = result['data']
            return pd.DataFrame(data=data)

    #------ functions

    def ping(self):

        return self.call("ping", {})

    def logon(self, ip, port, version, yyb_id, account_cookie, trade_account, jy_passwrod, tx_password):
        data = self.call("logon", {
            "ip": ip,
            "port": port,
            "version": version,
            "yyb_id": yyb_id,
            "account_no": account_cookie,
            "trade_account": trade_account,
            "jy_password": jy_passwrod,
            "tx_password": tx_password
        })
        if data['success']:
            self.client_id = data["data"]["client_id"]
            self.gddm_sh = self.query_data(5)['data'][0]['股东代码']
            self.gddm_sz = self.query_data(5)['data'][1]['股东代码']
            print('上海股东代码:%s,深圳股东代码:%s',self.gddm_sh,self.gddm_sz)
        return data

    def logoff(self):
        return self.call("logoff", {
            "client_id": self.client_id
        })

    def query_data(self,  category):
        return self.call("query_data", {
            "client_id": self.client_id,
            "category": category
        })

    def send_order(self,  code, price, amount, towards, order_model,market):
        """下单

        Arguments:
            code {[type]} -- [description]
            price {[type]} -- [description]
            amount {[type]} -- [description]
            towards {[type]} -- [description]
            order_model {[type]} -- [description]
            market:市场,SZ 深交所,SH 上交所

        Returns:
            [type] -- [description]
        """

        towards = 0 if towards == ORDER_DIRECTION.BUY else 1
        if order_model == ORDER_MODEL.MARKET:
            order_model = 4
        elif order_model == ORDER_MODEL.LIMIT:
            order_model = 0

        return self.call("send_order", {
            'client_id': self.client_id,
            'category': towards,
            'price_type': order_model,
            'gddm': self.gddm_sh if market=='SH' or market=='sh' else self.gddm_sz,
            'zqdm': code,
            'price': price,
            'quantity': amount
        })

    def cancel_order(self, exchange_id, order_id):
        """

        Arguments:
            exchange_id {[type]} -- 交易所  0 深圳 1上海 (偶尔2是深圳)
            order_id {[type]} -- [description]

        Returns:
            [type] -- [description]
        """

        return self.call("cancel_order", {
            'client_id': self.client_id,
            'exchange_id': exchange_id,
            'hth': order_id
        })

    def get_quote(self, code):
        return self.call("get_quote", {
            'client_id': self.client_id,
            'code': code,
        })

    def repay(self,  amount):
        return self.call("repay", {
            'client_id': self.client_id,
            'amount': amount
        })

    def receive_order(self, event):

        return self.send_order(event.client_id, event.category, event.price_type, event.gddm, event.zqdm, event.price, event.quantity)
        #client_id, category, price_type, gddm, zqdm, price, quantity

    def run(self, event):
        pass
Exemple #33
0
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

BLOCKLEN = 16


def blocks(data):
    split = [
        binascii.hexlify(data[i:i + BLOCKLEN])
        for i in range(0, len(data), BLOCKLEN)
    ]
    return ' '.join(split)


if __name__ == "__main__":

    # initialize a random key
    k = os.urandom(16)
    print 'k = %s' % binascii.hexlify(k)

    # create an instance of AES-128 to encrypt and decrypt
    cipher = Cipher(algorithms.AES(k), modes.ECB(), backend=default_backend())
    aes_encrypt = cipher.encryptor()

    # repeating inputs
    p = '\x12' * BLOCKLEN * 2

    # encrypt plaintext p to ciphertext c
    c = aes_encrypt.update(p) + aes_encrypt.finalize()
    print 'enc(%s) = %s' % (blocks(p), blocks(c))
Exemple #34
0
class SecureTemporaryFile(_TemporaryFileWrapper, object):
    """Temporary file that provides on-the-fly encryption.

    Buffering large submissions in memory as they come in requires too
    much memory for too long a period. By writing the file to disk as it
    comes in using a stream cipher, we are able to minimize memory usage
    as submissions come in, while minimizing the chances of plaintext
    recovery through forensic disk analysis. They key used to encrypt
    each secure temporary file is also ephemeral, and is only stored in
    memory only for as long as needed.

    Adapted from Globaleaks' GLSecureTemporaryFile:
    https://github.com/globaleaks/GlobaLeaks/blob/master/backend/globaleaks/security.py#L35

    WARNING: you can't use this like a normal file object. It supports
    being appended to however many times you wish (although content may not be
    overwritten), and then it's contents may be read only once (although it may
    be done in chunks) and only after it's been written to.
    """
    AES_key_size = 256
    AES_block_size = 128

    def __init__(self, store_dir: str) -> None:
        """Generates an AES key and an initialization vector, and opens
        a file in the `store_dir` directory with a
        pseudorandomly-generated filename.

        Args:
            store_dir (str): the directory to create the secure
                temporary file under.

        Returns: self
        """
        self.last_action = 'init'
        self.create_key()

        data = base64.urlsafe_b64encode(os.urandom(32))
        self.tmp_file_id = data.decode('utf-8').strip('=')

        self.filepath = os.path.join(store_dir,
                                     '{}.aes'.format(self.tmp_file_id))
        self.file = io.open(self.filepath, 'w+b')
        super(SecureTemporaryFile, self).__init__(self.file, self.filepath)

    def create_key(self) -> None:
        """Generates a unique, pseudorandom AES key, stored ephemerally in
        memory as an instance attribute. Its destruction is ensured by the
        automatic nightly reboots of the SecureDrop application server combined
        with the freed memory-overwriting PAX_MEMORY_SANITIZE feature of the
        grsecurity-patched kernel it uses (for further details consult
        https://github.com/freedomofpress/securedrop/pull/477#issuecomment-168445450).
        """
        self.key = os.urandom(self.AES_key_size // 8)
        self.iv = os.urandom(self.AES_block_size // 8)
        self.initialize_cipher()

    def initialize_cipher(self) -> None:
        """Creates the cipher-related objects needed for AES-CTR
        encryption and decryption.
        """
        self.cipher = Cipher(AES(self.key), CTR(self.iv), default_backend())
        self.encryptor = self.cipher.encryptor()
        self.decryptor = self.cipher.decryptor()

    def write(self, data: Union[bytes, str]) -> None:
        """Write `data` to the secure temporary file. This method may be
        called any number of times following instance initialization,
        but after calling :meth:`read`, you cannot write to the file
        again.
        """
        if self.last_action == 'read':
            raise AssertionError('You cannot write after reading!')
        self.last_action = 'write'

        if isinstance(data, str):
            data_as_bytes = data.encode('utf-8')
        else:
            data_as_bytes = data

        self.file.write(self.encryptor.update(data_as_bytes))

    def read(self, count: Optional[int] = None) -> bytes:
        """Read `data` from the secure temporary file. This method may
        be called any number of times following instance initialization
        and once :meth:`write has been called at least once, but not
        before.

        Before the first read operation, `seek(0, 0)` is called. So
        while you can call this method any number of times, the full
        contents of the file can only be read once. Additional calls to
        read will return an empty str, which is desired behavior in that
        it matches :class:`file` and because other modules depend on
        this behavior to let them know they've reached the end of the
        file.

        Args:
            count (int): the number of bytes to try to read from the
                file from the current position.
        """
        if self.last_action == 'init':
            raise AssertionError('You must write before reading!')
        if self.last_action == 'write':
            self.seek(0, 0)
            self.last_action = 'read'

        if count:
            return self.decryptor.update(self.file.read(count))
        else:
            return self.decryptor.update(self.file.read())

    def close(self) -> None:
        """The __del__ method in tempfile._TemporaryFileWrapper (which
        SecureTemporaryFile class inherits from) calls close() when the
        temporary file is deleted.
        """
        try:
            self.decryptor.finalize()
        except AlreadyFinalized:
            pass

        # Since tempfile._TemporaryFileWrapper.close() does other cleanup,
        # (i.e. deleting the temp file on disk), we need to call it also.
        super(SecureTemporaryFile, self).close()
def encrypt(message, key, iv):
    backend = default_backend()
    cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
    encryptor = cipher.encryptor()
    ct = encryptor.update(message) + encryptor.finalize()
    return ct
Exemple #36
0
    def encrypt(self, key):
        cipher = Cipher(AES(key.get_data()), ECB(), backend=self.backend)
        encryptor = cipher.encryptor()
        ciphertext = encryptor.update(self._data.get_data())

        return ByteData(ciphertext)
Exemple #37
0
    def create(self, key, enckey, dependencies=None):
        self.enckey = enckey

        if dependencies is None:
            dependencies_num = 0
            protected_tlv_size = 0
        else:
            # Size of a Dependency TLV = Header ('BBH') + Payload('IBBHI')
            # = 16 Bytes

            dependencies_num = len(dependencies[DEP_IMAGES_KEY])
            protected_tlv_size = (dependencies_num * 16) + TLV_INFO_SIZE

        # At this point the image is already on the payload, this adds
        # the header to the payload as well
        self.add_header(enckey, protected_tlv_size)

        prot_tlv = TLV(self.endian, TLV_PROT_INFO_MAGIC)

        # Protected TLVs must be added first, because they are also included
        # in the hash calculation
        protected_tlv_off = None
        if protected_tlv_size != 0:
            for i in range(dependencies_num):
                e = STRUCT_ENDIAN_DICT[self.endian]
                payload = struct.pack(
                    e + 'B3x' + 'BBHI', int(dependencies[DEP_IMAGES_KEY][i]),
                    dependencies[DEP_VERSIONS_KEY][i].major,
                    dependencies[DEP_VERSIONS_KEY][i].minor,
                    dependencies[DEP_VERSIONS_KEY][i].revision,
                    dependencies[DEP_VERSIONS_KEY][i].build)
                prot_tlv.add('DEPENDENCY', payload)

            protected_tlv_off = len(self.payload)
            self.payload += prot_tlv.get()

        tlv = TLV(self.endian)

        # Note that ecdsa wants to do the hashing itself, which means
        # we get to hash it twice.
        sha = hashlib.sha256()
        sha.update(self.payload)
        digest = sha.digest()

        tlv.add('SHA256', digest)

        if key is not None:
            pub = key.get_public_bytes()
            sha = hashlib.sha256()
            sha.update(pub)
            pubbytes = sha.digest()
            tlv.add('KEYHASH', pubbytes)

            # `sign` expects the full image payload (sha256 done internally),
            # while `sign_digest` expects only the digest of the payload

            if hasattr(key, 'sign'):
                sig = key.sign(bytes(self.payload))
            else:
                sig = key.sign_digest(digest)
            tlv.add(key.sig_tlv(), sig)

        # At this point the image was hashed + signed, we can remove the
        # protected TLVs from the payload (will be re-added later)
        if protected_tlv_off is not None:
            self.payload = self.payload[:protected_tlv_off]

        if enckey is not None:
            plainkey = os.urandom(16)

            if isinstance(enckey, rsa.RSAPublic):
                cipherkey = enckey._get_public().encrypt(
                    plainkey,
                    padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
                                 algorithm=hashes.SHA256(),
                                 label=None))
                tlv.add('ENCRSA2048', cipherkey)
            elif isinstance(enckey, ecdsa.ECDSA256P1Public):
                cipherkey, mac, pubk = self.ecies_p256_hkdf(enckey, plainkey)
                tlv.add('ENCEC256', pubk + mac + cipherkey)

            nonce = bytes([0] * 16)
            cipher = Cipher(algorithms.AES(plainkey),
                            modes.CTR(nonce),
                            backend=default_backend())
            encryptor = cipher.encryptor()
            img = bytes(self.payload[self.header_size:])
            self.payload[self.header_size:] = \
                encryptor.update(img) + encryptor.finalize()

        self.payload += prot_tlv.get()
        self.payload += tlv.get()
Exemple #38
0
def _flash_encryption_operation_aes_xts(output_file, input_file, flash_address,
                                        keyfile, do_decrypt):
    """
    Apply the AES-XTS algorithm with the hardware addressing scheme used by Espressif

    key = AES-XTS key (32 or 64 bytes)
    flash_address = address in flash to encrypt at. Must be multiple of 16 bytes.
    indata = Data to encrypt/decrypt. Must be multiple of 16 bytes.
    encrypt = True to Encrypt indata, False to decrypt indata.

    Returns a bitstring of the ciphertext or plaintext result.
    """

    backend = default_backend()
    key = _load_hardware_key(keyfile)
    indata = input_file.read()

    if flash_address % 16 != 0:
        raise esptool.FatalError(
            "Starting flash address 0x%x must be a multiple of 16" %
            flash_address)

    if len(indata) % 16 != 0:
        raise esptool.FatalError(
            "Input data length (%d) must be a multiple of 16" % len(indata))

    if len(indata) == 0:
        raise esptool.FatalError("Input data must be longer than 0")

    # left pad for a 1024-bit aligned address
    pad_left = flash_address % 0x80
    indata = (b"\x00" * pad_left) + indata

    # right pad for full 1024-bit blocks
    pad_right = len(indata) % 0x80
    if pad_right > 0:
        pad_right = 0x80 - pad_right
    indata = indata + (b"\x00" * pad_right)

    inblocks = _split_blocks(indata, 0x80)  # split into 1024 bit blocks

    output = b""
    for inblock in inblocks:  # for each block
        tweak = struct.pack("<I", (flash_address & ~0x7F)) + (b"\x00" * 12)
        flash_address += 0x80  # for next block

        if len(tweak) != 16:
            raise esptool.FatalError(
                "Length of tweak must be 16, was {}".format(len(tweak)))

        cipher = Cipher(algorithms.AES(key), modes.XTS(tweak), backend=backend)
        encryptor = cipher.decryptor() if do_decrypt else cipher.encryptor()

        inblock = inblock[::-1]  # reverse input
        outblock = encryptor.update(inblock)  # standard algo
        output += outblock[::-1]  # reverse output

    # undo any padding we applied to the input
    if pad_right != 0:
        output = output[:-pad_right]
    if pad_left != 0:
        output = output[pad_left:]

    # output length matches original input
    if len(output) != len(indata) - pad_left - pad_right:
        raise esptool.FatalError(
            "Length of input data ({}) should match the output data ({})".
            format(len(indata) - pad_left - pad_right, len(output)))

    output_file.write(output)
Exemple #39
0
def cryptography_symmetric_encrypt(encrypt_key, plaintext):
    """
    Encrypt the provided plaintext using AES encryption.

    NOTE 1: This function return a string which is fully compatible with Keyczar.Encrypt() method.

    NOTE 2: This function is loosely based on keyczar AESKey.Encrypt() (Apache 2.0 license).

    The final encrypted string value consists of:

    [message bytes][HMAC signature bytes for the message] where message consists of
    [keyczar header plaintext][IV bytes][ciphertext bytes]

    NOTE: Header itself is unused, but it's added so the format is compatible with keyczar format.

    """
    assert isinstance(encrypt_key,
                      AESKey), 'encrypt_key needs to be AESKey class instance'
    assert isinstance(plaintext, (six.text_type, six.string_types, six.binary_type)), \
        'plaintext needs to either be a string/unicode or bytes'

    aes_key_bytes = encrypt_key.aes_key_bytes
    hmac_key_bytes = encrypt_key.hmac_key_bytes

    assert isinstance(aes_key_bytes, six.binary_type)
    assert isinstance(hmac_key_bytes, six.binary_type)

    if isinstance(plaintext, (six.text_type, six.string_types)):
        # Convert data to bytes
        data = plaintext.encode('utf-8')
    else:
        data = plaintext

    # Pad data
    data = pkcs5_pad(data)

    # Generate IV
    iv_bytes = os.urandom(KEYCZAR_AES_BLOCK_SIZE)

    backend = default_backend()
    cipher = Cipher(algorithms.AES(aes_key_bytes),
                    modes.CBC(iv_bytes),
                    backend=backend)
    encryptor = cipher.encryptor()

    # NOTE: We don't care about actual Keyczar header value, we only care about the length (5
    # bytes) so we simply add 5 0's
    header_bytes = b'00000'

    ciphertext_bytes = encryptor.update(data) + encryptor.finalize()
    msg_bytes = header_bytes + iv_bytes + ciphertext_bytes

    # Generate HMAC signature for the message (header + IV + ciphertext)
    h = hmac.HMAC(hmac_key_bytes, hashes.SHA1(), backend=backend)
    h.update(msg_bytes)
    sig_bytes = h.finalize()

    result = msg_bytes + sig_bytes

    # Convert resulting byte string to hex notation ASCII string
    result = binascii.hexlify(result).upper()

    return result
Exemple #40
0
 def test_AES_decode(self, card, fAES):
     cipher = Cipher(algorithms.AES(fAES), modes.CBC(AESiv), backend=default_backend())
     encryptor = cipher.encryptor()
     v = card.cmd_pso(0x80, 0x86, b"\x02" + encryptor.update(AESPlainText) + encryptor.finalize())
     assert v == AESPlainText
Exemple #41
0
class _StreamCipher(six.with_metaclass(_StreamCipherMetaclass, object)):
    type = "stream"

    def __init__(self, key=None):
        """
        Note that we have to keep the encryption/decryption state in unique
        encryptor and decryptor objects. This differs from _BlockCipher.

        In order to do connection state snapshots, we need to be able to
        recreate past cipher contexts. This is why we feed _enc_updated_with
        and _dec_updated_with every time encrypt() or decrypt() is called.
        """
        self.ready = {"key": True}
        if key is None:
            self.ready["key"] = False
            if hasattr(self, "expanded_key_len"):
                tmp_len = self.expanded_key_len
            else:
                tmp_len = self.key_len
            key = b"\0" * tmp_len

        # we use super() in order to avoid any deadlock with __setattr__
        super(_StreamCipher, self).__setattr__("key", key)

        self._cipher = Cipher(self.pc_cls(key),
                              mode=None,
                              backend=default_backend())
        self.encryptor = self._cipher.encryptor()
        self.decryptor = self._cipher.decryptor()
        self._enc_updated_with = b""
        self._dec_updated_with = b""

    def __setattr__(self, name, val):
        """
        We have to keep the encryptor/decryptor for a long time,
        however they have to be updated every time the key is changed.
        """
        if name == "key":
            if self._cipher is not None:
                self._cipher.algorithm.key = val
                self.encryptor = self._cipher.encryptor()
                self.decryptor = self._cipher.decryptor()
            self.ready["key"] = True
        super(_StreamCipher, self).__setattr__(name, val)

    def encrypt(self, data):
        if False in six.itervalues(self.ready):
            raise CipherError(data)
        self._enc_updated_with += data
        return self.encryptor.update(data)

    def decrypt(self, data):
        if False in six.itervalues(self.ready):
            raise CipherError(data)
        self._dec_updated_with += data
        return self.decryptor.update(data)

    def snapshot(self):
        c = self.__class__(self.key)
        c.ready = self.ready.copy()
        c.encryptor.update(self._enc_updated_with)
        c.decryptor.update(self._dec_updated_with)
        c._enc_updated_with = self._enc_updated_with
        c._dec_updated_with = self._dec_updated_with
        return c
Exemple #42
0
def digest_secure_bootloader(args):
    """ Calculate the digest of a bootloader image, in the same way the hardware
    secure boot engine would do so. Can be used with a pre-loaded key to update a
    secure bootloader. """
    _check_output_is_not_input(args.keyfile, args.output)
    _check_output_is_not_input(args.image, args.output)
    _check_output_is_not_input(args.iv, args.output)
    if args.iv is not None:
        print("WARNING: --iv argument is for TESTING PURPOSES ONLY")
        iv = args.iv.read(128)
    else:
        iv = os.urandom(128)
    plaintext_image = args.image.read()
    args.image.seek(0)

    # secure boot engine reads in 128 byte blocks (ie SHA512 block
    # size), but also doesn't look for any appended SHA-256 digest
    fw_image = esptool.ESP32FirmwareImage(args.image)
    if fw_image.append_digest:
        if len(plaintext_image) % 128 <= 32:
            # ROM bootloader will read to the end of the 128 byte block, but not
            # to the end of the SHA-256 digest at the end
            new_len = len(plaintext_image) - (len(plaintext_image) % 128)
            plaintext_image = plaintext_image[:new_len]

    # if image isn't 128 byte multiple then pad with 0xFF (ie unwritten flash)
    # as this is what the secure boot engine will see
    if len(plaintext_image) % 128 != 0:
        plaintext_image += b"\xFF" * (128 - (len(plaintext_image) % 128))

    plaintext = iv + plaintext_image

    # Secure Boot digest algorithm in hardware uses AES256 ECB to
    # produce a ciphertext, then feeds output through SHA-512 to
    # produce the digest. Each block in/out of ECB is reordered
    # (due to hardware quirks not for security.)

    key = _load_hardware_key(args.keyfile)
    backend = default_backend()
    cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=backend)
    encryptor = cipher.encryptor()
    digest = hashlib.sha512()

    for block in get_chunks(plaintext, 16):
        block = block[::-1]  # reverse each input block

        cipher_block = encryptor.update(block)
        # reverse and then byte swap each word in the output block
        cipher_block = cipher_block[::-1]
        for block in get_chunks(cipher_block, 4):
            # Python hashlib can build each SHA block internally
            digest.update(block[::-1])

    if args.output is None:
        args.output = os.path.splitext(
            args.image.name)[0] + "-digest-0x0000.bin"
    with open(args.output, "wb") as f:
        f.write(iv)
        digest = digest.digest()
        for word in get_chunks(digest, 4):
            f.write(word[::-1])  # swap word order in the result
        f.write(b'\xFF' * (0x1000 - f.tell()))  # pad to 0x1000
        f.write(plaintext_image)
    print("digest+image written to %s" % args.output)
Exemple #43
0
@author: Pericle
"""

import binascii
import os
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

block = algorithms.AES.block_size/8

filename = raw_input('Type the file to encrypt: ')
with open(filename, 'rb') as f:
    plaintext = f.read()

key_hex = raw_input('Type the key in ' + str(2*block) + ' hexadecimal digits: ')
key = binascii.unhexlify(key_hex)

ctx = padding.PKCS7(8*block).padder()
padded_plaintext = ctx.update(plaintext) + ctx.finalize()

iv = os.urandom(block)
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), default_backend())
ctx = cipher.encryptor()
ciphertext = ctx.update(padded_plaintext) + ctx.finalize()

with open(filename + '.enc', 'wb') as f:
    f.write(iv)
    f.write(ciphertext)
print('Encrypted file: ' + filename + '.enc')
Exemple #44
0
def aes_ecb_encrypt(key, data):
    backend = default_backend()
    cipher = Cipher(algorithms.AES(key), modes.ECB, backend=backend)
    encryptor = cipher.encryptor()
    ciphertext = encryptor.update(data) + encryptor.finalize()
    return ciphertext
Exemple #45
0
class TuyaCipher:
    """Tuya cryptographic helpers."""
    def __init__(self, key, version):
        """Initialize the cipher."""
        self.version = version
        self.key = key
        self.cipher = Cipher(algorithms.AES(key.encode('ascii')),
                             modes.ECB(),
                             backend=openssl_backend)

    def get_prefix_size_and_validate(self, command, encrypted_data):
        try:
            version = tuple(
                map(int, encrypted_data[:3].decode('utf8').split('.')))
        except UnicodeDecodeError:
            version = (0, 0)
        if version != self.version:
            return 0
        if version < (3, 3):
            hash = encrypted_data[3:19].decode('ascii')
            expected_hash = self.hash(encrypted_data[19:])
            if hash != expected_hash:
                return 0
            return 19
        else:
            if command in (Message.SET_COMMAND, Message.GRATUITOUS_UPDATE):
                _, sequence, __, ___ = struct.unpack_from(
                    '>IIIH', encrypted_data, 3)
                return 15
        return 0

    def decrypt(self, command, data):
        prefix_size = self.get_prefix_size_and_validate(command, data)
        data = data[prefix_size:]
        decryptor = self.cipher.decryptor()
        if self.version < (3, 3):
            data = base64.b64decode(data)
        decrypted_data = decryptor.update(data)
        decrypted_data += decryptor.finalize()
        unpadder = PKCS7(128).unpadder()
        unpadded_data = unpadder.update(decrypted_data)
        unpadded_data += unpadder.finalize()

        return unpadded_data

    def encrypt(self, command, data):
        encrypted_data = b''
        if data:
            padder = PKCS7(128).padder()
            padded_data = padder.update(data)
            padded_data += padder.finalize()
            encryptor = self.cipher.encryptor()
            encrypted_data = encryptor.update(padded_data)
            encrypted_data += encryptor.finalize()

        prefix = '.'.join(map(str, self.version)).encode('utf8')
        if self.version < (3, 3):
            payload = base64.b64encode(encrypted_data)
            hash = self.hash(payload)
            prefix += hash.encode('utf8')
        else:
            payload = encrypted_data
            if command in (Message.SET_COMMAND, Message.GRATUITOUS_UPDATE):
                prefix += b'\x00' * 12
            else:
                prefix = b''

        return prefix + payload

    def hash(self, data):
        digest = Hash(MD5(), backend=openssl_backend)
        to_hash = "data={}||lpv={}||{}".format(
            data.decode('ascii'), '.'.join(map(str, self.version)), self.key)
        digest.update(to_hash.encode('utf8'))
        intermediate = digest.finalize().hex()
        return intermediate[8:24]
Exemple #46
0
def _flash_encryption_operation_esp32(output_file, input_file, flash_address,
                                      keyfile, flash_crypt_conf, do_decrypt):
    key = _load_hardware_key(keyfile)

    if flash_address % 16 != 0:
        raise esptool.FatalError(
            "Starting flash address 0x%x must be a multiple of 16" %
            flash_address)

    if flash_crypt_conf == 0:
        print("WARNING: Setting FLASH_CRYPT_CONF to zero is not recommended")

    if esptool.PYTHON2:
        tweak_range = _flash_encryption_tweak_range(flash_crypt_conf)
    else:
        tweak_range = _flash_encryption_tweak_range_bits(flash_crypt_conf)
        key = int.from_bytes(key, byteorder='big', signed=False)

    backend = default_backend()

    cipher = None
    block_offs = flash_address
    while True:
        block = input_file.read(16)
        if len(block) == 0:
            break
        elif len(block) < 16:
            if do_decrypt:
                raise esptool.FatalError(
                    "Data length is not a multiple of 16 bytes")
            pad = 16 - len(block)
            block = block + os.urandom(pad)
            print(
                "Note: Padding with %d bytes of random data (encrypted data must be multiple of 16 bytes long)"
                % pad)

        if block_offs % 32 == 0 or cipher is None:
            # each bit of the flash encryption key is XORed with tweak bits derived from the offset of 32 byte block of flash
            block_key = _flash_encryption_tweak_key(key, block_offs,
                                                    tweak_range)

            if cipher is None:  # first pass
                cipher = Cipher(algorithms.AES(block_key),
                                modes.ECB(),
                                backend=backend)

                # note AES is used inverted for flash encryption, so
                # "decrypting" flash uses AES encrypt algorithm and vice
                # versa. (This does not weaken AES.)
                actor = cipher.encryptor() if do_decrypt else cipher.decryptor(
                )
            else:
                # performance hack: changing the key using pyca-cryptography API requires recreating
                # 'actor'. With openssl backend, this re-initializes the openssl cipher context. To save some time,
                # manually call EVP_CipherInit_ex() in the openssl backend to update the key.
                # If it fails, fall back to recreating the entire context via public API.
                try:
                    backend = actor._ctx._backend
                    res = backend._lib.EVP_CipherInit_ex(
                        actor._ctx._ctx,
                        backend._ffi.NULL,
                        backend._ffi.NULL,
                        backend._ffi.from_buffer(block_key),
                        backend._ffi.NULL,
                        actor._ctx._operation,
                    )
                    backend.openssl_assert(res != 0)
                except AttributeError:
                    # backend is not an openssl backend, or implementation has changed: fall back to the slow safe version
                    cipher.algorithm.key = block_key
                    actor = cipher.encryptor(
                    ) if do_decrypt else cipher.decryptor()

        block = block[::-1]  # reverse input block byte order
        block = actor.update(block)

        output_file.write(block[::-1])  # reverse output block byte order
        block_offs += 16
Exemple #47
0
def encrypt_aes_128_ecb(msg, key):
    padded_msg = pkcs7_padding(msg, block_size=16)
    cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=backend)
    encryptor = cipher.encryptor()
    return encryptor.update(padded_msg) + encryptor.finalize()
Exemple #48
0
class AuxiliaryStreamCrypto(object):
    _backend = default_backend()

    def __init__(self, crypto_key, hash_key, server_iv, client_iv):
        """
        Initialize Auxiliary Stream Crypto-context.
        """

        self._encrypt_key = crypto_key
        self._hash_key = hash_key
        self._server_iv = server_iv
        self._client_iv = client_iv

        self._server_cipher = Cipher(
            algorithms.AES(self._encrypt_key),
            modes.CBC(self._server_iv),
            backend=AuxiliaryStreamCrypto._backend
        )

        self._server_encryptor = self._server_cipher.encryptor()
        self._server_decryptor = self._server_cipher.decryptor()

        self._client_cipher = Cipher(
            algorithms.AES(self._encrypt_key),
            modes.CBC(self._client_iv),
            backend=AuxiliaryStreamCrypto._backend
        )

        self._client_encryptor = self._client_cipher.encryptor()
        self._client_decryptor = self._client_cipher.decryptor()

    @classmethod
    def from_connection_info(cls, connection_info):
        """
        Initialize Crypto context via AuxiliaryStream-message
        connection info.
        """
        return cls(
            connection_info.crypto_key,
            connection_info.sign_hash,
            connection_info.server_iv,
            connection_info.client_iv
        )

    def encrypt(self, plaintext):
        """
        Encrypts plaintext with AES-128-CBC

        No padding is added here, data has to be aligned to
        block size (16 bytes).

        Args:
            plaintext (bytes): The plaintext to encrypt.

        Returns:
            bytes: Encrypted Data
        """
        return AuxiliaryStreamCrypto._crypt(self._client_encryptor, plaintext)

    def encrypt_server(self, plaintext):
        return AuxiliaryStreamCrypto._crypt(self._server_encryptor, plaintext)

    def decrypt(self, ciphertext):
        """
        Decrypts ciphertext

        No padding is removed here.

        Args:
            ciphertext (bytes): Ciphertext to be decrypted

        Returns:
            bytes: Decrypted data
        """
        return AuxiliaryStreamCrypto._crypt(self._server_decryptor, ciphertext)

    def decrypt_client(self, ciphertext):
        return AuxiliaryStreamCrypto._crypt(self._client_decryptor, ciphertext)

    def hash(self, data):
        """
        Securely hashes data with HMAC SHA-256

        Args:
            data (bytes): The data to securely hash.

        Returns:
            bytes: Hashed data
        """
        return AuxiliaryStreamCrypto._secure_hash(self._hash_key, data)

    def verify(self, data, secure_hash):
        """
        Verifies that the given data generates the given secure_hash

        Args:
            data (bytes): The data to validate.
            secure_hash (bytes): The secure hash to validate against.

        Returns:
            bool: True on success, False otherwise
        """
        return secure_hash == self.hash(data)

    @staticmethod
    def _secure_hash(key, data):
        return hmac.new(key, data, hashlib.sha256).digest()

    @staticmethod
    def _crypt(cryptor, data):
        return cryptor.update(data)
Exemple #49
0
    def create(self,
               key,
               public_key_format,
               enckey,
               dependencies=None,
               sw_type=None):
        self.enckey = enckey

        # Calculate the hash of the public key
        if key is not None:
            pub = key.get_public_bytes()
            sha = hashlib.sha256()
            sha.update(pub)
            pubbytes = sha.digest()
        else:
            pubbytes = bytes(hashlib.sha256().digest_size)

        protected_tlv_size = 0

        if self.security_counter is not None:
            # Size of the security counter TLV: header ('HH') + payload ('I')
            #                                   = 4 + 4 = 8 Bytes
            protected_tlv_size += TLV_SIZE + 4

        if sw_type is not None:
            if len(sw_type) > MAX_SW_TYPE_LENGTH:
                msg = "'{}' is too long ({} characters) for sw_type. Its " \
                      "maximum allowed length is 12 characters.".format(
                    sw_type, len(sw_type))
                raise click.UsageError(msg)

            image_version = (str(self.version.major) + '.' +
                             str(self.version.minor) + '.' +
                             str(self.version.revision))

            # The image hash is computed over the image header, the image
            # itself and the protected TLV area. However, the boot record TLV
            # (which is part of the protected area) should contain this hash
            # before it is even calculated. For this reason the script fills
            # this field with zeros and the bootloader will insert the right
            # value later.
            digest = bytes(hashlib.sha256().digest_size)

            # Create CBOR encoded boot record
            boot_record = create_sw_component_data(sw_type, image_version,
                                                   "SHA256", digest, pubbytes)

            protected_tlv_size += TLV_SIZE + len(boot_record)

        if dependencies is not None:
            # Size of a Dependency TLV = Header ('HH') + Payload('IBBHI')
            # = 4 + 12 = 16 Bytes
            dependencies_num = len(dependencies[DEP_IMAGES_KEY])
            protected_tlv_size += (dependencies_num * 16)

        if protected_tlv_size != 0:
            # Add the size of the TLV info header
            protected_tlv_size += TLV_INFO_SIZE

        # At this point the image is already on the payload, this adds
        # the header to the payload as well
        self.add_header(enckey, protected_tlv_size)

        prot_tlv = TLV(self.endian, TLV_PROT_INFO_MAGIC)

        # Protected TLVs must be added first, because they are also included
        # in the hash calculation
        protected_tlv_off = None
        if protected_tlv_size != 0:

            e = STRUCT_ENDIAN_DICT[self.endian]

            if self.security_counter is not None:
                payload = struct.pack(e + 'I', self.security_counter)
                prot_tlv.add('SEC_CNT', payload)

            if sw_type is not None:
                prot_tlv.add('BOOT_RECORD', boot_record)

            if dependencies is not None:
                for i in range(dependencies_num):
                    payload = struct.pack(
                        e + 'B3x' + 'BBHI',
                        int(dependencies[DEP_IMAGES_KEY][i]),
                        dependencies[DEP_VERSIONS_KEY][i].major,
                        dependencies[DEP_VERSIONS_KEY][i].minor,
                        dependencies[DEP_VERSIONS_KEY][i].revision,
                        dependencies[DEP_VERSIONS_KEY][i].build)
                    prot_tlv.add('DEPENDENCY', payload)

            protected_tlv_off = len(self.payload)
            self.payload += prot_tlv.get()

        tlv = TLV(self.endian)

        # Note that ecdsa wants to do the hashing itself, which means
        # we get to hash it twice.
        sha = hashlib.sha256()
        sha.update(self.payload)
        digest = sha.digest()

        tlv.add('SHA256', digest)

        if key is not None:
            if public_key_format == 'hash':
                tlv.add('KEYHASH', pubbytes)
            else:
                tlv.add('PUBKEY', pub)

            # `sign` expects the full image payload (sha256 done internally),
            # while `sign_digest` expects only the digest of the payload

            if hasattr(key, 'sign'):
                sig = key.sign(bytes(self.payload))
            else:
                sig = key.sign_digest(digest)
            tlv.add(key.sig_tlv(), sig)

        # At this point the image was hashed + signed, we can remove the
        # protected TLVs from the payload (will be re-added later)
        if protected_tlv_off is not None:
            self.payload = self.payload[:protected_tlv_off]

        if enckey is not None:
            plainkey = os.urandom(16)

            if isinstance(enckey, rsa.RSAPublic):
                cipherkey = enckey._get_public().encrypt(
                    plainkey,
                    padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
                                 algorithm=hashes.SHA256(),
                                 label=None))
                self.enctlv_len = len(cipherkey)
                tlv.add('ENCRSA2048', cipherkey)
            elif isinstance(enckey,
                            (ecdsa.ECDSA256P1Public, x25519.X25519Public)):
                cipherkey, mac, pubk = self.ecies_hkdf(enckey, plainkey)
                enctlv = pubk + mac + cipherkey
                self.enctlv_len = len(enctlv)
                if isinstance(enckey, ecdsa.ECDSA256P1Public):
                    tlv.add('ENCEC256', enctlv)
                else:
                    tlv.add('ENCX25519', enctlv)

            nonce = bytes([0] * 16)
            cipher = Cipher(algorithms.AES(plainkey),
                            modes.CTR(nonce),
                            backend=default_backend())
            encryptor = cipher.encryptor()
            img = bytes(self.payload[self.header_size:])
            self.payload[self.header_size:] = \
                encryptor.update(img) + encryptor.finalize()

        self.payload += prot_tlv.get()
        self.payload += tlv.get()

        self.check_trailer()
Exemple #50
0
class Snapshot(CoreSysAttributes):
    """A single Hass.io snapshot."""

    def __init__(self, coresys: CoreSys, tar_file: Path):
        """Initialize a snapshot."""
        self.coresys: CoreSys = coresys
        self._tarfile: Path = tar_file
        self._data: Dict[str, Any] = {}
        self._tmp = None
        self._key: Optional[bytes] = None
        self._aes: Optional[Cipher] = None

    @property
    def slug(self):
        """Return snapshot slug."""
        return self._data.get(ATTR_SLUG)

    @property
    def sys_type(self):
        """Return snapshot type."""
        return self._data.get(ATTR_TYPE)

    @property
    def name(self):
        """Return snapshot name."""
        return self._data[ATTR_NAME]

    @property
    def date(self):
        """Return snapshot date."""
        return self._data[ATTR_DATE]

    @property
    def protected(self):
        """Return snapshot date."""
        return self._data.get(ATTR_PROTECTED) is not None

    @property
    def addons(self):
        """Return snapshot date."""
        return self._data[ATTR_ADDONS]

    @property
    def addon_list(self):
        """Return a list of add-ons slugs."""
        return [addon_data[ATTR_SLUG] for addon_data in self.addons]

    @property
    def folders(self):
        """Return list of saved folders."""
        return self._data[ATTR_FOLDERS]

    @property
    def repositories(self):
        """Return snapshot date."""
        return self._data[ATTR_REPOSITORIES]

    @repositories.setter
    def repositories(self, value):
        """Set snapshot date."""
        self._data[ATTR_REPOSITORIES] = value

    @property
    def homeassistant_version(self):
        """Return snapshot Home Assistant version."""
        return self._data[ATTR_HOMEASSISTANT].get(ATTR_VERSION)

    @property
    def homeassistant(self):
        """Return snapshot Home Assistant data."""
        return self._data[ATTR_HOMEASSISTANT]

    @property
    def size(self):
        """Return snapshot size."""
        if not self.tarfile.is_file():
            return 0
        return round(self.tarfile.stat().st_size / 1048576, 2)  # calc mbyte

    @property
    def is_new(self):
        """Return True if there is new."""
        return not self.tarfile.exists()

    @property
    def tarfile(self):
        """Return path to Snapshot tarfile."""
        return self._tarfile

    def new(self, slug, name, date, sys_type, password=None):
        """Initialize a new snapshot."""
        # Init metadata
        self._data[ATTR_SLUG] = slug
        self._data[ATTR_NAME] = name
        self._data[ATTR_DATE] = date
        self._data[ATTR_TYPE] = sys_type

        # Add defaults
        self._data = SCHEMA_SNAPSHOT(self._data)

        # Set password
        if password:
            self._init_password(password)
            self._data[ATTR_PROTECTED] = password_for_validating(password)
            self._data[ATTR_CRYPTO] = CRYPTO_AES128

    def set_password(self, password: str) -> bool:
        """Set the password for an existing snapshot."""
        if not password:
            return False

        validating = password_for_validating(password)
        if validating != self._data[ATTR_PROTECTED]:
            return False

        self._init_password(password)
        return True

    def _init_password(self, password: str) -> None:
        """Set password + init aes cipher."""
        self._key = password_to_key(password)
        self._aes = Cipher(
            algorithms.AES(self._key),
            modes.CBC(key_to_iv(self._key)),
            backend=default_backend(),
        )

    def _encrypt_data(self, data: str) -> str:
        """Make data secure."""
        if not self._key or data is None:
            return data

        encrypt = self._aes.encryptor()
        padder = padding.PKCS7(128).padder()

        data = padder.update(data.encode()) + padder.finalize()
        return b64encode(encrypt.update(data)).decode()

    def _decrypt_data(self, data: str) -> str:
        """Make data readable."""
        if not self._key or data is None:
            return data

        decrypt = self._aes.decryptor()
        padder = padding.PKCS7(128).unpadder()

        data = padder.update(decrypt.update(b64decode(data))) + padder.finalize()
        return data.decode()

    async def load(self):
        """Read snapshot.json from tar file."""
        if not self.tarfile.is_file():
            _LOGGER.error("No tarfile %s", self.tarfile)
            return False

        def _load_file():
            """Read snapshot.json."""
            with tarfile.open(self.tarfile, "r:") as snapshot:
                json_file = snapshot.extractfile("./snapshot.json")
                return json_file.read()

        # read snapshot.json
        try:
            raw = await self.sys_run_in_executor(_load_file)
        except (tarfile.TarError, KeyError) as err:
            _LOGGER.error("Can't read snapshot tarfile %s: %s", self.tarfile, err)
            return False

        # parse data
        try:
            raw_dict = json.loads(raw)
        except json.JSONDecodeError as err:
            _LOGGER.error("Can't read data for %s: %s", self.tarfile, err)
            return False

        # validate
        try:
            self._data = SCHEMA_SNAPSHOT(raw_dict)
        except vol.Invalid as err:
            _LOGGER.error(
                "Can't validate data for %s: %s",
                self.tarfile,
                humanize_error(raw_dict, err),
            )
            return False

        return True

    async def __aenter__(self):
        """Async context to open a snapshot."""
        self._tmp = TemporaryDirectory(dir=str(self.sys_config.path_tmp))

        # create a snapshot
        if not self.tarfile.is_file():
            return self

        # extract an existing snapshot
        def _extract_snapshot():
            """Extract a snapshot."""
            with tarfile.open(self.tarfile, "r:") as tar:
                tar.extractall(path=self._tmp.name)

        await self.sys_run_in_executor(_extract_snapshot)

    async def __aexit__(self, exception_type, exception_value, traceback):
        """Async context to close a snapshot."""
        # exists snapshot or exception on build
        if self.tarfile.is_file() or exception_type is not None:
            self._tmp.cleanup()
            return

        # validate data
        try:
            self._data = SCHEMA_SNAPSHOT(self._data)
        except vol.Invalid as err:
            _LOGGER.error(
                "Invalid data for %s: %s", self.tarfile, humanize_error(self._data, err)
            )
            raise ValueError("Invalid config") from None

        # new snapshot, build it
        def _create_snapshot():
            """Create a new snapshot."""
            with tarfile.open(self.tarfile, "w:") as tar:
                tar.add(self._tmp.name, arcname=".")

        try:
            write_json_file(Path(self._tmp.name, "snapshot.json"), self._data)
            await self.sys_run_in_executor(_create_snapshot)
        except (OSError, json.JSONDecodeError) as err:
            _LOGGER.error("Can't write snapshot: %s", err)
        finally:
            self._tmp.cleanup()

    async def store_addons(self, addon_list=None):
        """Add a list of add-ons into snapshot."""
        addon_list = addon_list or self.sys_addons.installed

        async def _addon_save(addon):
            """Task to store an add-on into snapshot."""
            addon_file = SecureTarFile(
                Path(self._tmp.name, f"{addon.slug}.tar.gz"), "w", key=self._key
            )

            # Take snapshot
            try:
                await addon.snapshot(addon_file)
            except AddonsError:
                _LOGGER.error("Can't make snapshot from %s", addon.slug)
                return

            # Store to config
            self._data[ATTR_ADDONS].append(
                {
                    ATTR_SLUG: addon.slug,
                    ATTR_NAME: addon.name,
                    ATTR_VERSION: addon.version,
                    ATTR_SIZE: addon_file.size,
                }
            )

        # Run tasks
        tasks = [_addon_save(addon) for addon in addon_list]
        if tasks:
            await asyncio.wait(tasks)

    async def restore_addons(self, addon_list=None):
        """Restore a list add-on from snapshot."""
        addon_list = addon_list or self.addon_list

        async def _addon_restore(addon_slug):
            """Task to restore an add-on into snapshot."""
            addon_file = SecureTarFile(
                Path(self._tmp.name, f"{addon_slug}.tar.gz"), "r", key=self._key
            )

            # If exists inside snapshot
            if not addon_file.path.exists():
                _LOGGER.error("Can't find snapshot for %s", addon_slug)
                return

            # Perform a restore
            try:
                await self.sys_addons.restore(addon_slug, addon_file)
            except AddonsError:
                _LOGGER.error("Can't restore snapshot for %s", addon_slug)

        # Run tasks
        tasks = [_addon_restore(slug) for slug in addon_list]
        if tasks:
            await asyncio.wait(tasks)

    async def store_folders(self, folder_list=None):
        """Backup Hass.io data into snapshot."""
        folder_list = set(folder_list or ALL_FOLDERS)

        def _folder_save(name):
            """Internal function to snapshot a folder."""
            slug_name = name.replace("/", "_")
            tar_name = Path(self._tmp.name, f"{slug_name}.tar.gz")
            origin_dir = Path(self.sys_config.path_hassio, name)

            # Check if exists
            if not origin_dir.is_dir():
                _LOGGER.warning("Can't find snapshot folder %s", name)
                return

            # Take snapshot
            try:
                _LOGGER.info("Snapshot folder %s", name)
                with SecureTarFile(tar_name, "w", key=self._key) as tar_file:
                    tar_file.add(origin_dir, arcname=".")

                _LOGGER.info("Snapshot folder %s done", name)
                self._data[ATTR_FOLDERS].append(name)
            except (tarfile.TarError, OSError) as err:
                _LOGGER.warning("Can't snapshot folder %s: %s", name, err)

        # Run tasks
        tasks = [
            self.sys_run_in_executor(_folder_save, folder) for folder in folder_list
        ]
        if tasks:
            await asyncio.wait(tasks)

    async def restore_folders(self, folder_list=None):
        """Backup Hass.io data into snapshot."""
        folder_list = set(folder_list or self.folders)

        def _folder_restore(name):
            """Intenal function to restore a folder."""
            slug_name = name.replace("/", "_")
            tar_name = Path(self._tmp.name, f"{slug_name}.tar.gz")
            origin_dir = Path(self.sys_config.path_hassio, name)

            # Check if exists inside snapshot
            if not tar_name.exists():
                _LOGGER.warning("Can't find restore folder %s", name)
                return

            # Clean old stuff
            if origin_dir.is_dir():
                remove_folder(origin_dir)

            # Perform a restore
            try:
                _LOGGER.info("Restore folder %s", name)
                with SecureTarFile(tar_name, "r", key=self._key) as tar_file:
                    tar_file.extractall(path=origin_dir)
                _LOGGER.info("Restore folder %s done", name)
            except (tarfile.TarError, OSError) as err:
                _LOGGER.warning("Can't restore folder %s: %s", name, err)

        # Run tasks
        tasks = [
            self.sys_run_in_executor(_folder_restore, folder) for folder in folder_list
        ]
        if tasks:
            await asyncio.wait(tasks)

    def store_homeassistant(self):
        """Read all data from Home Assistant object."""
        self.homeassistant[ATTR_VERSION] = self.sys_homeassistant.version
        self.homeassistant[ATTR_WATCHDOG] = self.sys_homeassistant.watchdog
        self.homeassistant[ATTR_BOOT] = self.sys_homeassistant.boot
        self.homeassistant[ATTR_WAIT_BOOT] = self.sys_homeassistant.wait_boot

        # Custom image
        if self.sys_homeassistant.is_custom_image:
            self.homeassistant[ATTR_IMAGE] = self.sys_homeassistant.image
            self.homeassistant[
                ATTR_LAST_VERSION
            ] = self.sys_homeassistant.latest_version

        # API/Proxy
        self.homeassistant[ATTR_PORT] = self.sys_homeassistant.api_port
        self.homeassistant[ATTR_SSL] = self.sys_homeassistant.api_ssl
        self.homeassistant[ATTR_REFRESH_TOKEN] = self._encrypt_data(
            self.sys_homeassistant.refresh_token
        )
        self.homeassistant[ATTR_PASSWORD] = self._encrypt_data(
            self.sys_homeassistant.api_password
        )

    def restore_homeassistant(self):
        """Write all data to the Home Assistant object."""
        self.sys_homeassistant.watchdog = self.homeassistant[ATTR_WATCHDOG]
        self.sys_homeassistant.boot = self.homeassistant[ATTR_BOOT]
        self.sys_homeassistant.wait_boot = self.homeassistant[ATTR_WAIT_BOOT]

        # Custom image
        if self.homeassistant.get(ATTR_IMAGE):
            self.sys_homeassistant.image = self.homeassistant[ATTR_IMAGE]
            self.sys_homeassistant.latest_version = self.homeassistant[
                ATTR_LAST_VERSION
            ]

        # API/Proxy
        self.sys_homeassistant.api_port = self.homeassistant[ATTR_PORT]
        self.sys_homeassistant.api_ssl = self.homeassistant[ATTR_SSL]
        self.sys_homeassistant.refresh_token = self._decrypt_data(
            self.homeassistant[ATTR_REFRESH_TOKEN]
        )
        self.sys_homeassistant.api_password = self._decrypt_data(
            self.homeassistant[ATTR_PASSWORD]
        )

        # save
        self.sys_homeassistant.save_data()

    def store_repositories(self):
        """Store repository list into snapshot."""
        self.repositories = self.sys_config.addons_repositories

    def restore_repositories(self):
        """Restore repositories from snapshot.

        Return a coroutine.
        """
        return self.sys_store.update_repositories(self.repositories)
Exemple #51
0
 def __init__(self, key, iv):
     cipher = Cipher(AES(key), CTR(iv), backend)
     self.encrypter = cipher.encryptor()
     self.decrypter = cipher.decryptor()
     self.block_size = 128
    def fill_request(self):
        """
        Fill the XML document with data about the requested keys.
        """
        content_id = self.root.get("id")
        # self.use_playready_content_key = False
        system_ids = {}
        # check whether to perform CPIX 2.0 document encryption
        encrypted_response_recipients = self.root.findall(
            "./{urn:dashif:org:cpix}DeliveryDataList/{urn:dashif:org:cpix}DeliveryData"
        )
        if encrypted_response_recipients:
            print("ENCRYPTED-RESPONSE")
            # generate a random document key and HMAC key
            self.document_key = secrets.token_bytes(DOCUMENT_KEY_SIZE)
            self.hmac_key = secrets.token_bytes(HMAC_KEY_SIZE)
            backend = default_backend()
            for delivery_data in encrypted_response_recipients:
                delivery_key = delivery_data.find(
                    "./{urn:dashif:org:cpix}DeliveryKey")
                x509data = delivery_key.find(
                    "./{http://www.w3.org/2000/09/xmldsig#}X509Data")
                x509cert = x509data.find(
                    "./{http://www.w3.org/2000/09/xmldsig#}X509Certificate")
                cert = x509.load_der_x509_certificate(
                    base64.b64decode(x509cert.text), backend)
                public_key = cert.public_key()
                self.public_key = x509cert.text
                asym_padder = asym_padding.OAEP(
                    mgf=asym_padding.MGF1(algorithm=hashes.SHA1()),
                    algorithm=hashes.SHA1(),
                    label=None)
                # encrypt the document and HMAC keys using the x509 public key
                encoded_document_key = public_key.encrypt(
                    self.document_key, asym_padder)
                encoded_hmac_key = public_key.encrypt(self.hmac_key,
                                                      asym_padder)
                # insert document key
                document_key_leaf = element_tree.SubElement(
                    delivery_data, "{urn:dashif:org:cpix}DocumentKey")
                document_key_leaf.set(
                    "Algorithm", "http://www.w3.org/2001/04/xmlenc#aes256-cbc")
                data_leaf = element_tree.SubElement(
                    document_key_leaf, "{urn:dashif:org:cpix}Data")
                secret_leaf = element_tree.SubElement(
                    data_leaf, "{urn:ietf:params:xml:ns:keyprov:pskc}Secret")
                self.insert_encrypted_value(
                    secret_leaf,
                    "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p",
                    base64.b64encode(encoded_document_key).decode('utf-8'))
                # insert HMAC key
                mac_method = element_tree.SubElement(
                    delivery_data, "{urn:dashif:org:cpix}MACMethod")
                mac_method.set(
                    "Algorithm",
                    "http://www.w3.org/2001/04/xmldsig-more#hmac-sha512")
                mac_method_key = element_tree.SubElement(
                    mac_method, "{urn:dashif:org:cpix}Key")
                self.insert_encrypted_value(
                    mac_method_key,
                    "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p",
                    base64.b64encode(encoded_hmac_key).decode('utf-8'))
        else:
            print("CLEAR-RESPONSE")

        for drm_system in self.root.findall(
                "./{urn:dashif:org:cpix}DRMSystemList/{urn:dashif:org:cpix}DRMSystem"
        ):
            kid = drm_system.get("kid")
            system_id = drm_system.get("systemId")
            system_ids[system_id] = kid
            print("SYSTEM-ID {}".format(system_id.lower()))
            self.fixup_document(drm_system, system_id, content_id, kid)

        for content_key in self.root.findall(
                "./{urn:dashif:org:cpix}ContentKeyList/{urn:dashif:org:cpix}ContentKey"
        ):
            kid = content_key.get("kid")
            init_vector = content_key.get("explicitIV")
            data = element_tree.SubElement(content_key,
                                           "{urn:dashif:org:cpix}Data")
            secret = element_tree.SubElement(
                data, "{urn:ietf:params:xml:ns:keyprov:pskc}Secret")
            # HLS SAMPLE AES Only
            if init_vector is None and system_ids.get(HLS_SAMPLE_AES_SYSTEM_ID,
                                                      False) == kid:
                content_key.set(
                    'explicitIV',
                    base64.b64encode(self.generator.key(content_id,
                                                        kid)).decode('utf-8'))
            # generate the key
            key_bytes = self.generator.key(content_id, kid)
            # store to the key in the cache
            self.cache.store(content_id, kid, key_bytes)
            # log
            print("NEW-KEY {} {}".format(content_id, kid))
            # update the encrypted response
            if encrypted_response_recipients:
                # store the key encrypted
                padder = padding.PKCS7(algorithms.AES.block_size).padder()
                padded_data = padder.update(key_bytes) + padder.finalize()
                random_iv = secrets.token_bytes(RANDOM_IV_SIZE)
                cipher = Cipher(algorithms.AES(self.document_key),
                                modes.CBC(random_iv),
                                backend=backend)
                encryptor = cipher.encryptor()
                encrypted_data = encryptor.update(
                    padded_data) + encryptor.finalize()
                cipher_data = random_iv + encrypted_data
                encrypted_string = base64.b64encode(cipher_data).decode(
                    'utf-8')
                self.insert_encrypted_value(
                    secret, "http://www.w3.org/2001/04/xmlenc#aes256-cbc",
                    encrypted_string)
            else:
                plain_value = element_tree.SubElement(
                    secret, "{urn:ietf:params:xml:ns:keyprov:pskc}PlainValue")
                # PLAYREADY ONLY
                if self.use_playready_content_key:
                    plain_value.text = PLAYREADY_CONTENT_KEY
                else:
                    plain_value.text = base64.b64encode(key_bytes).decode(
                        'utf-8')
Exemple #53
0
def cc2_enc(key, plain, nonce):
    alg = cc2(key, nonce)
    cipher = Cipher(alg, mode=None)
    encryptor = cipher.encryptor()
    ct = encryptor.update(plain)
    return ct
def encrypt_string(plaintext, encryption_key):
    salt = str(uuid4())[:16]
    cipher = Cipher(algorithms.AES(encryption_key), modes.CBC(salt.encode()), backend=default_backend())
    encryptor = cipher.encryptor()
    encrypted = encryptor.update(pad(plaintext, 128).encode()) + encryptor.finalize()
    return base64.b64encode(bytes(salt, 'utf-8') + encrypted).decode('utf-8')
Exemple #55
0
# The book can be downloaded from https://leanpub.com/cryptop
# Online Crypto Playgroud https://8gwifi.org
# Author Anish Nath

backend = default_backend()

# This AES key is 256 but long
mykey = "mysecretkeyisverystrongofbitlong".encode("hex")
message = "Hello 8gwifi.org"

#AES-256 ECB Mode Encyption

cipher = Cipher(algorithms.AES(mykey.decode('hex')),
                modes.ECB(),
                backend=backend)
e = cipher.encryptor()
ct = e.update(message) + e.finalize()

#AES-256 ECB Mode Decryption
#Using same Cipher Object
d = cipher.decryptor()

clear = d.update(ct) + d.finalize()

assert clear, message

#AES-256 CBC Mode Encyption

iv = os.urandom(16)
cipher = Cipher(algorithms.AES(mykey.decode('hex')),
                modes.CBC(iv),
Exemple #56
0
class device:
    """Controls a Broadlink device."""

    def __init__(
        self,
        host: Tuple[str, int],
        mac: Union[bytes, str],
        devtype: int,
        timeout: int = 10,
        name: str = None,
        model: str = None,
        manufacturer: str = None,
        is_locked: bool = None,
    ) -> None:
        """Initialize the controller."""
        self.host = host
        self.mac = bytes.fromhex(mac) if isinstance(mac, str) else mac
        self.devtype = devtype if devtype is not None else 0x272A
        self.timeout = timeout
        self.name = name
        self.model = model
        self.manufacturer = manufacturer
        self.is_locked = is_locked
        self.count = random.randrange(0xFFFF)
        self.iv = bytes.fromhex("562e17996d093d28ddb3ba695a2e6f58")
        self.id = bytes(4)
        self.type = "Unknown"
        self.lock = threading.Lock()

        self.aes = None
        key = bytes.fromhex("097628343fe99e23765c1513accf8b02")
        self.update_aes(key)

    def __repr__(self):
        return "<%s: %s %s (%s) at %s:%s | %s | %s | %s>" % (
            type(self).__name__,
            self.manufacturer,
            self.model,
            hex(self.devtype),
            self.host[0],
            self.host[1],
            ":".join(format(x, "02x") for x in self.mac),
            self.name,
            "Locked" if self.is_locked else "Unlocked",
        )

    def update_aes(self, key: bytes) -> None:
        """Update AES."""
        self.aes = Cipher(
            algorithms.AES(key), modes.CBC(self.iv), backend=default_backend()
        )

    def encrypt(self, payload: bytes) -> bytes:
        """Encrypt the payload."""
        encryptor = self.aes.encryptor()
        return encryptor.update(payload) + encryptor.finalize()

    def decrypt(self, payload: bytes) -> bytes:
        """Decrypt the payload."""
        decryptor = self.aes.decryptor()
        return decryptor.update(payload) + decryptor.finalize()

    def auth(self) -> bool:
        """Authenticate to the device."""
        payload = bytearray(0x50)
        payload[0x04] = 0x31
        payload[0x05] = 0x31
        payload[0x06] = 0x31
        payload[0x07] = 0x31
        payload[0x08] = 0x31
        payload[0x09] = 0x31
        payload[0x0A] = 0x31
        payload[0x0B] = 0x31
        payload[0x0C] = 0x31
        payload[0x0D] = 0x31
        payload[0x0E] = 0x31
        payload[0x0F] = 0x31
        payload[0x10] = 0x31
        payload[0x11] = 0x31
        payload[0x12] = 0x31
        payload[0x1E] = 0x01
        payload[0x2D] = 0x01
        payload[0x30] = ord("T")
        payload[0x31] = ord("e")
        payload[0x32] = ord("s")
        payload[0x33] = ord("t")
        payload[0x34] = ord(" ")
        payload[0x35] = ord(" ")
        payload[0x36] = ord("1")

        response = self.send_packet(0x65, payload)
        check_error(response[0x22:0x24])
        payload = self.decrypt(response[0x38:])

        key = payload[0x04:0x14]
        if len(key) % 16 != 0:
            return False

        self.id = payload[0x03::-1]
        self.update_aes(key)
        return True

    def hello(self, local_ip_address=None) -> bool:
        """Send a hello message to the device.

        Device information is checked before updating name and lock status.
        """
        responses = scan(
            timeout=self.timeout,
            local_ip_address=local_ip_address,
            discover_ip_address=self.host[0],
            discover_ip_port=self.host[1],
        )
        try:
            devtype, host, mac, name, is_locked = next(responses)
        except StopIteration:
            raise exception(-4000)  # Network timeout.

        if (devtype, host, mac) != (self.devtype, self.host, self.mac):
            raise exception(-2040)  # Device information is not intact.

        self.name = name
        self.is_locked = is_locked
        return True

    def get_fwversion(self) -> int:
        """Get firmware version."""
        packet = bytearray([0x68])
        response = self.send_packet(0x6A, packet)
        check_error(response[0x22:0x24])
        payload = self.decrypt(response[0x38:])
        return payload[0x4] | payload[0x5] << 8

    def set_name(self, name: str) -> None:
        """Set device name."""
        packet = bytearray(4)
        packet += name.encode("utf-8")
        packet += bytearray(0x50 - len(packet))
        packet[0x43] = bool(self.is_locked)
        response = self.send_packet(0x6A, packet)
        check_error(response[0x22:0x24])
        self.name = name

    def set_lock(self, state: bool) -> None:
        """Lock/unlock the device."""
        packet = bytearray(4)
        packet += self.name.encode("utf-8")
        packet += bytearray(0x50 - len(packet))
        packet[0x43] = bool(state)
        response = self.send_packet(0x6A, packet)
        check_error(response[0x22:0x24])
        self.is_locked = bool(state)

    def get_type(self) -> str:
        """Return device type."""
        return self.type

    def send_packet(self, command: int, payload: bytes) -> bytes:
        """Send a packet to the device."""
        self.count = (self.count + 1) & 0xFFFF
        packet = bytearray(0x38)
        packet[0x00] = 0x5A
        packet[0x01] = 0xA5
        packet[0x02] = 0xAA
        packet[0x03] = 0x55
        packet[0x04] = 0x5A
        packet[0x05] = 0xA5
        packet[0x06] = 0xAA
        packet[0x07] = 0x55
        packet[0x24] = self.devtype & 0xFF
        packet[0x25] = self.devtype >> 8
        packet[0x26] = command
        packet[0x28] = self.count & 0xFF
        packet[0x29] = self.count >> 8
        packet[0x2A] = self.mac[5]
        packet[0x2B] = self.mac[4]
        packet[0x2C] = self.mac[3]
        packet[0x2D] = self.mac[2]
        packet[0x2E] = self.mac[1]
        packet[0x2F] = self.mac[0]
        packet[0x30] = self.id[3]
        packet[0x31] = self.id[2]
        packet[0x32] = self.id[1]
        packet[0x33] = self.id[0]

        # pad the payload for AES encryption
        padding = (16 - len(payload)) % 16
        if padding:
            payload = bytearray(payload)
            payload += bytearray(padding)

        checksum = sum(payload, 0xBEAF) & 0xFFFF
        packet[0x34] = checksum & 0xFF
        packet[0x35] = checksum >> 8

        payload = self.encrypt(payload)
        for i in range(len(payload)):
            packet.append(payload[i])

        checksum = sum(packet, 0xBEAF) & 0xFFFF
        packet[0x20] = checksum & 0xFF
        packet[0x21] = checksum >> 8

        start_time = time.time()
        with self.lock:
            conn = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            conn.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

            while True:
                try:
                    conn.sendto(packet, self.host)
                    conn.settimeout(1)
                    resp, _ = conn.recvfrom(2048)
                    break
                except socket.timeout:
                    if (time.time() - start_time) > self.timeout:
                        conn.close()
                        raise exception(-4000)  # Network timeout.
            conn.close()

        if len(resp) < 0x30:
            raise exception(-4007)  # Length error.

        checksum = resp[0x20] | (resp[0x21] << 8)
        if sum(resp, 0xBEAF) - sum(resp[0x20:0x22]) & 0xFFFF != checksum:
            raise exception(-4008)  # Checksum error.

        return resp
Exemple #57
0
aes_cbc_iv = binascii.unhexlify(args.cbc_iv)
aes_cbc_key = binascii.unhexlify(args.cbc_key)
aes_cmac_key = binascii.unhexlify(args.cmac_key)

# Add padding to source file
data = input_bin_file.read().decode('latin-1')
data_size = len(data)
data_padding = data_size % DECRYPT_PKT_SIZE
data = data + PAD_INIT + NULL * (DECRYPT_PKT_SIZE - data_padding - 1)
data_size = len(data)
num_dec_pkts = old_div(data_size, DECRYPT_PKT_SIZE)

# Encrypt data
backend = default_backend()
cipher = Cipher(algorithms.AES(aes_cbc_key), modes.CBC(aes_cbc_iv), backend)
encryptor = cipher.encryptor()
decryptor = cipher.decryptor()

cipher_text = encryptor.update(data.encode('latin-1'))
cipher_size = len(cipher_text)

cipher_dec_text = decryptor.update(cipher_text)

if (data.encode('latin-1') == cipher_dec_text):
    print('CIPHER OK')
else:
    print('CIPHER ERROR, src_size: ' + str(len(data)) + ' decrypt_size :' +
          str(len(cipher_dec_text)))

# Get signature
signer = cmac.CMAC(algorithms.AES(aes_cmac_key), backend)
class AES:
    def __init__(self, create_key=True):
        if create_key == True:
            self.key = os.urandom(32)  #Generate a random key
            self.iv = os.urandom(16)
            self.cipher = Cipher(
                algorithms.AES(self.key),
                modes.CBC(self.iv),
                backend=default_backend())  #Using cryptography AES
            self.encryptor = self.cipher.encryptor()
            self.decryptor = self.cipher.decryptor()
        else:
            self.key = None
            self.iv = None
            self.cipher = None

    def Encrypt(
        self, message
    ):  #Encrypt message if only the message is in bytes and if the cipher is initialized
        if type(message) == bytes:
            if self.cipher != None:
                self.encryptor = self.cipher.encryptor()
                total_bytes_needed = (ceil(len(message) / 16) *
                                      16) - len(message)
                message += b"\0" * total_bytes_needed
                return self.encryptor.update(
                    message) + self.encryptor.finalize()
            else:
                logging.fatal(
                    "Tried to encrypt a message while AES wasn't fully initialized"
                )
        else:
            raise TypeError(
                "The message must be in bytes and not in {}".format(
                    type(message)))

    def Decrypt(self, ciphertext):
        if type(ciphertext) == bytes:
            if self.cipher != None:
                self.decryptor = self.cipher.decryptor()
                return (self.decryptor.update(ciphertext) +
                        self.decryptor.finalize()).split(b'\0', 1)[0]
            else:
                logging.fatal(
                    "Tried to decrypt a message while AES wasn't fully initialized"
                )
        else:
            raise TypeError(
                "The ciphertext must be in bytes and not in {}".format(
                    type(ciphertext)))

    def GetKey(self):
        key = base64.b64encode(self.key).decode("utf-8")
        iv = base64.b64encode(self.iv).decode("utf-8")
        return json.dumps({
            'key': key,
            'iv': iv,
            'aesisfkncool': True
        }).encode("utf-8")

    def LoadKey(self, key):
        if type(key) == bytes:
            key_dict = json.loads(key.decode("utf-8"))  #Load to a dictionary
            try:
                self.key = base64.b64decode(key_dict['key'].encode("utf-8"))
                self.iv = base64.b64decode(key_dict['iv'].encode("utf-8"))
            except KeyError:
                raise TypeError("This key it isn't in a valid format.")
            self.cipher = Cipher(algorithms.AES(self.key),
                                 modes.CBC(self.iv),
                                 backend=default_backend())
            self.encryptor = self.cipher.encryptor()
            self.decryptor = self.cipher.decryptor()
        else:
            raise TypeError("Key must be in bytes and not in {}".format(
                type(key)))
Exemple #59
0
def encryptStream(fIn, fOut, passw, bufferSize):
    # validate bufferSize
    if bufferSize % AESBlockSize != 0:
        raise ValueError("Buffer size must be a multiple of AES block size.")

    if len(passw) > maxPassLen:
        raise ValueError("Password is too long.")

    # generate external iv (used to encrypt the main iv and the
    # encryption key)
    iv1 = urandom(AESBlockSize)

    # stretch password and iv
    key = stretch(passw, iv1)

    # generate random main iv
    iv0 = urandom(AESBlockSize)

    # generate random internal key
    intKey = urandom(32)

    # instantiate AES cipher
    cipher0 = Cipher(algorithms.AES(intKey),
                     modes.CBC(iv0),
                     backend=default_backend())
    encryptor0 = cipher0.encryptor()

    # instantiate HMAC-SHA256 for the ciphertext
    hmac0 = hmac.HMAC(intKey, hashes.SHA256(), backend=default_backend())

    # instantiate another AES cipher
    cipher1 = Cipher(algorithms.AES(key),
                     modes.CBC(iv1),
                     backend=default_backend())
    encryptor1 = cipher1.encryptor()

    # encrypt main iv and key
    c_iv_key = encryptor1.update(iv0 + intKey) + encryptor1.finalize()

    # calculate HMAC-SHA256 of the encrypted iv and key
    hmac1 = hmac.HMAC(key, hashes.SHA256(), backend=default_backend())
    hmac1.update(c_iv_key)

    # write header
    fOut.write(bytes("AES", "utf8"))

    # write version (AES Crypt version 2 file format -
    # see https://www.aescrypt.com/aes_file_format.html)
    fOut.write(b"\x02")

    # reserved byte (set to zero)
    fOut.write(b"\x00")

    # setup "CREATED-BY" extension
    cby = "pyAesCrypt " + version

    # write "CREATED-BY" extension length
    fOut.write(b"\x00" + bytes([1 + len("CREATED_BY" + cby)]))

    # write "CREATED-BY" extension
    fOut.write(bytes("CREATED_BY", "utf8") + b"\x00" + bytes(cby, "utf8"))

    # write "container" extension length
    fOut.write(b"\x00\x80")

    # write "container" extension
    for i in range(128):
        fOut.write(b"\x00")

    # write end-of-extensions tag
    fOut.write(b"\x00\x00")

    # write the iv used to encrypt the main iv and the
    # encryption key
    fOut.write(iv1)

    # write encrypted main iv and key
    fOut.write(c_iv_key)

    # write HMAC-SHA256 of the encrypted iv and key
    fOut.write(hmac1.finalize())

    # encrypt file while reading it
    while True:
        # try to read bufferSize bytes
        fdata = fIn.read(bufferSize)

        # get the real number of bytes read
        bytesRead = len(fdata)

        # check if EOF was reached
        if bytesRead < bufferSize:
            # file size mod 16, lsb positions
            fs16 = bytes([bytesRead % AESBlockSize])
            # pad data (this is NOT PKCS#7!)
            # ...unless no bytes or a multiple of a block size
            # of bytes was read
            if bytesRead % AESBlockSize == 0:
                padLen = 0
            else:
                padLen = 16 - bytesRead % AESBlockSize
            fdata += bytes([padLen]) * padLen
            # encrypt data
            cText = encryptor0.update(fdata) \
                    + encryptor0.finalize()
            # update HMAC
            hmac0.update(cText)
            # write encrypted file content
            fOut.write(cText)
            # break
            break
        # ...otherwise a full bufferSize was read
        else:
            # encrypt data
            cText = encryptor0.update(fdata)
            # update HMAC
            hmac0.update(cText)
            # write encrypted file content
            fOut.write(cText)

    # write plaintext file size mod 16 lsb positions
    fOut.write(fs16)

    # write HMAC-SHA256 of the encrypted file
    fOut.write(hmac0.finalize())
def encrypt_aes_128_block(msg, key):
    '''unpadded AES block encryption'''
    cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=backend)
    encryptor = cipher.encryptor()
    return encryptor.update(msg) + encryptor.finalize()