Irish Flan
6 minutos de lectura
Yum, time for dessert.
Challenge contributed by CryptoHack
Challenge files:
Se nos proporciona un script en Python que usa cuaterniones para ocultar una clave AES utilizada para cifrar la flag. La implementación de los cuaterniones se basa en clases de Python. Podemos suponer que la implementación es correcta (aunque hay un error en la potencia de un cuaternión, pero no es intencionado).
Análisis del código fuente
La parte relevante del script es:
class Dessert:
def __init__(self):
self.n = getPrime(1024) * getPrime(1024)
self.R = Z(self.n)
r = secrets.randbelow(self.n**8)
self.χ = Q(*[self.R(secrets.randbelow(self.n)) for _ in "abcd"])
self.α = Q(*[self.R(secrets.randbelow(self.n)) for _ in "abcd"])
self.β = self.χ**-1 * self.α**-1 * self.χ
self.γ = self.χ**r
@property
def pub(self):
return (self.n,
self.α,
self.β,
self.γ)
def encrypt(self, m):
k = Q(*[self.R(secrets.randbelow(self.n)) for _ in "abcd"])
K = hashlib.sha256(str(k).encode()).digest()
c = AES.new(K, AES.MODE_CBC, iv=b"\0" * 16).encrypt(pad(m, 16))
s = secrets.randbelow(self.n**8)
δ = self.γ**s
ε = δ**-1 * self.α * δ
κ = δ**-1 * self.β * δ
μ = κ * k * κ
return (c, μ, ε)
if __name__ == "__main__":
flan = Dessert()
print("Public key:", ",".join(map(str, flan.pub)))
with open("flag.txt") as f:
print("Encryption:", ",".join(
map(str, flan.encrypt(f.read().strip().encode()))))
La clase Dessert
define un módulo público
Para cifrar, el script toma un cuaternión aleatorio
Solución
De los valores anteriores, se nos proporcionan
- Nuestro objetivo es encontrar
, que solo aparece en . Entonces necesitamos hallar . - Y para hallar
, tenemos que tener , porque . - Y probablemente podremos encontrar
a partir de y , aunque no sabemos el exponente .
Podemos pensar que
Un enfoque es usar un cuaternión simbólico:
E intentar resolver para
Un enfoque alternativo es utilizar la forma matricial de los cuateriones (digamos que las letras griegas en minúsculas denotan cuaterniones y las letras griegas mayúsculas denotan formas matriciales), que es un procedimiento equivalente:
Y
Ahora, la ecuación nos da
Si intentamos resolver esto con SageMath, obtendremos la solución trivial
Por alguna razón, SageMath no permite calcular el rango de
Si usamos C.right_kernel_matrix()
en SageMath, veremos que la base del
para ciertos enteros
En este punto, si establecemos cualquier valor en
Sin embargo,
En este punto, podemos usar la otra relación:
Y luego,
Así,
Algo notable es que las coordenadas
Usando el hecho de que
Esta vez,
Pero aún más, no nos importa el valor de
Y el
Pero
Finalmente, solo necesitamos hallar
Flag
Después de implementar todas las operaciones requeridas, terminamos encontrando la flag:
$ python3 solve.py
ECSC{3qu1v4l3nt_k3y_rec0very_988b09742b}
El script completo se puede encontrar aquí: solve.py
.