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()
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()
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()
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()
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()
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
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)
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
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
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)
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
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())
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)
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)
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'))
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
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()
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()
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
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
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)
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)
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)
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))
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
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))
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
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)
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()
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)
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
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
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)
@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')
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
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]
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
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()
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)
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()
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)
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')
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')
# 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),
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
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)))
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()