def decrypt(infile, outfile, key): iv = infile.read(12) if len(iv) != 12: raise Exception('IV of incorrect length was read from input.') decryptor = Cipher( algorithms.AES(key), modes.GCM(iv), backend=backend, ).decryptor() buff = b'' for block in read_blocks(infile): block = buff + block buff = block[-16:] block = block[:-16] outfile.write(decryptor.update(block)) decryptor.finalize_with_tag(buff)
def decrypt(self, key, verbose=False): assert (isinstance(key, bytes)) (meta, dkey) = self.kdf(self._header["kdf"], key, salt=bytes.fromhex(self._header["kdf"]["salt"]), verbose=verbose) if self._header["cipher"]["name"] == "AES256-GCM": iv = bytes.fromhex(self._header["cipher"]["iv"]) decryptor = Cipher(algorithms.AES(dkey), modes.GCM(iv), backend=_backend).decryptor() plaintext = decryptor.update(self._encrypted_payload) tag = bytes.fromhex(self._header["cipher"]["tag"]) decryptor.finalize_with_tag(tag) else: raise NotImplementedError(self._header["cipher"]["name"]) return plaintext
def pay(): token = ast.literal_eval(raw_input("Token: ")) iv = token["iv"].decode("hex") enc = token["enc"].decode("hex") tag = token["tag"].decode("hex") decryptor = Cipher( algorithms.AES(key), modes.GCM(iv), backend=default_backend() ).decryptor() account = ast.literal_eval(decryptor.update(enc) + decryptor.finalize_with_tag(tag)) if account["balance"] != 1000 and account["admin"] == "N": print("Huh? you have no money and want the flag? -.-") else: print(flag)
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 receive(self, message_id, outfp=None, access_method=AccessMethod.view, extra_key_hashes=None, max_size=None): if not self.ok: raise NotReady() merged_url, headers = self.merge_and_headers(self.url, raw="embed") response = self.session.get(merge_get_url(self.url, raw="embed"), headers=headers) response.raise_for_status() graph = Graph() graph.parse(data=response.content, format="turtle") self.retrieve_missing(graph, merged_url) result = list( graph.query( """ SELECT DISTINCT ?base ?hash_algorithm ?type WHERE { ?base a <https://spkcspider.net/static/schemes/spkcgraph#spkc:Content> ; spkc:type ?type ; spkc:properties ?propalg , ?propid . ?propid spkc:name ?idname ; spkc:value ?idvalue . ?propalg spkc:name ?algname ; spkc:value ?hash_algorithm . } """, # noqa E501 initNs={"spkc": spkcgraph}, initBindings={ "idvalue": Literal(message_id), "algname": Literal("hash_algorithm", datatype=XSD.string), "idname": Literal("id", datatype=XSD.string), })) if not result or result[0].type.toPython() not in { "WebReference", "MessageContent" }: raise SrcException("No Message") # every object has it's own copy of the hash algorithm, used hash_algo = getattr(hashes, result[0].hash_algorithm.upper())() if not outfp: outfp = tempfile.TempFile() if hash_algo == self.hash_algo: pub_key_hashalg = "%s=%s" % (hash_algo.name, self.hash_key_public.hex()) else: digest = hashes.Hash(hash_algo, backend=default_backend()) digest.update(self.pem_key_public) pub_key_hashalg = "%s=%s" % (hash_algo.name, digest.finalize().hex()) key_hashes = list() if extra_key_hashes: extra_key_hashes = set(extra_key_hashes) extra_key_hashes.discard(pub_key_hashalg) for key in self.client_list: if key[0] in extra_key_hashes: if hash_algo == self.hash_algo: key_hashalg = "%s=%s" % (hash_algo.name, key[0]) else: digest = hashes.Hash(hash_algo, backend=default_backend()) digest.update(key[1]) key_hashalg = "%s=%s" % (hash_algo.name, digest.finalize().hex()) key_hashes.append(key_hashalg) if access_method == AccessMethod.view: key_hashes.append(pub_key_hashalg) retrieve_url, headers = self.merge_and_headers( replace_action( result[0].base, "bypass/" if (access_method == AccessMethod.bypass) else "message/")) data = {} if access_method != AccessMethod.bypass: data.update({"max_size": max_size or "", "keyhash": key_hashes}) response = self.session.post(retrieve_url, stream=True, headers=headers, data=data) try: response.raise_for_status() except Exception as exc: raise DestException("Message retrieval failed", response.text) from exc key_list = json.loads(response.headers["X-KEYLIST"]) key = key_list.get(pub_key_hashalg, None) if not key: raise WrongRecipient("message not for me") decrypted_key = self.priv_key.decrypt( base64.b64decode(key), padding.OAEP(mgf=padding.MGF1(algorithm=hash_algo), algorithm=hash_algo, label=None)) headblock = b"" fdecryptor = None eparser = emailparser.BytesFeedParser(policy=policy.default) headers = None for chunk in response.iter_content(chunk_size=256): blob = None if not fdecryptor: headblock = b"%b%b" % (headblock, chunk) if b"\0" in headblock: nonce, headblock = headblock.split(b"\0", 1) nonce = base64.b64decode(nonce) fdecryptor = Cipher(algorithms.AES(decrypted_key), modes.GCM(nonce), backend=default_backend()).decryptor() blob = fdecryptor.update(headblock[:-16]) headblock = headblock[-16:] else: continue else: blob = fdecryptor.update(b"%b%b" % (headblock, chunk[:-16])) headblock = chunk[-16:] if not headers: if b"\n\n" not in blob: eparser.feed(blob) continue headersrest, blob = blob.split(b"\n\n", 1) eparser.feed(headersrest) headers = eparser.close() # check what to do t = headers.get("SPKC-Type", MessageType.email) if t == MessageType.email: outfp.write( headers.as_bytes(unixfrom=True, policy=policy.SMTP)) outfp.write(blob) outfp.write(fdecryptor.finalize_with_tag(headblock)) return outfp, headers, decrypted_key
def __decrypt(input: Union[str, Iterable[bytes]], cipher: str = "AES-256-GCM", kdf: str = "PBKDF2", hashfunc: str = "SHA3_512", iterations: int = 100000, buf_size: int = 65536) -> Iterable[bytes]: with BufferedReader(input) as istream: cipher, key_len, mode, kdf, hashfunc = __get_meta( cipher, kdf, hashfunc) salt_len = int.from_bytes(istream.read(2), byteorder="little") salt = istream.read(salt_len) if len(salt) != salt_len: raise ValueError( f"Expected a salt of length {salt_len} but the file is not long enough. Most likely the file is corrupted or not encrypted using this cipher." ) key = __make_key(salt, kdf["algorithm"], hashfunc["algorithm"], key_len, iterations) if mode: iv = istream.read(cipher["block_size"]) else: iv = None decryptor = Cipher(cipher["algorithm"](key), mode["algorithm"](iv) if mode else None, backend=__backend).decryptor() unpadder = PKCS7(cipher["block_size"] * 8).unpadder() buf = None while len(buf2 := istream.read(buf_size)) != 0: if buf: if mode["padded"]: yield unpadder.update(decryptor.update(buf)) else: yield decryptor.update(buf) buf = buf2 if mode["auth_tag"]: try: if mode["padded"]: yield unpadder.update( decryptor.update(buf[:-mode["auth_tag"]])) yield unpadder.update( decryptor.finalize_with_tag(buf[-mode["auth_tag"]:])) yield unpadder.finalize() else: yield decryptor.update(buf[:-mode["auth_tag"]]) yield decryptor.finalize_with_tag(buf[-mode["auth_tag"]:]) except InvalidTag as e: raise ValueError( "\nThe authentication token could not be verified. Most likely the data is corrupt or was not encrypted using the given cipher." ) from e else: if mode["padded"]: yield unpadder.update(decryptor.update(buf)) yield unpadder.update(decryptor.finalize()) try: yield unpadder.finalize() except ValueError as e: raise ValueError( "Could not finalize padding. Most likely the file is corrupt or was not encrypted using the given cipher." ) from e else: yield decryptor.update(buf) yield decryptor.finalize()
def action_view(argv, priv_key, pem_public, own_url, session, g_message): if argv.message_id is not None: assert isinstance(argv.message_id, int) result = list(g_message.query( """ SELECT DISTINCT ?base ?hash_algorithm ?type WHERE { ?base a <https://spkcspider.net/static/schemes/spkcgraph#spkc:Content> ; spkc:type ?type ; spkc:properties ?propalg , ?propid . ?propid spkc:name ?idname ; spkc:value ?idvalue . ?propalg spkc:name ?algname ; spkc:value ?hash_algorithm . } """, # noqa E501 initNs={"spkc": spkcgraph}, initBindings={ "idvalue": Literal(argv.message_id), "algname": Literal( "hash_algorithm", datatype=XSD.string ), "idname": Literal( "id", datatype=XSD.string ), } )) if not result or result[0].type.toPython() not in { "WebReference", "MessageContent" }: parser.exit(0, "message not found\n") pub_key_hasher = getattr( hashes, result[0].hash_algorithm.upper() )() digest = hashes.Hash(pub_key_hasher, backend=default_backend()) digest.update(pem_public) pub_key_hashalg = "%s=%s" % ( pub_key_hasher.name, digest.finalize().hex() ) retrieve_url = merge_get_url( replace_action( result[0].base, "message/" ) ) data = { "max_size": argv.max } if argv.action == "view": data["keyhash"] = pub_key_hashalg response = session.post( retrieve_url, stream=True, headers={ "X-TOKEN": argv.token }, data=data ) if not response.ok: logger.info("Message retrieval failed: %s", response.text) parser.exit(0, "message could not be fetched\n") key_list = json.loads(response.headers["X-KEYLIST"]) key = key_list.get(pub_key_hashalg, None) if not key: parser.exit(0, "message not for me\n") decrypted_key = priv_key.decrypt( base64.b64decode(key), padding.OAEP( mgf=padding.MGF1(algorithm=argv.src_hash_algo), algorithm=argv.src_hash_algo, label=None ) ) headblock = b"" fdecryptor = None eparser = emailparser.BytesFeedParser(policy=policy.default) headers = None for chunk in response.iter_content(chunk_size=256): blob = None if not fdecryptor: headblock = b"%b%b" % (headblock, chunk) if b"\0" in headblock: nonce, headblock = headblock.split(b"\0", 1) nonce = base64.b64decode(nonce) fdecryptor = Cipher( algorithms.AES(decrypted_key), modes.GCM(nonce), backend=default_backend() ).decryptor() blob = fdecryptor.update(headblock[:-16]) headblock = headblock[-16:] else: continue else: blob = fdecryptor.update( b"%b%b" % (headblock, chunk[:-16]) ) headblock = chunk[-16:] if not headers: if b"\n\n" not in blob: eparser.feed(blob) continue headersrest, blob = blob.split(b"\n\n", 1) eparser.feed(headersrest) headers = eparser.close() # check what to do t = headers.get("SPKC-Type", MessageType.email) if t == MessageType.email: argv.file.write(headers.as_bytes( unixfrom=True, policy=policy.SMTP )) argv.file.write(blob) argv.file.write(fdecryptor.finalize_with_tag(headblock)) else: queried_webrefs = {} queried_messages = {} for i in g_message.query( """ SELECT DISTINCT ?base ?idvalue ?namevalue ?type WHERE { ?base a <https://spkcspider.net/static/schemes/spkcgraph#spkc:Content> ; spkc:type ?type ; spkc:properties ?propname , ?propid . ?propid spkc:name ?idname ; spkc:value ?idvalue . ?propname spkc:name ?namename ; spkc:value ?namevalue . } """, # noqa E501 initNs={"spkc": spkcgraph}, initBindings={ "idname": Literal( "id", datatype=XSD.string ), "namename": Literal( "name", datatype=XSD.string ), } ): if i.type.toPython() == "WebReference": queried = queried_webrefs elif i.type.toPython() == "MessageContent": queried = queried_messages else: continue queried.setdefault(str(i.base), {}) queried[str(i.base)]["id"] = i.idvalue queried[str(i.base)]["name"] = i.namevalue print("Received Messages:") for i in sorted(queried_webrefs.values(), key=lambda x: x["id"]): print(i["id"], i["name"]) print("Own Messages:") for i in sorted(queried_messages.values(), key=lambda x: x["id"]): print(i["id"], i["name"])