The following content is password protected. Javascript needs to be enabled to decrypt content Provided files flag.txt.aes: AES encrypted file. key: RSA encrypted file containing AES key. pubkey.pem: public key used for encrypting key file. Getting private key Usually, with a properly created RSA key, it should be impossible to calculate the private key from the public key. However, since this challenge is made to be solved, it is likely that the public key from the pubkey.pem file is weak enough to make it possible to get the private key from it. First, let’s get e and n from the public key file. e = 65537 n = 1128137999850045612492145429133282716267233566834715456536184965477269592934207986950131365518741418540788596074115883774105736493742449131477464976858161587355643311888741515506653603321337485523828144179637379528510277430032789458804637543905426347328041281785616616421292879871785633181756858096548411753919440011378411476275900648915887370219369154688926914542233244450724820670256654513052812215949495598592852131398736567134556141744727764716053145639513031 Now that we have this two numbers, we’re factoring n. In normal conditions, factoring such a large number (when it’s a product of two big prime numbers) should be computationally unfeasible. Nevertheless, if this challenge can be solved, this is one of the more logical options to be considered. There are several options that can be used in order to get the factors from this number. We’re going to use a tool called FactorDb. After factoring it, we get that n is not a result of the product of two big prime numbers (p and q), but the cube of single prime number. $$n = p^3$$ Therefore, now we can calculate Euler’s totient. $$\varphi(n) = p^2 * (p-1)$$ Once we do this, we can calculate the private key that we’re going to use to decrypt the key file. In order to get d, we need to calculate the modular multiplicative inverse from e and $\varphi(n)$. We can use the python function inverse from the Crypto.Util.number package. from Crypto.Util.number import inverse inverse(e, phi) Resolution Now that we have d we can decrypt the key file ( $M = C^d\bmod n$ ). After we decrypt it, we have the key that needs to be used to decrypt flag.txt.aes file. Script There’s a python script below that can be used to solve this challenge. from Crypto.Util.number import bytes_to_long, long_to_bytes, inverse from Crypto.PublicKey import RSA from Crypto.Cipher import AES from gmpy2 import iroot def get_private(pub): n = pub.n e = pub.e # n = p**3 p = int(iroot(n,3)[0]) phi = (p**2) * (p - 1) return inverse(e, phi) def decrypt_rsa(c, d, n): result = 1 while d 0: if (d & 1) 0: result = (result*c) % n d = 1 c = c**2 % n return result def decrypt_aes(k, c): aes = AES.new(k, AES.MODE_ECB) return aes.decrypt(c) if __name__ == '__main__': # Open challenge files with open('pubkey.pem') as f: pub = RSA.import_key(f.read()) with open('key') as f: k = bytes.fromhex(f.read()) with open('flag.txt.aes', 'rb') as f: c = f.read() c = c[:-1] # Solve challenge d = get_private(pub) k = bytes_to_long(k) k = long_to_bytes(decrypt_rsa(k, d, pub.n)) flag = decrypt_aes(k,c).decode() # Print results print(f'RSA Private Key: {d}\n') print(f'Unciphered "key" file: {k}\n') print(f'Unciphered "flag.txt.aes" file: {flag}') Flag HTB{pl4y1ng_w1th_pr1m3s_1s_fun!} div#hugo-encrypt-sha1sum {display: none;} const storageKey = location.pathname + "password"; const userStorage = localStorage ; function str2buf(str) { return new TextEncoder("utf-8").encode(str); } function buf2str(buffer) { return new TextDecoder("utf-8").decode(buffer); } function hex2buf(hexStr) { return new Uint8Array(hexStr.match(/.{2}/g).map(h = parseInt(h, 16))); } function deriveKey(passphrase, salt) { salt = salt || crypto.getRandomValues(new Uint8Array(8)); return crypto.subtle .importKey("raw", str2buf(passphrase), "PBKDF2", false, ["deriveKey"]) .then(key = crypto.subtle.deriveKey( { name: "PBKDF2", salt, iterations: 1000, hash: "SHA-256" }, key, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"], ), ) .then(key = [key, salt]); } function decrypt(passphrase, saltIvCipherHex) { const [salt, iv, data] = saltIvCipherHex.split("-").map(hex2buf); return deriveKey(passphrase, salt) .then(([key]) = crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, data)) .then(v = buf2str(new Uint8Array(v))); } async function digestMessage(message) { const msgUint8 = new TextEncoder().encode(message); const hashBuffer = await crypto.subtle.digest('SHA-1', msgUint8); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map(b = b.toString(16).padStart(2, '0')).join(''); return hashHex; } const hugoDecrypt = function(password, type) { for (const cipher of ciphers) { decrypt(password, cipher.innerText).then(function(decrypted_text) { digestMessage(decrypted_text.replace(/\r?\n?[^\r\n]*$/, "")).then(function(sha1_sum) { if ( decrypted_text.includes(sha1_sum) ) { document.getElementById("hugo-encrypt-encryption-notice").remove(); cipher.outerHTML = decrypted_text; userStorage.setItem(storageKey, password); document.getElementById("hugo-encrypt-sha1sum").innerHTML = "Success: " + sha1_sum; console.log("Decryption successful. Storing password in Storage."); MathJax.Hub.Typeset(); code_copy_bttn(); } }); }).catch(function(error) { if (type === "input") { document.getElementById("hugo-encrypt-input-response").innerHTML = "Password is incorrect"; console.log('Password is incorrect', error); } else if (type === "storage") { userStorage.removeItem(location.pathname + "password"); console.log("Password changed. Clearing userStorage.", error); } }); } }; window.onload = () = { ciphers = Array.from(document.querySelectorAll("cipher-text")); if (userStorage.getItem(storageKey)) { console.log("Found storageKey in userStorage. Attemtping decryption"); hugoDecrypt(userStorage.getItem(storageKey), "storage"); } };