server.pycrypto/Provably SecurejyuI proved this cryptographic combiner to be super secure (specifically IND-CCA2) on my graduate cryptography final exam, but just to be safe, I'm making you break it with both primitives being computationally secure!
nc mc.ax 31493
Downloads
#!/usr/local/bin/python
# Normally you have unlimited encryption and decryption query requests in the IND-CCA2 game.
# For performance reasons, my definition of unlimited is 8 lol
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes
from secrets import randbits
from os import urandom
from Crypto.Util.strxor import strxor
def encrypt(pk0, pk1, msg):
r = urandom(16)
r_prime = strxor(r, msg)
ct0 = pk0.encrypt(r, padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(), label=None))
ct1 = pk1.encrypt(r_prime, padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(), label=None))
return ct0.hex() + ct1.hex()
def decrypt(key0, key1, ct):
ct0 = ct[:256]
ct1 = ct[256:]
r0 = key0.decrypt(ct0, padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(), label=None))
r1 = key1.decrypt(ct1, padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(), label=None))
return strxor(r0, r1)
if __name__ == '__main__':
print("""Actions:
0) Solve
1) Query Encryption
2) Query Decryption
""")
for experiment in range(1, 129):
print("Experiment {}/128".format(experiment))
key0 = rsa.generate_private_key(public_exponent=65537, key_size=2048)
key1 = rsa.generate_private_key(public_exponent=65537, key_size=2048)
pk0 = key0.public_key()
pk1 = key1.public_key()
print("pk0 =", pk0.public_numbers().n)
print("pk1 =", pk1.public_numbers().n)
m_bit = randbits(1)
seen_ct = set()
en_count = 0
de_count = 0
while True:
choice = int(input("Action: "))
if choice == 0:
guess = int(input("m_bit guess: "))
if (guess == m_bit):
print("Correct!")
break
else:
print("Wrong!")
exit(0)
elif choice == 1:
en_count += 1
if (en_count > 8):
print("You've run out of encryptions!")
exit(0)
m0 = bytes.fromhex(input("m0 (16 byte hexstring): ").strip())
m1 = bytes.fromhex(input("m1 (16 byte hexstring): ").strip())
if len(m0) != 16 or len(m1) != 16:
print("Must be 16 bytes!")
exit(0)
msg = m0 if m_bit == 0 else m1
ct = encrypt(pk0, pk1, msg)
seen_ct.add(ct)
print(ct)
elif choice == 2:
de_count += 1
if (de_count > 8):
print("You've run out of decryptions!")
exit(0)
in_ct = bytes.fromhex(input("ct (512 byte hexstring): ").strip())
if len(in_ct) != 512:
print("Must be 512 bytes!")
exit(0)
if in_ct in seen_ct:
print("Cannot query decryption on seen ciphertext!")
exit(0)
print(decrypt(key0, key1, in_ct).hex())
with open('flag.txt', 'r') as f:
print("Flag: " + f.read().strip())
Actionsで1) Query Encryptionを選択し2つの値を入力すると暗号化されたデータが返される。次に2) Query Decryptionを選択し暗号化されたデータを入力として与えると1で入力した2つの値のどちらかに復号される。m_bitが0の時は最初の入力、1の時は2つ目の入力となるので、m_bitが分かる。
from pwn import *
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--local', action='store_true')
args = parser.parse_args()
context.log_level = 'debug'
p = remote('mc.ax', 31493)
for i in range(128):
p.recvuntil(b"/128\n")
ret = p.recvline() #pk0
ret = p.recvline() #pk1
p.recvuntil(b"Action: ")
p.sendline(b"1")
p.recvuntil(b"m0 (16 byte hexstring): ")
p.sendline(b"11111111111111111111111111111111")
p.recvuntil(b"m1 (16 byte hexstring): ")
p.sendline(b"22222222222222222222222222222222")
ct = p.recvline()
ct = ct.strip()
#print(ct)
p.recvuntil(b"Action: ")
p.sendline(b"2")
p.recvuntil(b"ct (512 byte hexstring): ")
p.sendline(ct)
val = p.recvline()
val = val.strip()
#print(val)
p.recvuntil(b"Action: ")
p.sendline(b"0")
p.recvuntil(b"m_bit guess: ")
if val == b"11111111111111111111111111111111":
p.sendline(b"0")
else:
p.sendline(b"1")
ret = p.recvline()
#print(ret)
if ret == b"Wrong":
break
ret = p.recvall()
#print(ret)
p.close()
フラグは、b'Experiment 128/128\n'b'pk0 = 26483178418609116136951478639155735955228244719231038357154286456849164060537738601129461329027032592022630276653274631380513565573453208959131970498627891166304660979526866358093970418467452255935885486672919046263969293559022305618635679493450910418358860413789966895286255402093586148398942408961686081886747201577911268454355107333476809801749505548136117482308470616651066354286490397379793697989041763209509786130857855625486035421706980743070961196362581601994281592155108200050766753687511387016112248369819804225762436294955214316499544033467870439578449504064153537328438230865934214907862597149182412802701\n'b'pk1 = 22667744595601474719286417722625980199953337073921238439970513544682185573760647158871048307685415680411492067802867281482343310100191877885779793610507355501999611487469590935934426591359710644022154322375553905976005195668301956253448563908292821833250608789296031973513718421770681387826699074934899042073377864571289646893078940363500912533248781684860073627225276507037962023181884504883692372741763762006049491280194835446782532329513422943632894660291064132748577211239618413055708718354177215501903052248014031902261890798295746583994399760723038360888997246445020179588051003201717048265195427106050941676633\n'b'Action: '[DEBUG] Sent 0x2 bytes:b'1\n'[DEBUG] Received 0x18 bytes:b'm0 (16 byte hexstring): '[DEBUG] Sent 0x21 bytes:b'11111111111111111111111111111111\n'[DEBUG] Received 0x18 bytes:b'm1 (16 byte hexstring): '[DEBUG] Sent 0x21 bytes:b'22222222222222222222222222222222\n'[DEBUG] Received 0x409 bytes:b'5a3f744e9f9c02d1b11bf4bf85d9dbf5ec1f8ca76b2468cd3479f55f337a65ad38a74ab8aa698903c48672c4d2681c1da170f4cf2551a35515258f7e1536fa92d7184d90d20096605a939adc17e58c6c0f010d1ee7978f034baa3c54bb6650bc496232cc298349ccefff2b9aca787603bca06b04e8d6c7317cc928097b3cc5a0a376794f67d4926df80e9d8729d14284d64ae34977fd87be5ec37072fe4f2842761fe25275ac903fc44677bd79a49d76d04b96c9152703b569fd4e6e21041eb69c5c8b6b970391c693a46748b63a6179fc53fb24a30ee651a98afdff748f4cbecb86f81d1a53acc93cadb338f06fccbc4515707a7ab721e644205986eb29d8be6f50162452fc1d8891df1b576d5da495c4631f7d1a353f2fcf79460fe2207d96ccae1385d33890705a19bafdf910ef2b723e21a1a225df761416626d1cf3d4b405b456514b050dd69dcb3987cd9cca82de7cce0dc57d32967a2d43ace5f0bab765c03664d61dd32a876de664f2e5b4cf4d8c744cb5b30a538b03aba6d111596af6fcb60252843c07f9b120b57b06ab46cca0b306b6215bb1a90eb062bdb7c1e7192092fcb24089b0d5a114c77b8904e4fffbf5ef2b8dbf95112c2362c14df478cb2f89dfd03d48ffe89cc864f5b5ac056e4886c87dbdc2ee126e1ed69848401fee18cfde7cf326aad014cc53d047979d92d851678d002105ab341f8c0b83e060\n'b'Action: '[DEBUG] Sent 0x2 bytes:b'2\n'[DEBUG] Received 0x19 bytes:b'ct (512 byte hexstring): '[DEBUG] Sent 0x401 bytes:b'5a3f744e9f9c02d1b11bf4bf85d9dbf5ec1f8ca76b2468cd3479f55f337a65ad38a74ab8aa698903c48672c4d2681c1da170f4cf2551a35515258f7e1536fa92d7184d90d20096605a939adc17e58c6c0f010d1ee7978f034baa3c54bb6650bc496232cc298349ccefff2b9aca787603bca06b04e8d6c7317cc928097b3cc5a0a376794f67d4926df80e9d8729d14284d64ae34977fd87be5ec37072fe4f2842761fe25275ac903fc44677bd79a49d76d04b96c9152703b569fd4e6e21041eb69c5c8b6b970391c693a46748b63a6179fc53fb24a30ee651a98afdff748f4cbecb86f81d1a53acc93cadb338f06fccbc4515707a7ab721e644205986eb29d8be6f50162452fc1d8891df1b576d5da495c4631f7d1a353f2fcf79460fe2207d96ccae1385d33890705a19bafdf910ef2b723e21a1a225df761416626d1cf3d4b405b456514b050dd69dcb3987cd9cca82de7cce0dc57d32967a2d43ace5f0bab765c03664d61dd32a876de664f2e5b4cf4d8c744cb5b30a538b03aba6d111596af6fcb60252843c07f9b120b57b06ab46cca0b306b6215bb1a90eb062bdb7c1e7192092fcb24089b0d5a114c77b8904e4fffbf5ef2b8dbf95112c2362c14df478cb2f89dfd03d48ffe89cc864f5b5ac056e4886c87dbdc2ee126e1ed69848401fee18cfde7cf326aad014cc53d047979d92d851678d002105ab341f8c0b83e060\n'[DEBUG] Received 0x29 bytes:b'11111111111111111111111111111111\n'b'Action: '[DEBUG] Sent 0x2 bytes:b'0\n'[DEBUG] Received 0xd bytes:b'm_bit guess: '[DEBUG] Sent 0x2 bytes:b'0\n'[DEBUG] Received 0x43 bytes:b'Correct!\n'b'Flag: dice{yeah_I_lost_like_10_points_on_that_proof_lmao}\n'
dice{yeah_I_lost_like_10_points_on_that_proof_lmao}