def __init__(self, path, mode, callback, event, encrypted_upload=False, key=None, iv=None, *args): file.__init__(self, path, mode) self.event = event self.encrypted_upload = encrypted_upload self.seek(0, os.SEEK_END) if self.encrypted_upload: if os.name == 'nt': self.backend = backend else: self.backend = default_backend() self.encryptor = Cipher(algorithms.AES(key), GCM(iv), backend=self.backend).encryptor() self._total = self.tell() + TAGSIZE else: self._total = self.tell() self.seek(0) self._callback = callback self._args = args self._seen = 0
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 aes_decrypt_fast(self, key, iv, payload): # Use AES128 GCM with the given key and iv to decrypt the payload. data = payload[:-16] tag = payload[-16:] decryptor = Cipher(algorithms.AES(key), GCM(iv, tag=tag), backend=self.backend).decryptor() return decryptor.update(data) + decryptor.finalize()
def aes_decrypt(key, iv, payload): """ Use AES128 GCM with the given key and iv to decrypt the payload. """ data = payload[:-16] tag = payload[-16:] backend = default_backend() decryptor = Cipher(algorithms.AES(key), GCM(iv, tag=tag), backend=backend).decryptor() return decryptor.update(data) + decryptor.finalize()
def encrypt(self, cleartext: bytes): # No need for padding as we are using GCM # Get a new iv for GCM iv = urandom(int(AES.block_size // 8)) cipher = Cipher(self._hazmat_key, GCM(iv), backend=openssl) encryptor = cipher.encryptor() enc = encryptor.update(cleartext) + encryptor.finalize() return iv + enc + encryptor.tag
def aes_encrypt(key, iv, plaintext): """ Use AES128 GCM with the given key and iv to encrypt the plaintext. """ if os.name == 'nt': _backend = backend else: _backend = default_backend() encryptor = Cipher(algorithms.AES(key), GCM(iv), backend=_backend).encryptor() return encryptor.update(plaintext) + encryptor.finalize(), encryptor.tag
def aes_decrypt(self, payload): # Use AES128 GCM with the given key and iv to decrypt the payload. payload = payload.getvalue() data = payload[:-16] tag = payload[-16:] decryptor = Cipher(algorithms.AES(self.file.key), GCM(self.file.iv, tag=tag), backend=default_backend()).decryptor() return decryptor.update(data) + decryptor.finalize()
def _encrypt(data, key_size, iv_size): if isinstance(data, str): data = data.encode() key = os.urandom(key_size) iv = os.urandom(iv_size) encryptor = Cipher(algorithms.AES(key), GCM(iv), backend=default_backend()).encryptor() payload = encryptor.update(data) + encryptor.finalize() return key, iv, encryptor.tag, payload
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 pytest.raises(UnsupportedAlgorithm): cipher.encryptor()
def _aes_decrypt_fast(self, key, iv, payload): # Use AES128 GCM with the given key and iv to decrypt the payload. if os.name == 'nt': be = backend else: be = default_backend() data = payload[:-16] tag = payload[-16:] decryptor = Cipher(algorithms.AES(key), GCM(iv, tag=tag), backend=be).decryptor() return decryptor.update(data) + decryptor.finalize()
def encrypt_and_sign(self, header, data): encryptor = Cipher(self._cipher(self._key), GCM(self._iv), default_backend()).encryptor() if header: encryptor.authenticate_additional_data(header) ciphertext = encryptor.update(data) + encryptor.finalize() self._update_iv() return ciphertext, encryptor.tag
def encrypt_and_sign(self, header, data): """Encrypt and sign a block of data""" encryptor = Cipher(self._cipher(self._key), GCM(self._iv), default_backend()).encryptor() if header: encryptor.authenticate_additional_data(header) data = encryptor.update(data) + encryptor.finalize() self._update_iv() return header + data, encryptor.tag
def encrypt(self, msg, aad, iv, key): """Key Encryption with AES GCM :param msg: text to be encrypt in bytes :param aad: additional authenticated data in bytes :param iv: initialization vector in bytes :param key: encrypted key in bytes :return: (ciphertext, iv, tag) """ self.check_iv(iv) cipher = Cipher(AES(key), GCM(iv), backend=default_backend()) enc = cipher.encryptor() enc.authenticate_additional_data(aad) ciphertext = enc.update(msg) + enc.finalize() return ciphertext, enc.tag
def verify_and_decrypt(self, header, data, tag): decryptor = Cipher(self._cipher(self._key), GCM(self._iv, tag), default_backend()).decryptor() if header: decryptor.authenticate_additional_data(header) try: plaintext = decryptor.update(data) + decryptor.finalize() except InvalidTag: plaintext = None self._update_iv() return plaintext
def decrypt(self, ciphertext, aad, iv, tag, key): """Key Decryption with AES GCM :param ciphertext: ciphertext in bytes :param aad: additional authenticated data in bytes :param iv: initialization vector in bytes :param tag: authentication tag in bytes :param key: encrypted key in bytes :return: message """ self.check_iv(iv) cipher = Cipher(AES(key), GCM(iv, tag), backend=default_backend()) d = cipher.decryptor() d.authenticate_additional_data(aad) return d.update(ciphertext) + d.finalize()
def parse_frame(self, frame): # type: (bytes) -> bytes """Parse one encrypted frame (without size header) and get cleartext data.""" if len(frame) < IV_SIZE + 16: raise AuthenticationError("Frame too short") try: iv = frame[:IV_SIZE] gcm_tag = frame[-16:] cipher_text = frame[IV_SIZE:-16] cipher = Cipher(AES(self._key), GCM(iv), default_backend()) decryptor = cipher.decryptor() clear_text = decryptor.update( cipher_text) + decryptor.finalize_with_tag(gcm_tag) return clear_text except InvalidTag: raise AuthenticationError("Invalid GCM authentication tag")
def verify_and_decrypt(self, header, data, mac): """Verify the signature of and decrypt a block of data""" decryptor = Cipher(self._cipher(self._key), GCM(self._iv, mac), default_backend()).decryptor() decryptor.authenticate_additional_data(header) try: data = decryptor.update(data) + decryptor.finalize() except InvalidTag: data = None self._update_iv() return data
def emit_frame(self, data, with_size_header=False): # type: (bytes, bool) -> bytes """Emit one encrypted frame from input data ready to be send to the client.""" iv = os.urandom(IV_SIZE) cipher = Cipher(AES(self._key), GCM(iv), default_backend()) encryptor = cipher.encryptor() frame_list = [ iv, encryptor.update(data), encryptor.finalize(), encryptor.tag ] frame = b"".join(frame_list) if with_size_header: frame = b"".join([struct.pack("!I", len(frame)), frame]) return frame
def wrap(self, cek, headers, key): self._check_key(key) #: https://tools.ietf.org/html/rfc7518#section-4.7.1.1 #: The "iv" (initialization vector) Header Parameter value is the #: base64url-encoded representation of the 96-bit IV value iv_size = 96 iv = os.urandom(iv_size // 8) cipher = Cipher(AES(key), GCM(iv), backend=default_backend()) enc = cipher.encryptor() ek = enc.update(cek) + enc.finalize() h = { 'iv': to_native(urlsafe_b64encode(iv)), 'tag': to_native(urlsafe_b64encode(enc.tag)) } return {'ek': ek, 'header': h}
def unwrap(self, ek, headers, key): self._check_key(key) iv = headers.get('iv') if not iv: raise ValueError('Missing "iv" in headers') tag = headers.get('tag') if not tag: raise ValueError('Missing "tag" in headers') iv = urlsafe_b64decode(to_bytes(iv)) tag = urlsafe_b64decode(to_bytes(tag)) cipher = Cipher(AES(key), GCM(iv, tag), backend=default_backend()) d = cipher.decryptor() cek = d.update(ek) + d.finalize() return cek
def unwrap(self, enc_alg, ek, headers, key): op_key = key.get_op_key('unwrapKey') self._check_key(op_key) iv = headers.get('iv') if not iv: raise ValueError('Missing "iv" in headers') tag = headers.get('tag') if not tag: raise ValueError('Missing "tag" in headers') iv = urlsafe_b64decode(to_bytes(iv)) tag = urlsafe_b64decode(to_bytes(tag)) cipher = Cipher(AES(op_key), GCM(iv, tag), backend=default_backend()) d = cipher.decryptor() cek = d.update(ek) + d.finalize() if len(cek) * 8 != enc_alg.CEK_SIZE: raise ValueError('Invalid "cek" length') return cek
def aes_decrypt(_key, iv, payload): """ Use AES128 GCM with the given key and iv to decrypt the payload. """ if len(_key) >= 32: # XEP-0384 log.debug('XEP Compliant Key/Tag') data = payload key = _key[:16] tag = _key[16:] else: # Legacy log.debug('Legacy Key/Tag') data = payload[:-16] key = _key tag = payload[-16:] if os.name == 'nt': _backend = backend else: _backend = default_backend() decryptor = Cipher(algorithms.AES(key), GCM(iv, tag=tag), backend=_backend).decryptor() return decryptor.update(data) + decryptor.finalize()
def _encrypt(self, data: typing.Iterable[bytes]) -> typing.Iterable[bytes]: eprikey = x25519.X25519PrivateKey.generate() epubkey_bytes = eprikey.public_key().public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) yield epubkey_bytes assert self._PUBKEY_SIZE_BYTES == len(epubkey_bytes) iv = os.urandom(self._IV_SIZE_BYTES) yield iv shared_secret = eprikey.exchange(self._enc_pubkey) cipher_key = self._derive_keys(shared_secret, iv) cipher_iv = iv[:self._CIPHER_IV_SIZE_BYTES] encryptor = Cipher(algorithm=self._CIPHER(cipher_key), mode=GCM(cipher_iv), backend=self._CRYPTO_BACKEND).encryptor() for chunk in data: yield encryptor.update(chunk) yield encryptor.finalize() yield encryptor.tag
def wrap(self, enc_alg, headers, key, preset=None): if preset and 'cek' in preset: cek = preset['cek'] else: cek = enc_alg.generate_cek() op_key = key.get_op_key('wrapKey') self._check_key(op_key) #: https://tools.ietf.org/html/rfc7518#section-4.7.1.1 #: The "iv" (initialization vector) Header Parameter value is the #: base64url-encoded representation of the 96-bit IV value iv_size = 96 iv = os.urandom(iv_size // 8) cipher = Cipher(AES(op_key), GCM(iv), backend=default_backend()) enc = cipher.encryptor() ek = enc.update(cek) + enc.finalize() h = { 'iv': to_native(urlsafe_b64encode(iv)), 'tag': to_native(urlsafe_b64encode(enc.tag)) } return {'ek': ek, 'cek': cek, 'header': h}
def _decrypt(cls, fobj: io.BufferedIOBase, input_size: typing.Optional[int], privkey: x25519.X25519PrivateKey, chunk_size: int) -> typing.Iterable[bytes]: if input_size is None: input_size = cls._get_size_till_eof(fobj) epubkey = x25519.X25519PublicKey.from_public_bytes( cls._read_exact(fobj, cls._PUBKEY_SIZE_BYTES)) input_size -= cls._PUBKEY_SIZE_BYTES shared_secret = privkey.exchange(epubkey) iv = cls._read_exact(fobj, cls._IV_SIZE_BYTES) input_size -= cls._IV_SIZE_BYTES cipher_key = cls._derive_keys(shared_secret, iv) cipher_iv = iv[:cls._CIPHER_IV_SIZE_BYTES] decryptor = Cipher(algorithm=cls._CIPHER(cipher_key), mode=GCM(cipher_iv), backend=cls._CRYPTO_BACKEND).decryptor() if input_size < cls._AUTH_TAG_SIZE_BYTES: raise RuntimeError('input_size is too short') bufmv = memoryview(bytearray(chunk_size)) auth_tag = b'' while input_size > 0: bytes_read = fobj.readinto(bufmv) if bytes_read == 0: break input_size -= bytes_read if input_size <= cls._AUTH_TAG_SIZE_BYTES: auth_tag_part_len = cls._AUTH_TAG_SIZE_BYTES - input_size auth_tag += bufmv[bytes_read - auth_tag_part_len:bytes_read] auth_tag += fobj.read() yield decryptor.update(bufmv[:bytes_read - auth_tag_part_len]) else: yield decryptor.update(bufmv[:bytes_read]) yield decryptor.finalize_with_tag(auth_tag)
def decrypt_packet(data): data = bytearray(data) data_len = len(data) offset = 0 if data[4] not in IQUIC.VERSIONS: return None salt = IQUIC.QUIC_VERSION_PARAMETERS[data[4]]['salt'] offset = 5 dcid_len = data[offset] dcid = data[offset + 1:offset + 1 + dcid_len] offset += 1 + dcid_len if offset >= data_len: return None scid_len = data[offset] scid = data[offset + 1:offset + 1 + scid_len] offset += 1 + scid_len if offset >= data_len: return None token_len = data[offset] token = data[offset + 1:offset + 1 + token_len] offset += 2 + token_len if offset >= data_len: return None initial_secret = IQUIC.hmac(salt, SHA256(), dcid) client_initial_secret = IQUIC.kdf_tls13(initial_secret, b'client in', 32) key = IQUIC.kdf_tls13(client_initial_secret, b'quic key', 16) iv = IQUIC.kdf_tls13(client_initial_secret, b'quic iv', 12) hp = IQUIC.kdf_tls13(client_initial_secret, b'quic hp', 16) hp_encryptor = Cipher(algorithms.AES(hp), mode=modes.ECB(), backend=default_backend()).encryptor() buf = bytearray(31) sample = data[offset + 4:offset + 4 + IQUIC.SAMPLE_SIZE] hp_encryptor.update_into(sample, buf) mask = buf[:5] data[0] ^= mask[0] & 0x0F pn_length = (data[0] & 0x03) + 1 if offset + pn_length >= data_len: return None for i in range(pn_length): data[offset + i] ^= mask[1 + i] pn = data[offset:offset + pn_length] plain_header = data[:offset + pn_length] nonce = bytearray(len(iv) - pn_length) + bytearray(pn) for i in range(len(iv)): nonce[i] ^= iv[i] cipher = Cipher(AES(key), GCM(iv), backend=default_backend()) payload = cipher.decryptor().update(bytes(data[offset + pn_length:])) return payload[4:]
def decrypt(self, ciphertext: bytes): iv = ciphertext[:AES.block_size // 8] tag = ciphertext[-16:] cipher = Cipher(self._hazmat_key, GCM(iv, tag), backend=openssl).decryptor() return cipher.update(ciphertext[16:-16]) + cipher.finalize()
def _decrypt(key, iv, tag, data): decryptor = Cipher(algorithms.AES(key), GCM(iv, tag=tag), backend=default_backend()).decryptor() return decryptor.update(data) + decryptor.finalize()