def header_protection_mask(self, sample: bytes) -> bytes: if self.cipher_suite == CipherSuite.CHACHA20_POLY1305_SHA256: encryptor = Cipher( algorithms.ChaCha20(key=self.hp, nonce=sample), mode=None, backend=default_backend(), ).encryptor() buf = bytearray(5) encryptor.update_into(bytes(5), buf) return bytes(buf) else: encryptor = Cipher(algorithms.AES(self.hp), mode=modes.ECB(), backend=default_backend()).encryptor() buf = bytearray(31) encryptor.update_into(sample, buf) return buf[:5]
def encrypt(mode, key, iv, inputBytes): backend = default_backend() encryptor = Cipher(algorithms.AES(key), mode, backend=backend).encryptor() if isinstance(mode, modes.CBC): length = ceil(len(inputBytes) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE else: length = len(inputBytes) + AES_BLOCK_SIZE - 1 buf = bytearray(length) lenEncrypted = encryptor.update_into(inputBytes, buf) ct = bytes(buf[:lenEncrypted]) + encryptor.finalize() return ct
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:]