Last active
June 21, 2026 01:03
-
-
Save safiire/551db4cc0f4f05b7ff7584a6d7c518ec to your computer and use it in GitHub Desktop.
Implement a quick and probably bad RSA keypair, and factor it with yafu.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python | |
| from math import lcm | |
| from Crypto.Util.number import long_to_bytes, bytes_to_long, getPrime as get_prime | |
| from Crypto.PublicKey.RSA import construct, import_key | |
| from base64 import b64encode, b64decode | |
| import subprocess | |
| import re | |
| class RSA: | |
| def __init__(self, bit_depth): | |
| self.public_key, self.private_key = self.generate_keys(bit_depth) | |
| with open('private_key.pem', 'wb') as fp: | |
| fp.write(self.private_key.export_key()) | |
| with open('public_key.pem', 'wb') as fp: | |
| fp.write(self.public_key.export_key()) | |
| def generate_keys(self, bit_depth): | |
| e = 0x10001 # !! 1 < e < lambda_n && e is not a divisor of lambda_n | |
| p = get_prime(bit_depth // 2) | |
| q = get_prime(bit_depth // 2) | |
| lambda_n = self.lam(p, q) # Carmichael's totient function | |
| n = p * q # Product of primes | |
| d = self.mod_inv(e, lambda_n) # Find the multiplicative inverse of e | |
| crt = self.mod_inv(p, q) | |
| private_key = construct((n, e, d, p, q, crt)) | |
| public_key = construct((n, e)) | |
| return (public_key, private_key) | |
| def encrypt(self, message): | |
| m = bytes_to_long(message.encode()) | |
| ct = pow(m, self.public_key.e, self.public_key.n) | |
| return b64encode(long_to_bytes(ct)).decode() | |
| def decrypt(self, ct): | |
| pt = pow(ct, self.private_key.d, self.private_key.n) | |
| return long_to_bytes(pt).decode() | |
| def lam(self, p, q): | |
| return lcm(p - 1, q - 1) | |
| def mod_inv(self, e, mod): | |
| return pow(e, -1, mod) | |
| class Cracker: | |
| def __init__(self, ct, public_key_file): | |
| self.ct = bytes_to_long(b64decode(ct)) | |
| with open(public_key_file) as fp: | |
| self.public_key = import_key(fp.read()) | |
| def crack(self): | |
| n = self.public_key.n | |
| print(f'[*] Factoring public key...') | |
| factors = self.factor(n) | |
| if not factors: | |
| print(f"[-] YAFU couldn't factor {n}") | |
| return None | |
| p, q = factors | |
| print(f'[+] Done:') | |
| print(f"{n} =\n {p}\n* {q}") | |
| lambda_n = lcm(p - 1, q - 1) | |
| d = pow(self.public_key.e, -1, lambda_n) | |
| pt = pow(self.ct, d, self.public_key.n) | |
| return long_to_bytes(pt).decode() | |
| def factor(self, n): | |
| yafu_cmd = ['yafu', f'factor({n})'] | |
| output = subprocess.check_output(yafu_cmd).decode() | |
| matches = re.findall(r'^P\d\d = (\d+)', output, re.MULTILINE) | |
| if matches: | |
| return map(lambda n: int(n), matches) | |
| else: | |
| return None | |
| if __name__ == '__main__': | |
| bits = 256 | |
| print(f'[*] Generating a random {bits}-bit RSA Keypair') | |
| rsa = RSA(256) | |
| print(f'[*] Encrypting a message') | |
| ct = rsa.encrypt('This is a big secret') | |
| print(f'[*] Message: {ct}') | |
| print(f'[*] Load public key into cracker') | |
| cracker = Cracker(ct, 'public_key.pem') | |
| decrypted = cracker.crack() | |
| if decrypted: | |
| print(f'[+] Message was: {decrypted}') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment