BYUCTF 2024 | times-writeup
crypto/times [154 Solves] 🩸
Challenge Description
It’s just multiplication… right?
Challenge Author
Author: overllama
Challenge Files
we are provided with a python files and a text file
import hashlib
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from ellipticcurve import * # I'll use my own library for this
from base64 import b64encode
import os
from Crypto.Util.number import getPrime
def encrypt_flag(shared_secret: int, plaintext: str):
iv = os.urandom(AES.block_size)
#get AES key from shared secret
sha1 = hashlib.sha1()
sha1.update(str(shared_secret).encode('ascii'))
key = sha1.digest()[:16]
#encrypt flag
plaintext = pad(plaintext.encode('ascii'), AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(plaintext)
return { "ciphertext" : b64encode(ciphertext), "iv" : b64encode(iv) }
def main():
the_curve = EllipticCurve(13, 245, getPrime(128))
start_point = None
while start_point is None:
x = getPrime(64)
start_point = the_curve.point(x)
print("Curve: ", the_curve)
print("Point: ", start_point)
new_point = start_point * 1337
flag = "byuctf{REDACTED}"
print(encrypt_flag(new_point.x, flag))
if __name__ == "__main__":
main()
Curve: y^2 = x**3 + 13x + 245 % 335135809459196851603485825030548860907
Point: (14592775108451646097, 237729200841118959448447480561827799984)
{'ciphertext': b'SllGMo5gxalFG9g8j4KO0cIbXeub0CM2VAWzXo3nbIxMqy1Hl4f+dGwhM9sm793NikYA0EjxvFyRMcU2tKj54Q==', 'iv': b'MWkMvRmhFy2vAO9Be9Depw=='}
Solution
first we must analyse the python file and upon analysing it we realise that this is a straight-forward decryption challenge. we have all that’s required for decryption and we just need to reverse all the encryption logic.
Computing the Shared Secret
observe that all we need to know for the AES decryption is the shared secret. to compute this we need the x-
coordinate of the new_point
. since we know the start_point
and the scalar multiplier as well, this is an easy task. here’s a sage script that computes this
from sage.all import *
from Crypto.Util.number import *
# y^2 = x**3 + 13x + 245 % 335135809459196851603485825030548860907
p = 335135809459196851603485825030548860907
Fp = GF(p)
E = EllipticCurve(Fp, [13, 245])
P = E((14592775108451646097, 237729200841118959448447480561827799984))
Q = P * 1337
print(Q)
the result is
fooker@fooker:~/byuctf-2024/crypto/times$ python3 solve.sage
(130102914376597655583988556541378621904 : 127059956561887163664745694619573305167 : 1)
thus we have shared_secret = 130102914376597655583988556541378621904
AES Decryption
notice that the AES encryption mode used was CBC
and therefore we require the iv
that we already have anyway and now we know the key
too. so we could stuff all the required parameters into the decryption oracle to get the flag
Solve Script
import hashlib
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from base64 import *
import os
from Crypto.Util.number import getPrime
shared_secret = 130102914376597655583988556541378621904
ciphertext= b'SllGMo5gxalFG9g8j4KO0cIbXeub0CM2VAWzXo3nbIxMqy1Hl4f+dGwhM9sm793NikYA0EjxvFyRMcU2tKj54Q=='
iv = b'MWkMvRmhFy2vAO9Be9Depw=='
ciphertext = b64decode(ciphertext)
iv = b64decode(iv)
#get AES key from shared secret
sha1 = hashlib.sha1()
sha1.update(str(shared_secret).encode('ascii'))
key = sha1.digest()[:16]
# plaintext = pad(plaintext.encode('ascii'), AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)
print(plaintext)
and we get the flag
fooker@fooker:~/byuctf-2024/crypto/times$ python3 solve.py
b'byuctf{mult1pl1c4t10n_just_g0t_s0_much_m0r3_c0mpl1c4t3d}\x08\x08\x08\x08\x08\x08\x08\x08'