1. Finding Flags
Each challenge is designed to help introduce you to a new piece of cryptography. Solving a challenge will require you to find a "flag".
These flags will usually be in the format crypto{y0ur_f1rst_fl4g}. The flag format helps you verify that you found the correct solution.
Try submitting this into the form below to solve your first challenge.
Writeup:
Flag: crypto{y0ur_f1rst_fl4g}
> Qadratic Residues
Quadratic residual
An integer is called quadratic residual if..
a^2=x % p ——> (a^2 - x)=k*p ——> [1]
p-integer modulo
where Zp={0..p-1} and Z*p={set of integers where GCD(p, Zp)==1}
Now solve Eq-1
Here, Z*p are "a" values
p=29
ints = [14, 6, 11]
from Crypto.Util.number import *
a_val=[i for i in range(0,p-1) if GCD(p,i)==1]
for i in a_val:
for j in ints:
for k in range(0,100):
if (pow(i,2)-j)==k*p:
print(i)
#We later go for 8 as it is the smallest among all.
> Legendre Symbol
Legendre Symbol obeys these following rules,
Where (a / p) == (a^(p-1)/2) % p, this will give you all the Legendre's Symbols
The prime supplied obeys p = 3 mod 4, which allows us easily compute the square root.
So from this, we can take (p+1/4).
(a/p) = a**(p+1/4) mod p —→ for p = 3(mod 4)
According to Tonelli–Shanks algorithm, p = 3%4 this makes the computation much easier. Tonelli factorization doesn’t work on composite( Non-Prime ) number.
p = 101524035174539890485408575671085261788758965189060164484385690801466167356667036677932998889725476582421738788500738738503134356158197247473850273565349249573867251280253564698939768700489401960767007716413932851838937641880157263936985954881657889497583485535527613578457628399173971810541670838543309159139
ints = [25081841204695904475894082974192007718642931811040324543182130088804239047149283334700530600468528298920930150221871666297194395061462592781551275161695411167049544771049769000895119729307495913024360169904315078028798025169985966732789207320203861858234048872508633514498384390497048416012928086480326832803, 45471765180330439060504647480621449634904192839383897212809808339619841633826534856109999027962620381874878086991125854247108359699799913776917227058286090426484548349388138935504299609200377899052716663351188664096302672712078508601311725863678223874157861163196340391008634419348573975841578359355931590555, 17364140182001694956465593533200623738590196990236340894554145562517924989208719245429557645254953527658049246737589538280332010533027062477684237933221198639948938784244510469138826808187365678322547992099715229218615475923754896960363138890331502811292427146595752813297603265829581292183917027983351121325, 14388109104985808487337749876058284426747816961971581447380608277949200244660381570568531129775053684256071819837294436069133592772543582735985855506250660938574234958754211349215293281645205354069970790155237033436065434572020652955666855773232074749487007626050323967496732359278657193580493324467258802863, 4379499308310772821004090447650785095356643590411706358119239166662089428685562719233435615196994728767593223519226235062647670077854687031681041462632566890129595506430188602238753450337691441293042716909901692570971955078924699306873191983953501093343423248482960643055943413031768521782634679536276233318, 85256449776780591202928235662805033201684571648990042997557084658000067050672130152734911919581661523957075992761662315262685030115255938352540032297113615687815976039390537716707854569980516690246592112936796917504034711418465442893323439490171095447109457355598873230115172636184525449905022174536414781771, 50576597458517451578431293746926099486388286246142012476814190030935689430726042810458344828563913001012415702876199708216875020997112089693759638454900092580746638631062117961876611545851157613835724635005253792316142379239047654392970415343694657580353333217547079551304961116837545648785312490665576832987, 96868738830341112368094632337476840272563704408573054404213766500407517251810212494515862176356916912627172280446141202661640191237336568731069327906100896178776245311689857997012187599140875912026589672629935267844696976980890380730867520071059572350667913710344648377601017758188404474812654737363275994871, 4881261656846638800623549662943393234361061827128610120046315649707078244180313661063004390750821317096754282796876479695558644108492317407662131441224257537276274962372021273583478509416358764706098471849536036184924640593888902859441388472856822541452041181244337124767666161645827145408781917658423571721, 18237936726367556664171427575475596460727369368246286138804284742124256700367133250078608537129877968287885457417957868580553371999414227484737603688992620953200143688061024092623556471053006464123205133894607923801371986027458274343737860395496260538663183193877539815179246700525865152165600985105257601565]
from Crypto.Util.number import *
for a in ints:
if pow(a,(p-1)//2,p)==1:
non_res=a
print(non_res)
#Now Finding roots of the non residuel value
new_val=pow(non_res,(p+1)//4,p)
print(new_val)
> Chinese Remainder Theorem
#import gmpy2
'''
Given the following set of linear congruences:
x ≡ 2 mod 5
x ≡ 3 mod 11
x ≡ 5 mod 17
Find the integer a such that x ≡ a mod 935
'''
from Crypto.Util.number import *
def Chinese(n, N, a):
result = 0
for i in range(len(n)):
ai = a[i]
ni = n[i]
bi = N // ni
result += ai * bi * inverse(bi, ni)
return result % N
N=935
n=[5,11,17]
a=[2,3,5]
result=Chinese(n,N,a)
print(result)
> Successive Powers
from Crypto.Util.number import *
import gmpy2
t=[588, 665, 216, 113, 642, 4, 836, 114, 851, 492, 819, 237]
pval=max(t)+1
for p in range(pval,1000000):
try:
x=[ (t[i] * inverse(t[i-1]) ,p)%p for i in range(1000) ]
if len(set(x))==1:
print(p,x)
except:
pass
> Broken RSA
import Crypto.Util.number as cun
from pprint import pprint
def roots_of_unity(e, phi, n, rounds=500):
# Divide common factors of `phi` and `e` until they're coprime.
phi_coprime = phi
while cun.GCD(phi_coprime, e) != 1:
phi_coprime //= cun.GCD(phi_coprime, e)
# Don't know how many roots of unity there are, so just try and collect a bunch
roots = set(pow(i, phi_coprime, n) for i in range(1, rounds))
assert all(pow(root, e, n) == 1 for root in roots)
return roots, phi_coprime
e = 16
n=27772857409875257529415990911214211975844307184430241451899407838750503024323367895540981606586709985980003435082116995888017731426634845808624796292507989171497629109450825818587383112280639037484593490692935998202437639626747133650990603333094513531505209954273004473567193235535061942991750932725808679249964667090723480397916715320876867803719301313440005075056481203859010490836599717523664197112053206745235908610484907715210436413015546671034478367679465233737115549451849810421017181842615880836253875862101545582922437858358265964489786463923280312860843031914516061327752183283528015684588796400861331354873
c = 11303174761894431146735697569489134747234975144162172162401674567273034831391936916397234068346115459134602443963604063679379285919302225719050193590179240191429612072131629779948379821039610415099784351073443218911356328815458050694493726951231241096695626477586428880220528001269746547018741237131741255022371957489462380305100634600499204435763201371188769446054925748151987175656677342779043435047048130599123081581036362712208692748034620245590448762406543804069935873123161582756799517226666835316588896306926659321054276507714414876684738121421124177324568084533020088172040422767194971217814466953837590498718
# Problem: e and phi are not coprime - d does not exist
phi = n-1 # there were no prime factors of n
# Find e'th roots of unity modulo n
roots, phi_coprime = roots_of_unity(e, phi, n)
# Use our `phi_coprime` to get one possible plaintext
d = pow(e, -1, phi_coprime)
m = pow(c, d, n)
assert pow(m, e, n) == c
# Use the roots of unity to get all other possible plaintexts
ms = [(m * root) % n for root in roots]
ms = [cun.long_to_bytes(m) for m in ms]
pprint(ms)
> ECB CBC WTF
In the given challenge the given mode encryption was in CBC but decryption with ECB.
Learn More →
ciphertext = iv.hex() + encrypted.hex()
The generated ciphertext in my case was "cb30b6a41ea0302796321785baa60db2af7989205ddcbac9a207e202970885d8a275d6e53e3effcf527bf9bbf1cf87a1"
We see the length of the ciphertext to be 96 in hexadecimal, 48 in bytes where Initialization vector (iv) length is of 16 and the remaining is the actual ciphertext.
iv=ciphertext[:16]
ct=ciphetext[16:]
Now decrypt the first 16 bytes ct block with ECB mode and then xor with iv, this is the first part of the plaintext and the second 16 bytes block will be decrypted with ECB mode and that text is now xored with the first ct block resulting in the 2nd plaintext.
plaintext=p1+p2
> Flipping Cookie
Learn More →
{"cookie":"29ba24b9e53b8f4852ce8daa7fbad6de8cf8813d64f394306815baa49b7c3fc323c646c6455fbf3b920455962deb81d9"}
from Crypto.Cipher import AES
import os
from Crypto.Util.Padding import pad, unpad
from datetime import datetime, timedelta
KEY = ?
FLAG = ?
@chal.route('/flipping_cookie/check_admin/<cookie>/<iv>/')
def check_admin(cookie, iv):
cookie = bytes.fromhex(cookie)
iv = bytes.fromhex(iv)
try:
cipher = AES.new(KEY, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(cookie)
unpadded = unpad(decrypted, 16)
except ValueError as e:
return {"error": str(e)}
if b"admin=True" in unpadded.split(b";"):
return {"flag": FLAG}
else:
return {"error": "Only admin can read the flag"}
@chal.route('/flipping_cookie/get_cookie/')
def get_cookie():
expires_at = (datetime.today() + timedelta(days=1)).strftime("%s")
cookie = f"admin=False;expiry={expires_at}".encode()
iv = os.urandom(16)
padded = pad(cookie, 16)
cipher = AES.new(KEY, AES.MODE_CBC, iv)
encrypted = cipher.encrypt(padded)
ciphertext = iv.hex() + encrypted.hex()
return {"cookie": ciphertext}
> Lazy CBC
Learn More →
ct="339451173da40bb3f2599e0adcb474759c89a29d7eb5ece460037fd4158c3cd8af8f76d0164ebe3b676b28e1eff93508”
from Crypto.Cipher import AES
KEY = ?
FLAG = ?
@chal.route('/lazy_cbc/encrypt/<plaintext>/')
def encrypt(plaintext):
plaintext = bytes.fromhex(plaintext)
if len(plaintext) % 16 != 0:
return {"error": "Data length must be multiple of 16"}
cipher = AES.new(KEY, AES.MODE_CBC, KEY)
encrypted = cipher.encrypt(plaintext)
return {"ciphertext": encrypted.hex()}
@chal.route('/lazy_cbc/get_flag/<key>/')
def get_flag(key):
key = bytes.fromhex(key)
if key == KEY:
return {"plaintext": FLAG.encode().hex()}
else:
return {"error": "invalid key"}
@chal.route('/lazy_cbc/receive/<ciphertext>/')
def receive(ciphertext):
ciphertext = bytes.fromhex(ciphertext)
if len(ciphertext) % 16 != 0:
return {"error": "Data length must be multiple of 16"}
cipher = AES.new(KEY, AES.MODE_CBC, KEY)
decrypted = cipher.decrypt(ciphertext)
try:
decrypted.decode() # ensure plaintext is valid ascii
except UnicodeDecodeError:
return {"error": "Invalid plaintext: " + decrypted.hex()}
return {"success": "Your message has been received"}
Given the conditions above we can exploit this in the following way:
Make a plaintext with a length of *at least* 3 blocks
Encrypt the plaintext and get the resulting ciphertext
Modify the second block of the ciphertext to *contain only zeros*
Modify the third block of the ciphertext to be *the same as the first block*
Decrypt the ciphertext and get the *invalid plaintext* result
XOR the first and third blocks of the *invalid plaintext*
That’s our key!
As IV = Key let’s say, Pt1 = Key ^ Decrypt(Ct1)
Pt2 = Ct1 ^ Decrypt(Ct2)
Pt3 = Ct2 ^ Decrypt(Ct3)
If we make Ct2 = 0 [Block] and C3 = C1 then,
Pt1 = Key ^ Decrypt(Ct1)
Pt2 = Ct1 ^ Decrypt(0)
Pt3 = 0 ^ Decrypt(Ct1)
Therefore, Key = XOR(Pt1,Pt3)
ct="339451173da40bb3f2599e0adcb474759c89a29d7eb5ece460037fd4158c3cd8af8f76d0164ebe3b676b28e1eff93508"
ct=ct.encode()
b1=ct[:32]
b2='0'*32.encode()
new_ct=b1+b2+b1
print("New fake Cipher: ", new_ct)
#after decryption of new_ct we get a plaintext
pt="61616161616161616161616161616161ff2f3668967735aa1d493ff1f1c4ff39c5153f87bbf70ac3705e5c4ffd5e7a14"
pt1=pt[:32]
pt3=pt[64:]
key=xor(bytes.fromhex(pt1),bytes.fromhex(p3)).hex()
print("Key:", key)
#use this key to get the FLAG
> Triple DES
from Crypto.Cipher import DES3
from Crypto.Util.Padding import pad
IV = os.urandom(8)
FLAG = ?
def xor(a, b):
# xor 2 bytestrings, repeating the 2nd one if necessary
return bytes(x ^ y for x,y in zip(a, b * (1 + len(a) // len(b))))
@chal.route('/triple_des/encrypt/<key>/<plaintext>/')
def encrypt(key, plaintext):
try:
key = bytes.fromhex(key)
plaintext = bytes.fromhex(plaintext)
plaintext = xor(plaintext, IV)
cipher = DES3.new(key, DES3.MODE_ECB)
ciphertext = cipher.encrypt(plaintext)
ciphertext = xor(ciphertext, IV)
return {"ciphertext": ciphertext.hex()}
except ValueError as e:
return {"error": str(e)}
@chal.route('/triple_des/encrypt_flag/<key>/')
def encrypt_flag(key):
return encrypt(key, pad(FLAG.encode(), 8).hex())
There is a serious Vulnerability with DES, it is vulnerable to Weak Keys .
This vulnerability was discovered when the key was brute forced within a day or two in 1990s.
Let me demonstrate by solving this challenge.
There are various weak keys that can be used for attack, not necessary to use my key alone.
The key that I used to encrypt was “0101010101010101FEFEFEFEFEFEFEFE
".
Now we obtained the cipher text {"ciphertext":"63727970746f7b6e30745f346c6c5f6b3379735f3472335f673030645f6b3379737d060606060606"}
Use the same ciphertext to and key to encrypt again, this gives us the FLAG.
> Symmetry
from Crypto.Cipher import AES
KEY = ?
FLAG = ?
@chal.route('/symmetry/encrypt/<plaintext>/<iv>/')
def encrypt(plaintext, iv):
plaintext = bytes.fromhex(plaintext)
iv = bytes.fromhex(iv)
if len(iv) != 16:
return {"error": "IV length must be 16"}
cipher = AES.new(KEY, AES.MODE_OFB, iv)
encrypted = cipher.encrypt(plaintext)
ciphertext = encrypted.hex()
return {"ciphertext": ciphertext}
@chal.route('/symmetry/encrypt_flag/')
def encrypt_flag():
iv = os.urandom(16)
cipher = AES.new(KEY, AES.MODE_OFB, iv)
encrypted = cipher.encrypt(FLAG.encode())
ciphertext = iv.hex() + encrypted.hex()
return {"ciphertext": ciphertext}
AES OFB mode is symmetrical cipher, so just by using the same IV and Ciphertext we can get the Flag.
> Bean Counter
from Crypto.Cipher import AES
KEY = ?
class StepUpCounter(object):
def __init__(self, value=os.urandom(16), step_up=False):
self.value = value.hex()
self.step = 1
self.stup = step_up
def increment(self):
if self.stup:
self.newIV = hex(int(self.value, 16) + self.step)
else:
self.newIV = hex(int(self.value, 16) - self.stup)
self.value = self.newIV[2:len(self.newIV)]
return bytes.fromhex(self.value.zfill(32))
def __repr__(self):
self.increment()
return self.value
@chal.route('/bean_counter/encrypt/')
def encrypt():
cipher = AES.new(KEY, AES.MODE_ECB)
ctr = StepUpCounter()
out = []
with open("challenge_files/bean_flag.png", 'rb') as f:
block = f.read(16)
while block:
keystream = cipher.encrypt(ctr.increment())
xored = [a^b for a, b in zip(block, keystream)]
out.append(bytes(xored).hex())
block = f.read(16)
return {"encrypted": ''.join(out)}
def __init__(self, value=os.urandom(16), step_up=False):
. Here steup_up = False means the value is not getting updated.
Let’s understand the working of the code, the first block header of the png file is XORed with the key and so on.
ct='649b00e86c44d40680028e6a09bc6d9cedcb4f83614ece7b88048e67404d6ab318cb4ebe02349a54f450ef1060845ba18ba222ca413ab77ce522eb1f299229ce95118b360adcea3b0e8671a0690221b26cebc1ec73ee17d0e08d3178e24673a4a4e89de702f853910f880483438491f5b544b140dea03d337c693bc2e77da7f09684b2c4d2837cf4b0d059d8b54acf1a331cb9f058d181f567e9018da7bfac85783cb45a82a651e74ef74c9aa587d4b2502c8bda989b8edfbfbd5658bf9654c8c7287d6e86b43948b57dc3f77ef71625de9b6330f89519c37b69d5ce8f5596102f3292d05ef1b1cf40f107f016415d27b4d0e102459bf0f5bc48e42d9cd83fb4a252bf92b8d14f7273f17d1a2b95640b8665c778706562534fc73dd9efb8e821ea5405c2dda834d5b2dba428622c50b02a3e81509c9704936fa7f135bea763b191310305dab2f0df4ff905881b1e46fc39b4f25080bbe2b3dc7df0fa92c3467173723191f4d1618311ecc11cbe3a73f2027e3f001ea3a0b94e947500132b72b2d2ba912109f311e6bc9629c35135a70909fa662662c0c29ced1ca9a81cbcca03c090105607311143be2e3f726f3e52e74a1f32b14f405c3d4bab1fbb567b55453b92c3fbf6344e4f656877d6d60867f5322200b12d22b7302025bd3fa6dfd6261c37db348fc34cc6b9605782cde1c2e4bca2e28d53d93d9fb2b51ff63ccb685bda0b9120beb045b0d630a608d8f33292840c460b1e053009dcf7c313a5b2c833464bfd75064e8cc88a864b830af27b01b8b981e62a37fa6b823bc6b7221d3d9f346f6b24752d5fa955d8c7691534f5b2aa3835c4f0bcbb15a2269f35bba7bc12217106f90a4cb0b88d323ac30ae7b8e0c788e8033f359a546fd80d36d7a244e4379e3b47b5bb42365a925fe0cec5cf965e07444cabead0eb187120a2e47fb8d93295921fb76075e2366779ca3b189019c404e7087c7733e499651002855e78093b862377d5ab178d12359988eeca5534578ba379bae01272758cb5f8fb8a4d237e1d91929fcd62e9cfd444fce94c78b18946e50021f28de8201107fbd145fbfce41c86efcf01e79d3336fc0c65c63ef7a6781eba33166a48f22ec9a18894da92092d51169a6bbdfe54fc51ae9bb70b0492e83de0c5a0e1686ef5f79ce358f0b46865f0b6eb7c42ac26487b1693f6c3b477b267ccfef4f5683138cfd3339a688f21589a0ff074b37cf3f586089e89f770814638d43c646909df57d56049cfe578d06a80bc3c5532dc58f6ace1b7dde7200843dc011fbd56b19abbe7152a6d9e5b5f0c973f85a7a523ef66e31252520e5953ad20f97b879c297d67decf908878a051c0e7fed468ea658c341a0ddfa1467988b8a23e956cab1a111cc992185fb7972c48d9f60f15c6bcb1629cd095e8f378b12d578ebbbb40ed1d8f9e80a58e6c83502434dc13847bd6c4bc1115ee82b0e0087fa52109d522573dae6f9c3ab9520ecaa7339ead80fcb550b58335197772ce7c44a45c90a5185eb697c23facc6d2f080b1707cac33050ea97b5811a6e63008e30c00d2552c84fd80915090128fa948d81f2dec4b436229f658bf64fba2f143c5b36dc503edb5c5fbc2f98eccb949b5ec6a5d3852d202b98766975225a3eee83b023934bc74b765445897c9d0ecdb204738ce236ad2171bc59b47084f34bfa4ab31630b4a67489e5fb2b151a06f5d9f7063eeaa4501e88b172a0fad8cbae96c385333b3b303ebd0741e2bffee38c0b95a70534b13a97aa43f4b7cf225939fb465c81c3755acaed576a3c87decf3e4e95335c27433973d0a6894dd830b484071d0c1f823e8f912a82ec1b794eaed42e6ee490aeab1c8702d259161c9010a9b8c394c5b05aaedeecb420382ab19561db6842be93f66d227b3fd7d709346fe35f609f24e3d19fc8736a8e7ff3280f8a01d78416a801a710eaf0f478b4c5fa0f35644f0a2ba5f7c0aa15fd4f842a4f91959e0316b53a26ca8ec60565af772a9915fa4361ff36b06a374703af731928b5849e791388aeff34ddc9ccae3257dfd407bb827468c832a5c4fa34292f87374213028b86a4671a32b6b2d97a42c1e39df2eefa55bc5fc53642dd130019751bf1ad2b6f82f253306939ece37c71f6d6abc5c6ce28083b598489fed29385e6acf18aba71d0d5f0fc456ed34f6cf74f803f5730c7a5df4f91ed4cc502bdf91a74e2195cd364e1b25f26c15e2e3031a80c3f4997a7dd187a5a326cd39e43978b87785933d5367aadf050776894557e4d808e5601e15a7d23b2d71b777b70e566bde53f4d7203901a77e2510ac3f2d211205a514c53c483831474906c16ce66fb6e16115b56cd9c1d180ad61738f90fa8be69b1b44180cfd2ebac158929a07eff4cf4bfdddfe421b01a220fccece09612545d306ab69527ff6831b9c91776c22911c6453d4b2baf45dfe8ca4b0a68c7966a8a780774bd2ebeb38b0549db21675c9d1049fa462cc08b00ffbb8c358583a33b35fbeb047ac6a674c8ed966b78d4fb32290d025ed1fad03c566229c3f5285539ed884c1b8fc37646edbbe8998d6a3014fb9b6954054e8266fe95a790ad427f46e76e38aa6e61a2c56dc1a725ad5bddedb302ab6429f7d4087e5dc04a96792bdb5d064ba57b1b73c0ed2d94fb60361802de1621a8bbbc3e014cb9e9896a0c31082d5ceddaf7e46da0cdd6a59cd08d88be22c7e64398ff741ed5d2ac301be114fd629953bcb668a7a9a982edee2363f38dc13c7a56371eeb2f6dbb89d47482b6c954d30b6432abf7d2241f6c8ce11d736182ec3daff4a4415495d24f14d780706ae2e8f0d709ca1e0b9bb445940d4ae62f69cbeb80fe585630ef19807849664cc280df4843234d0df7132a1f7a25d129dfebb515cabeeb63b5ba0f5ace8f725bf35a71f15ab41af88ea45db666d90aeabcd7290bb65422cc28c74e82785febee1bce89673d3673bef9b2d1c116e96864264804c30a07efa7553ec4e8aa018323cd9155d3389c2cfa44f1816cb9af5d19d54faa80c36c0f20920c03a221bdfb2e8a566af919354eddaa6742bae11e1930c1622cf14c1fcea5c483082e9c0a769c547d87a37fd20fe9648d841c1f6aa8847db2cd9bb6b515c9add7f15783a866bdb2e8facffa75509348c7ed149c705184d088a759dfda47d78f7ad83e06b7e616de595294e919e3732425fd592b813e640ee1d2e898c6d06c0f2d6317a5925575bdeb721318539f8a32f29ab684c809e2852df9868f57cc1a6106b93a18d8f16d21d3b3dd780054e7b21361e881f5f240254d5e902416328aabf1017f9c5e2abce170bd21d86140b57f0b5f0e0491f722f889e3e8fbbd8f2ed5b527e6b7b64624b3e59884bdce8a6a12192ae8e84692e16ee842f6946654204edee253eb82c8f7ab690f2119c6c52714c7b0f8374f5de4a951ff2fe755cd566f3db72f70245a5c89526fe2e9f68e1b8dd37569c91b59b81c9efbffa4e93ab8299ee73eec266c400a4b46f1b63ae0942cfbb80926156b7c16889d7a1f81220b064349c4f1c6ab76f90a7997200fe432b927fc83b6772367f25c20cbad04d1b3acf15e1247273405f822a37a2c8094f60f073142a3a00e7640c7804c7de4a8122a44e31f65163c7a8eacebed52d66f3e8cdfa5ddca5661f18fbfc8fa0297ebc84441b97b304c0012c5621bb1fcab9939069a328cc339ea314ed506626a2ef2d1ea06dd64ff3fe01f5147bc533ea828f449c177918262a760b4397e5ffbd6274ecf846ae2c7abbdab4c6d00f0a4e0530e5e380a6c3c3c8ef2240700f3da3e34c471ef8bd392834e6356eb403d6dde16978c39ecc7ebee011f113b78fdf2beb91cefb1deb44119c317a6ba33eeea7f269c1bf5263433e6b92bd808dc8f1e671ff2bd796bd8e307e755844f9e4076dbba67c1d28bc6b1b627b72329d7e03d809001796fe7ac8eac5ebc835b984ba66fe9c4bf46dd6a9fcdd5d8e7cbe4ee4bec0ba225aa77d517e670675c49a7e2e0b092b9276d51fe1765bfa28b3169ece0232982212793dafc69e683a25b7e7f08a480fe268dded0dd2de3108e4a9820c8db027b8fbc6714d5abb04489ac7c3378b09a5d114968a8389ed9ee86d30288526b84b11b4facd489b9cf7f27cd80f41ce991671524431161490df2f646051db8950b91ff0f634aaaf03bddfbd4223ccaa6ab26d058903a905927af2b3b8a6e02f9e6c83b1bcecfb60b49756cc22fcd799085f08345aae2d3191c3897724a7d5db05d520d4a60a0a3fa69a60cf12e2e9b60bfe83d242c64654198f587483eed1c4944d0119758a0a8e3e8656ca251dbb48b71d4514daf9e8873e39b8d846c6688e3573905da633b5eb70476e896c5536aa5343e842328b201b1d5a0a4ea787b8d38d7f260ec839c08df984dcbc316c392af2a92eac16a45218097518be33e13bdc70bb228022ec0abaa4b743fc99b4480894c9d4d1e5788e08550b851649adf3f1b7fc6fd857a29fe109fff211bdae36ba61bbed655584838e0d4721bf936f85d8794294ec9974f543d4225fce5a6d6ae2d9397401c6cda12b5ffca3f338b0401b42fa57412cd504cc18e1b928fdd23ab64d8659f88b937a3a980168b95a65f552c500e4e5a988bcc5df6f7937fab81dd2b8a242459284e179d5f0150e640491bf5de07742f9ea8bd12737977595b5f1e3d3a491dfb15a095348487676f10ce3992eedfa9b1f3bbc1e6ce62493a3f8e321259b31bab89f2ac6315c542c3b70fc05ec12c30b135e092cca03d5b5f00c601fac9a5c0ff89906e43f260464c374a423968f6c940c63e0926e1eba6db2a82abcb9f944153602c3ba58bac2e1ccd89d532e0959e26d5d84e6ff47e764526db1cf015b7f108b6010655242ce72711f935aae4d79cf66162599c5c843f56efdcf863d6b968755054d2ec3693cb64307ccc9dff250912a921172fb43306370ca51e91b4b7f7f0ea5c2fc623629ec33301b6957afa96484774e1b3faf1c3c57b42c43896c5dfeadea73128e0bfd483fa32788a5af54affb78e152365414493af9b01ec96e85e6fe90800d7d5a18216b6a5c8b4e250388ab6cc6ea5a79fb1b7647a5befa0c4892124dc3d210bd825e08a061c5fec639238cf2f4380ccd2013ca9ab710eff51c00940418f90ea178ae901a9e446c94052649cae1f2170025b1b1918065ce39540a592ca7701e5da54ccfcd52d20ca08aadc522f6cac9daefb8a953d0784aa820d8ab0ac9fad53e7841090da398a3ded9cf7fafc442ff04414c72f2b31f2931cf7a40fc22856856add4a346da7137cd1b9a2a7cebb6f5ef9269c12357c46b2303892f19b69be8eca66407d80ea26f9d0533d36682f645c1e1f9cec62e5d04320c9abe507ab2bffea35d81d6bbd631af080a4d4edb458d638099ee0ffee0b8bdcf73002b15cc12cde58c80be9b867e9ea93f3eb41f137c64a6823508a8b21c737946fc174729a46f397b3acdcf4b78214d3fba80852026548795029748edbba685a86ecad3241f6cd4b0e84a7c8d03f9b99c4424c31e89c836f65dade5c90d1996c6b8360ed1828cf71751cdf9692cdb180e54d2a301338f038e51ddec377a2879392507be3cf5daa7d661f37847bd6cb46b36c448d225a991ff4f86f5c44392017e6d735af6bde208db085bdad6b8ba0630dbc7cfa88745b5e4ee2a13a7e4808da544cf816ad9ae170c6e9c6ebf5ffafdddde04ea59e0ccd8e143a3febf5628cf54c1dc619db3f9300779bb0cc03dc2a2eb1f83d1578be8ccb7f6bfdd3a94e4675bb7ddfa5c83b09bee77ee21c5d5b16e73e5eef97307cf7aa292bb2771aed05cb0f24d484880bccb6d896d06dce45ab726c1bd977e9bbe92e4c47df2a3269aeebd1e0f32f1800acca6f4ad887359f4b921d29a2e6ae141f5fe73e7a3d67be1a88db518413122e0ae838ae75d1de22abeafd852397c5bea3656eb302ec36eb089a4962f1e3fbf68e5f6549277f3e476866daf37c3b3ce4dddd2d7d43286a34d756ea01688dae3dae774a0bec3297d04f0762e5902279e3db6b29995d4d020281abf0e6dd4073613e3a322f1dee53ce7bc9d51cd1273ca28e545cca60198b226ea4cfc85a39fa93e4434cb6afc8cc38c920eb1f87d731630c43aaa1065bd6f12c65e566ce1488e77fedcf3ef73aab451389131fb8e129aa1c002182959d0ba2861c408377e8ceee3b3cde42762c875736a23aa38ca6e234f38e0930a320a3ffafa4c8ac9c8149724bff852c7f77b11f775c207cc30019e01c9923a0a2ad43a0a5337d22821baca74ef0863f45bbaf2e8e5dd2001cb23a57df0eaeeb99fa36f5f63a989c374f551f83fcee931268b3400aca9310caba15df8c83cd7d6edcb4ea90305894880028e6740f4d08d56b44eaf6147be44d9718e676ed729cec3e84fd7c471b80c8002891309b96cc909c84abd7943a4c70d4b8e6740ed5d8bb5bf0dc00c23ab62f402cd1525955dab89eb39c61526ee4bc94fde30c1fa3eceedeb4ee6250f9a745aef131e10a07e341a74f37e55f37ebb32c824af92461c8c39436c9ee78aea1427d6077407933b836152c2062ddcfcc7b8ab3f41d330b3aa27016a2147dd967d2cba056de8d481765cc24fca660f186a69a415093acdc6d11e20b52d156d85bfe8cc29cdeb60523533b8d011863501754e7110a46270399ec5df84ec61d5548cc2a3dea6e2a401dac7935aa5e444d889c2a3c214f8202d5a5cab7c36017ad47d7f9e83ec85f6ae0dec500370e45ae454146bae33fd4994a687a10ccc026d9a26958ec84433a801daafe5d96cac83c320968994eb02f1c29f843333d21c7ed481900a8a87b18cfa70214f5edb153a2eee458946af88b450b7d4df44aa6d48cd7f4ec00b6c718fdfa25572f77e7ed78c096b532fc0e7f330d7f49b66bb19bc072b61e56950ad7378a458d1f716d8b62897ef52df36c170adcad136ba7c113cbc6e4a2c1f2f60e6a026e287ef2d94e6c75ade5c90734af13fe3b73f1e5b69d55597119f13eac2762b6a4b6d2c6ce743c6028e8433da7dc7d5ad5c93cd512eef9ecdfa0608e47dc914a683a548389a3e3208c6a19f4a6dd981644749c5246a50b5e0b18609e003d83f9d9c6902b5c2544d1cc284f20bcd5152824a1e0d1949d50f6c00402f2707b3ee6a78baf29945ca6ebb3715d33a1d64636b75fa2da99932f019abc87a8d216d65e8053e345b97b86cbb3715b4fa4ed2bac7b1e5595997b8de874572fe174063e2b30d082511f787aa0e1bcf88e8879755d1ab685fb5ec4884a992180361065738a2dbd01281766c5f044ecc40eb236e39cc6e0a8e971a77d202f83e50ef5b3be9bc5d93625f1972be341c430c0570ec69c68c6543af3be3d831bd3fdecc9524c23b8d7897df113e4eaf2321927b5cf2740dbf489944947ed48168e965a4fd8fdebe02157317d8f78fab53a321c88f5626a5d9be7d362d9ea4b9d0abda37eb21c12102cc4e5f1972f634b842a27103d439c2b605af650e7c576cb01aae734a954ea9aa0ec49ddc4a65b33f1d43aa8ddc02e5aeb237960b24a4dc52d08cfa0ef3a08aefe46180654bcb2dac2e8214a638a87d5e38fe2220e398ef66cf150f2a9eab5576d0aadd5812925020d167371bafa23211b7da39f7ec70b29e281b6d36825fbe9cba8f2d64453ee033cd4ca28571387947616473db3bc5763d1c8f66417ca3446f8b6eb7308d25e468c2037c7724fc1be88c09e8a589093f53f2a8f44979a443250481282fe98d6ce022ea5559ce12f57c54d120c3ecec58d5572fccebff2b4fedb530d1f187aa840d8f0bd8ffcbd1b2530eb5c5d414da1a96a028c146ae84d894b23707cee14948a243c821463ee3046bc34e24a4cc71b3bfa02cc5a014c9fe8156faf54c54d416d050dce5b2065b1a381eef0cc24d4a1c38b834a587332ebd0b070feb254acc0e82229a6d87d1119a41e39de5d1fa9421fefc7700dcce5cc4b492174789a64eab2725d23b1c9446a16275f09185a828ee448b9d6f4bffea5da2f5c788ff36ccd25edcd822cbe4ab6447e1a275d445451baf8401e84f706befa78005de91ae8f68e6642cc0e7f355f0f2a778b4e55e7ed5ecfa769f4c6e13f9f2703e4e630051320db7e5b0822ff2d5d3f570a00d0688af91d75bb2984346d16740c51e0c95f83076daede48a2cfc1b6834b058de82bf4bc74512583feac02704abfd7671c50b1c0bc7e60a2d31a4d5dabbb84338e296bd826958cb018c517628db4b123fc17cbeb27e7782d71cc225aeac29889bb4345cdc5e02b196a2a2ac262cbd1e0485d8880785813c67417343f6fc204fa5c7ddb4f4eb9c67803be6c1bf625aafc11c679c199b0704877a08f0d3d565f8cf8a0c898be3668f0871ae3c1dc0d86e010eab69a57c7686476813bbe7ea6f8e39fba419a220ac87ae1a27d062ccfbf5ecf4743664e46885ac2d9aa685a3cee1c68dc5233c82975426ac45c691f551418fa0de85c46ae20b04bf62c5d5d740a17e7042ff67cdcd41d3b50f5dace1db2daea90d64b44029b48131ecab7dc3fe760d36b476a228a46d57db770a182099fe3c134395b3654ca98e9af1c486ff543bf6d96db4381acf26017ca146f52976999ef56daf8337bb52a08411e6c3e588dcae7349fc7072b65c7b3741fa0f259314a98707cd1121c917a82408f6d5f38e62ac4310d25e4164a8a58638d2f14799f11a43a4b99a55203b81650a89fddd5829f5dada74fa78d48b2139b7f396135682cc18458e020062bcf7fb10f7d48306e721048406e430973b1da9e8ac5c1b9b7ae4d1b1f2996be70e7889d3faf9c14bd75d50d0737cf39f920addbda7c693cabf495ac468e466ae4a6df9a84f6c13f6de4258e0508865e980018abf5e7ddb4aaa64cf0ded60c20f64788edde66f49cc1f0587dc87c321b8fc4d934ea9215777bc8ca323a42aa8cc2205f14713574efbc4b66ce72589bc30d9507d6d2e9f72c260a52afc01991007a222b06c8bccef6aab98b737b4f9f1a8b40873da3f597cf94c878355e46defcb1334c02bcdeecc47adea8bac32bd3fb3af8e3a6f99badc18023bcbcb079642a27173c9954e6dcbb6559b8caa3ee1ed50da883ee30c1132bdb6a05346b13d3f6c85a2e434d36025a0c189bbb490bc7b9c6641f56187a48a06e7e90bd19a5955e6ca7eb96483a580056ce445d91c9b19056a5bc209efccaadea71a36b66c56aed7173387aa884e8a00e16f32b27060ed61e8e0540974614dbc7fa1f81ab72aaa26a7b907ce6f3e22fed3983ce2543002e0092e145b778d789763266ede2cb83a96acd6d9ea6ca8406ebde81e95578bb7d40ab992d6f971b93adb252dad2f4e9cb3ec8c3865eacbed2c5a8b9b5ec5e472f91027d6963791f5caed408aacfd1063a8e083b5698eed29ac4d017c575cd0520ee1c6f2b182cb60db7a8abb66a42842cf26418855b2fdde5baa1639b987bd197d97115579eecfe94cddd85240820ee2fe5f204571ae5e12fe1cd2cd51939f94a03aca24f99eabb735d41a631851a012bea4090725557056534c71f93a1d8806d8e02dceb4c088ae2b1713abc4f4fc3c101fa2fded082b896c3ee183a83f42c9e8d461e6a0def4d2c7caaad88f209621a1484f11cc2b3d223a8c1f16822a9331df26e1b8220f0720a5ec2807c7625fbc0387a0946d8ba80a9776b8a48dc667f19f7255711e1095c8a1119a605820d9603b20809698eefdc36ebf699e17d509de523bf84c91ae1439ab5f90bfd7f972160723c20dda29cef376b7042bab24ab290d21e3455370bf620ad11f70d4179b139079ce04d9be46853c1ca9d653e6566e4e84b114ce296a7bfe9f495ac4d855d72fdcfb8feb8ddcc36fffca9be623af45f71e79b66b8cdda49093ca30e71a0b070723c204d9be694fca0fc3eccc199517668aade978972080c7d51a350fedf044ba4c0c5565668dda0c7fb29d4db63a38a6734a8c50b72c0085c4b9d7f11a0b07f9103730ee09cee560a112a802bdbaa1eb6961449a7deeea4a814f60b6f071c59f7750c48fcea7f07594654bcb2dbe3c90caed5901e6c58b35d4da8bc864b418df381f7bcb2c8f3bb7d3a58909cf4bc9e5bfa1647042d1f77203f7c1036a43d35f765eea377e5e780df43a55b476fa84638e99be9902525e1c06e5e161e330e7ba686f93e556ec8401e009fb9458d755d58b4dae9359bf620ae22c43f437bbe3648d4ab36e89d75feae31c4185a5d4a037ded9e50b5fa53f8ea8b272223c8f41c8156e7fec4c725451ed220d09e078673f3f30875a8d81a762d31c3357bc81bfd058a4a89a7d103da3746941c173e0aa0e3ef028f413cc5a06b149d200c24e72f811c6b6887ed7eff89adcf37364ec6eeafbbdd6b8a6b530fdf74d464b4e38b935a48135283b183e9ec75518b554667a39a98eba757397de17f638de84a9088905e4c773ee560f72663b907e2a792cd7e4b695212cd062cc09e826d5e111b135a651db79e90e2deac053b06cde04901894ed883c6152d0b058ea240b563bef1cbd24269a51c468c90bea24a627e5c17ef25b3c8954d1352b76b36f0aecdd83d548febda72b4fed81ebbd3be3b85e0686d4ca56d904e39dbb3e2f256cd7dd1098498471ca1d5ba7aeff03e55ea6389ab63bd2e15984c3280e8be72a058d6be725d01fa1f10de9caf87fde75845a05163b94bc5c8114feff16981f3962f637bb597b10cd4ca2068b0885646a7fff3d48cf43a2b51ffe5f795f7a87e91b61db23a428618531ecc6e5c30ecb056a52901c445a7ca48690c1f97dcf4808fb144d79a3a835f0786fed599163173da0462f4fcf314cc737985469445e2dfbd4d4707fff79df331327e4c7e15eb37dc2e35736625fc5056c1ca53b88fda9f3bcc60389cf4d524e73eae22853e63163c50b0e1fcd39aef0b60ddccced68a912a90049d95b972d0abe891b87cc43322b04845cd3510daf88bce550d0b016c89ab32b701012823bebc37017db06f1baee89d5d9dac30f0c4b39f08fc01ee110de51b9e35e47e30a6da003db29a97f33fcd3ef1e09eadef772895596d1d541edc05ec88f817ff31a531e157838e75d28a2cf51939f109c759027fa4d1137321bd4fbffae5bde52eb5bc3478ec9d96f955b94a46c2b3791a9c38e654afd3fb958c2f17113a293e6b5d205d8b6d1f37796c0f17193c90476478c491b4d2ccb70300effa9cae2b36e8cab7f84955a2993d8be8b14b9eb53d930c75b9630f78cc1b1242dadef044da43768d73be25ec81900b60d6f5c0cda9154956d3ceaffc22ccc027fa9c29c6433f81e5b4eac780184657154d486f9f168ea983d46fc746b9fc7c19d278a2d955f0fc4be8c4ca76ecc1cd2bd7ebdd3b49a1cc1b429c1e2c4e6fb4b3ab87abeb212a7bf969e7457719e78b6498143cf89705eb390ef321438bf43d281acff66cfd6d83ec93dc4e875b5415a12767c813fb35af40179689383a64b854a8143cf6404d9f3475a165a6237d5dce66604c547cbcfec58b57ab479b5d47a0f8f4d0889052423970a2d8d9c66bb4962e2681cefb0597ed7371c193cb90cdcf3d3462570569db701dc8f4c9bee08c649a062ee92c643d3d671dc644fc71b0e23a349d75559d7c2911b573d169322f7d8d8140d448a6344ace4c0873d859659760ec34f0d45f06fb37b9cffe1658410a71c29b435b9b41ee24c2496932c1e798f0fcd70f27e272d9904644660d79b4498d44dc5478bd9bc06622231725d082fd3d45deccdca5320a37e99290d886dac83c349c54726ccebb75cbbd841c4257152d28068eae6ef851638913e27e21016a110ac45d579b01f55796e537550d35f519052de21f88fdb4b16d8b26a171fe3cc4cec6be9058daa9efd193ac4b5f4883af4d857d52dc9eefaf71033c340a11f2ee688f9caa3f20ae53fd8eb420a2d87a8a878f674c0ada4f6acfc41abbf561d0a8a48a030bc754df924769f2e44b57b54e2321ce44261779bf70a386019fe341b0bc8ee4f8b91b602b1f59ae56c8c421f985a06be325b1c4d5bcb183ebb3faaab6d02d0270ac7f6423f4b684e0205f7b527e76b61929a9e2af7c6e4c237cf6e8572a007cd69c4fb4f32f3d0f618b49e3e0d6087058901d8af74936077f2935579f9573c94b704a8414219bd9613622d1c4278f8ce6b15616561d6729231d09efa84a0c8fb0b6dd62da8738f0e44ab644bef3fb311a929dcb46c8be89f64ba1574d3ef6437699f7e89d3fa79816b3df3dcee9b4ba5a264c0cda24db1e5c96e018e3fef477362bf717cecaca98c09a0eb83d405669ccb0e29dd5bbd9e1a94756bd3800b03c38eda1e7bb750f3df58b94363e3018d0f83efca7e6bb695334d44aead3fec66e488587fcb7d9ab92b941a0a26a66400482be50657a8884e8a21c04e7db267ef6d395fbc1659f6e5c540e9331cdc30bc3e1ef6d175dd3a9917f3d4f63f62e77578e6535ac01dfa0d27971c2901818b0f8d81f16ea9a30e2d0b1fa6d937870295284433210540db660e161b095f14d75b7366b76108cef1128a1bfa742cad6f61e76b625e7bae6043e5da3bf5ae1ca9cbbaf5906e6a57348467141a6bfda8c11ad0ab7c0255b9070f5bd8396740498f3569594564d04d0a4cc728ab634fdc1e92129f76c1c74e004d61e4a553d7c222ae2c6688afb35cbbd8e51217e1a222604c99b96869dd00821b41af9f4e6744820ec45fc40705ca41d269ff1e703d29c2055aa2e18194a994408d09e8661ae41992119df6dc6815ea98459748f9da5a8876f4f89bb427661652b471b57b54ee9b4b231b2d21c6b01e3f19cc345621ec27ab090a77ecaa94d4a65d622ec2eded6181960938f038e8564462e737583de8c21d3909a582b675759b46c7745054433c194e7e96b135026151496be4f7c2a6958d894be508d06ba281e74aade0830b8143e34eb097e3da29228c00e16f52d3119119956c0fbbe69f32408d4e01884215d8bef6565ce934bf173f27cb052a8ea3574121b003597f4d28a92f4ea3cb96b5f227184b19c68b2fdd4c8dee012eee5a2f5c8371cb310d11d6b8a8a372e205edf0c26f17a011ccfb016574497fbf5439eb32fd810c904fa8cff673b27857d7406fcbee57c0314baf235777e72f0008aec5896e8cabbffeccbfd5436e5379ca63ef6db29294a7a144678923c24ca424e650dc5069fdaa267fb5c751b07e4ac80a42d55910086614a58f2ea041efd991729919b80bc0a401527dd27ba8664986a9d20a0b25c470adeedff95cedc03e02cfcc75f9107c05eddde5c2476efc75b95cdf5d01f9deea21caef33b455437afa187efc702b1a63b8eeff42564ed93d29026ae864ff10f5889ee59c19f8add6ff0fb36540e3f743de7eaefc5020e6ce4e0c38b834456edaa7bf2dbc39d8e283a8cf45c78bd426396bae8debf213dd6268e72152900d81c61e981e0dd6519fb002ca8de45aa2a6f93b62a88015b4d38350311b13be3ccb6110024f7df8b927eddf7df17316522b2291d44512400ec0efc6028e64b8cf40340545f4028cc02a73039c10128a6146fa93282dde49497d2aed954971f811c6578aed0b07d79c893428c1bc443cabc8b650a6e8a02e2cd4fd7d77e0f86ff67620a042bc19a55ad93d29022e5c33ed8034690a280ec387ad2e6a4fc459b91f1baafa7239ad6ceb082efccc013998366867e0ed080f7eb76de661a3c764e841ea5f827f9d2a0c63fc75192ac2f9c5a05cad065fa51b9776e88000420b6bf24f54de710de1343a957cfd91ec1d39f917ac2c186a486e6f834d42859bae87da4de56d18a339d8d29e024832f07c7261b97de03dda4d7df839b8e51c101b67f87c10dc7af8c957e0c7555492b7f60fd33a1d1cc522a9aa2f8e133cbcec6ae804b394a0e1aadf11f51db4d523f3e2de984a1a70fb1cbf5770d27b685d0573e4437cd4b777eefdeb7c9d7360e0227447cfc6c2c1b93013b5283450fb9401ae9585fe0c72bd5af9e7131515127027b699b38df8596ed3648fcc8a2ad88ea1d6e142fe733ce1062d723d4867a3821195178b587fcbb32e62894b441fa222e090119da474fa5eb99acf49a8427efe7cd423889063e2a25f795fca77b916ca0b87d1ea1243b0f50526c06113914cec2ea252dd34c35a8760acc536dcd744c469a2621fe03869acf7a07bf76e1176d2d459db033c200053f37e9dc96c8002868c6bc1025e0fac56b1125bcb74872fef19f9089b4b4a71db05032e1dbc3166da26d81684e202f1a28c4c9b8f0d3166da26d81684e202f1a28c4c9b8f357dc0d1338e1405e2ad2f9e31cfc621019e7521b0c39dcc0d3ffec4afbc8d843e42090e6e31a4ea1c76feacc4fbae1a539dbd01d88816a43fd41d26efe922a746b55eda26d896672817a33ee0b27502a22037e69472172481054624c3e0f3375d45fc7cbed05bd7ee45ff3f2e74acd06ed32b058a5dde2cc8effb3ee1b38f18f977e091b38ea7dceed86c31e2b3775666a8875e46254130b49622af2a09af92151445b775f98a01e8f78cc45c7fd986cb53c60b6e9414984570c4f92818fce9cac8e767cd0911a9f7d367aa3417b162f1dd5601327b2e98491ccc012b5c022a6dce3133679c3ef677c7fa340c071ee528dc308f4d8160ec056061639fb4924726254cce34f7ec92f5d3672e5386a28930ee7034049f7c76c60d19165e032520f3d93ecf1baf5c4a92ab2348faf7fa31511d8a0ac8a03bb77e1eaa77dd1737c3799ff86073e567aba9dfcba6057ae4ad5594a5be7df143cc2542620793676e0538a38f0fcd62f580797c7c9ca53a298e2e621679629d18957c311efde789ae2b0ed5fada05890bd6de32d1bfe1b2f52235c5e778f3d8848a3482454a09e5cbfcdc86009c5cd0422a356965e22b8938a862457afa988062007ccdb2a21985a1248d4867e70880f37891669b9633db32bd309e02dc1f930b8e45d5bee01b469c63d196bc2bc784021faca5509a7d9e03bf71bf1028d6478d91f8f00ec6165c4812101fd346c9e21091780f424517afdd63f5a59a31dfcf3d9335bf78a5c2ef4b6a88465d7352bfeef311ad2e6cce7de4f0570306333beedec631edaeec128636b45a05ad0881033cd11ab561fca5620cb02b711c995bc7e6fc5eb3cf95370b502a68ef532af5679de9ad341af577e4b6b069033195d97fea5fc48c89cb2d0e0298023a493312ebd422469d29f4d852b0b65f004c4ee05db9197355e138a182a4c5428693b9d3a5040d069a2d5662a1722e129ba46548ae951dab8cb88f3ff4c74849664f8e860a88081b1f57f8fe6b36aa3c2ec69ca5e48c67923a86c31ac4c9ce27a42c9c53df6d3f6bfb83c6a8a91a2a9d6c74786b4f1c8ce7fc07e7f5bbb43ef4b5b16b9bde20fcdedc904ea9e26131d51b749df37b1df4c212bd957350c24edd8a98e3a777ea608966969856edebf9c0bef8b642d5579b14df2af710fc5c91b997917a659303ce695dce6dbad7d6bdd8f2878a625db8cb6542f621ce3f1f9a9bcca2a1877ad558b172236685a6d0ba4dd8353922f3efb31cb6f802b89237adb02832b2f030efa9587f8bf317126a5b8361aa26dd2341007ccdb2db2c66e45caf05917071c38c29c2e5e529eac8eecb5b94bbc327c89df295c931ca735076822cf0d353c17cbf26cfc88dc2e7f94147009ecfcd0bac9c7dae676b19c10836325ab419ca0c79f951982e01372922542971b598b405e31722969a4b8a6d6e72e1f9cafb36f19f7c76e62c2e9d47b17038c2bb97b1b075cd40a9661ffe61ca2098027abc7c28049212fb5cf6a90273f695cd4e34fae1e7ed50da933ad7c158abe7fb4bc5297073cfb963400dd90de24c52d488eb590480707493295fde769030785cf79da63896cd27cfe8d4298685a366c60e21e9261588223ff17629eedaa49033f5b411b7f7cd6c5eb90dd098286fe809e7e755b9e1c125c8febe295e193f3a048456656c0dd5704a6dd9e5b3d6f1740995b7d5877d6f7b9b1937d535ef7bb67d7d213595eaf901f2696b0c125daacd7a8c939351dd038edafd49aa30439de55ebc39110d80be33daedaaf222dd9fe7fb0927a7bdf84cfe1770fa36f06179fc9d1db037eb58bdf1588e68104d4274b0b5507fff1fdefd5eb71038b5f73e297fa06e4128d39d1f93e4ce0dd2350e1e19f0e4046bce0d19b9e13c438067e4b0b843e01ae4c97cfb7d0a1a927216321e9b3a10b471f176d9a64d6a767f65703fa9c04db879e9736503e6ce06c8386dd70554f8003873686487e0dbb11869c87571868b8ed14ca691038f7edebc04077adb8436ac033b5fc6203afbf429253a64895594a5e9a97e099949f44e78082dcc1f0cb042f7b2eedfb48b99472ef113336d394c15f8e458d7253041f4c6731ad552b27c23946adbda11aca596de20308303e2a4f0b3f7306d5159388f522d9a74b5b2735cdc1c9e1c80280f3b40a7929073d01bf3d0f579fb3616a3f26384a79b19f866cb8c8d5edcd05377c36696165200591ea6ca67acb9546b9c345a3d0b066dc5f18d2b146770371faa5d8e7e963c20afa1dd81328979f59c095dd6be88d476320f271dde189a96afa586c5155ac475d98dce71b3bf024e0f7496d63010cbce4aaad915b04cb43c1818ac31e0b275c263ad02d234f002e70e290cc16d6253ad74d62109baedd96e8cabcf84228240b4d81738acf776ef76919b9b28ce469ce169838b45ed64e68a79cff3bc84687c90d50a0c14c3f4b071245722d969d236a72e869221f8ec6fe302862b7c9bb82860e43a15d59d4966429374f47b97b4f2675abef8a39755711a2d65a7e63c1fb9c5487d76be8c80225119bbd9da791f39bca85b9509ef43b03b9a8dc77ab902156b48afd3ed737ef111fe9939a94eed9915f45ae322630bf831909e8f65a6676e259b547bfffbe86fe3d2290fb0c01bb426d2392d0f107c6af034cdf3aa0f6d74b3420ef6bbe7960c905b880c0f10942c5324a27e955fdd5fb3c5e16379e659b3803d4405ce0cdf7e7f6234ce34cecdf07534902182c8ee3d38d3bf34b74c5a7c793df3dc3ecd871d2eddfaee7278818a03e26cf031f27b6beb98b122766fbd2be1d09c65ceecaf7d77ec85744d85936cc7b188024bf1c7c9cd4e1802df3835713b8461ee76b4f85e595d39060df016277d139dbc0544cd4fcb0522d617321d8852911d5631f277bda9db6e9d40a7bde1dbb9ee43bad83abb373e35f8963113306687490e874589f8749df08fdea0650e2c0470b21dc57ed4fe103733426150cd4ebcdb3aa620761de19afb4f9257929055c1f4da5a40e919154bbb0b0bcae6cbd0d09f37cecc2e5f35e18c54b0e7c2e489b40ef24f3fe7ccd61afb528f68afe1db4d9cb9110b0fc58dfc8d329fa336ebd964d023153a467bb3f654e23f9411b000e16f4eaecb0e1f4d090e9e9f8b97b174e52a059f5dd183135c377af379df51ba9d82fb31a9cb957e81db9b1b73ac80ba58964dce0e820028fabd337a31ea12f202cc43f57b6e667008726d45900a222a50269049498823b4face98f17e6ccb6e345723d4180d69be7f089548ef5e0f8cfdcdc288afa1a9d9c8f68ed50478e04aaff087aaa82daf4381b5c36ee44a6fea3f99b6362d11ea68c203443b27d2dbf3f12e186254c1c6ec563909dc19e4cb1cf937786c7e2856a4817eab5737c8d8ffc25156465e2926bb5275e2ca4e2ba0b17db31ccc8ca424a8f5aa1ec3ef2a249314a68af4019745b832b6eb66335891634c52b336ef0f9b4e2ad33d6d84a680879cae728d3eb331179c1baee4fe333d7d7a9731a60fc7c56d532c9b46e9061de3cc1f9611f37ef56a8af72b4f189fca6e701cb953c9c8e3f199b36b269297f87e7d980fa5fac6c91f44076c9ca40bae5280dcbadcd5397169c77a09c291127956a61c7109839f6530d43a01c3c9d710491d1eb1b0ea3b01a9798c6bc2194210925147dd47f078e101ab395f7f63cfd4325f603731f17705d394b33b1679542623ca9ebf1af36cdb3dab7925f81f093e99f046055922a5024699bd0f20ef6937afa01e6ecec4b3cdb224fe0bd7b53f199ccdd2b8fdd9761da568b58acba083a596180e51f8615a867d808f17c31b4623a0412712925bb2a7236740f18187a98a1ab3b7e1918344c6caec9d2d32f983aba579ccde076858bcf3dc9521d16151394461ff7345c3bffd926c56d869a4876183650f385e0705402ac3e4548d6ae9ec01312520a022da59d5d63d0f5f6a4b6d6c8e402f8a5f5789984ac2ac0548a76e8c69ec5589e9ec7d7fa25715ca2d6ed869e18192777f30b539a0a37b16403478298c436ccc72fe7cb8d2ff2de0758b06542be4cbef2ba70559c91d3766f110cfe3f9ead656147ce1919800964b2c6528d209a3b02da57ff06bacd163be4972b5b4a6f8d757a42aa8cc0522d6173319980aea244fced2fae9a39738c8b5f192d557b678167274314f138b139dd6ff7a505e1534b36d8cd2abeac5eeef33d40d2faaebec0cb7e860509d5b5a10cf28af6e1c4ed281f0afe247f703e1ed6e89d4472e1e39ad34d857d555db1ca97493153f9de0604e0131771e3b98642fb68c96939dbd7fc149961a98ff3a2332a5d7dbe61df43a55f0f27861ea002797de20301825a59b59ae734ae6cc1a1867ad1f850f26e2ac2c7fa0ce0a62bef3f350b79433af287e4e326341f4105a3b5887124a87522b715643cad17d01a4a17842e3cd262ffe47c22ffe028d8be48174c522816fea0b01835439f8ec3780e8ac641bb6548bb5173ff38976b2a6738adb3924996c1e8735fee6188ac7583f5d8c3a8c6be7f49b5a46e92ee50b0b25e178607ea1ed5d41bff3457777ec83fd99165b777d836a3f2bebbe78f4b63744d9b6889eabe616e9c25feb29a5da331c7767614228a90f87752c18a0d992458208b8658a8dab6e438da26619a91644b349e2a20b6f8f6c6e02c1f30a03c38e2548f82fcdb790153efed1416757ac2fc2e5f1963720a4ae408e0149849408eb35f0ecff8ee54a140227119113b326ba7f4c1cc126ad9d18b997a01307be9d018a9b434a2b275e187c961ce6184aa67ad704d6f86ead8f0ca7c51ce7b4dc2ce0bafa719d7ad95fd938427fff9d8a140b25d9e06ff27bf861bc103dbd4fe062ae137ae9f314371b997826e386add0a41907d9b1a20508098f6e60685d05ba9fe02b2b5c01dae7ae8caaaa6294cf6d2ac5c610dcfa885de35aa5e444d889c2a3dea6e2a4019a5de35aa504f4c59ab9be0fa222b58619ae6499fc86754b4e199c0ca2a305c92605c359b8763aba7820af236a3a49b7947f89efe35e8f2cff790a846dc2a8078988ae6b013df74caa262454b4e2a401dde32ced205fb4a6b8c3402f3748dabe454b6d68bb745b0f6cb0824984710570f2f3446878c61ee63ae74eb7ba0dd23adae7cee0f1dcc43af8f4e66b82812ff2d5ccea6f27efc008fe65c96701dee023ab074cca6f9e7c4036b93baf4b6cf838dffcdb442ad93a271ece9fb4e28a3e63243e691e87728c56faa6d06592e85e830c0418e93ef8d7c71a0b875199b64321c7e40aa276d26fde042867a7738a2022d8cccf8362ac76b8e0980c925fc0ad9aa88c38a862f971b1325cde52a7a70740d8bfc1cb9d5c4a65b33f1d6b82a5bc6681eacb72509dbd8642ce8405ec4b3915844c9b683b30658273ff3d947c5ba57790636bee8fa92afc34b93bdfd6e2a4011da27b42a9627ad4013458a34352fdf4f36a89efe33e8fccf2ff1ca251dbf91f55a0a8e08775843a19ac080b25e1766c6fbde31a1f495ac419ac080b25d93aababdf522e9f79d6032428c11325e1b8620fcf4f0e08b2ef65a78b1e806062652192c35c143e23ef82065ce3f43543e710562861f819776beb29908bca97b105307ad6ffcbedc002746c194ea85377c38a7b585e5f82dc1041aa2624d2df30f52ccbe85b87cbe9c4448ec4202f31e4a4019dca93080c708b0bc978f865c8d959c143abe834d51bee9a2691179be21f09c3996547c2abee896d5a2452a6347bd09d795a8c0eef61b435f781fea1b4e8b4094e624441cb53570ccf43e3628b0c69c7dae7ae9c1ff93f5a1c8297c462f5ae1406620eafdf0129a90b2152c6b460a7015a04ea16bb6bcbfc1121832d734a7123d86889efffa0ec9e24d4b2a6734a7123d86889ef77e9b1c9e36e3369f8141b8aceedcb4ee624008aa2c2620c'
from pwn import xor
# .png files all have headers like this. This is the first block of plaintext
png_header = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR'
#this is the first block of the ciphertext
b1=bytes.fromhex(ct[:32])
key=xor(png_header,b1)
#now we use the key to xor with the whole png header data
val=xor(key,ct)
with open('bean.png','wb') as f:
f.write(bytes(val))
PUBLIC EXPONENT
> Crossed Wires
'''
Here we are provided with multiple public key exponent i.e "e".
Therefore, we will have have mutiple d with respective to different e values
'''
import binascii
import gmpy2
n=21711308225346315542706844618441565741046498277716979943478360598053144971379956916575370343448988601905854572029635846626259487297950305231661109855854947494209135205589258643517961521594924368498672064293208230802441077390193682958095111922082677813175804775628884377724377647428385841831277059274172982280545237765559969228707506857561215268491024097063920337721783673060530181637161577401589126558556182546896783307370517275046522704047385786111489447064794210010802761708615907245523492585896286374996088089317826162798278528296206977900274431829829206103227171839270887476436899494428371323874689055690729986771
p=134460556242811604004061671529264401215233974442536870999694816691450423689575549530215841622090861571494882591368883283016107051686642467260643894947947473532769025695530343815260424314855023688439603651834585971233941772580950216838838690315383700689885536546289584980534945897919914730948196240662991266027
q=161469718942256895682124261315253003309512855995894840701317251772156087404025170146631429756064534716206164807382734456438092732743677793224010769460318383691408352089793973150914149255603969984103815563896440419666191368964699279209687091969164697704779792586727943470780308857107052647197945528236341228473
print("n==p*q?",n==p*q)
n_e_values=[(21711308225346315542706844618441565741046498277716979943478360598053144971379956916575370343448988601905854572029635846626259487297950305231661109855854947494209135205589258643517961521594924368498672064293208230802441077390193682958095111922082677813175804775628884377724377647428385841831277059274172982280545237765559969228707506857561215268491024097063920337721783673060530181637161577401589126558556182546896783307370517275046522704047385786111489447064794210010802761708615907245523492585896286374996088089317826162798278528296206977900274431829829206103227171839270887476436899494428371323874689055690729986771, 106979), (21711308225346315542706844618441565741046498277716979943478360598053144971379956916575370343448988601905854572029635846626259487297950305231661109855854947494209135205589258643517961521594924368498672064293208230802441077390193682958095111922082677813175804775628884377724377647428385841831277059274172982280545237765559969228707506857561215268491024097063920337721783673060530181637161577401589126558556182546896783307370517275046522704047385786111489447064794210010802761708615907245523492585896286374996088089317826162798278528296206977900274431829829206103227171839270887476436899494428371323874689055690729986771, 108533), (21711308225346315542706844618441565741046498277716979943478360598053144971379956916575370343448988601905854572029635846626259487297950305231661109855854947494209135205589258643517961521594924368498672064293208230802441077390193682958095111922082677813175804775628884377724377647428385841831277059274172982280545237765559969228707506857561215268491024097063920337721783673060530181637161577401589126558556182546896783307370517275046522704047385786111489447064794210010802761708615907245523492585896286374996088089317826162798278528296206977900274431829829206103227171839270887476436899494428371323874689055690729986771, 69557), (21711308225346315542706844618441565741046498277716979943478360598053144971379956916575370343448988601905854572029635846626259487297950305231661109855854947494209135205589258643517961521594924368498672064293208230802441077390193682958095111922082677813175804775628884377724377647428385841831277059274172982280545237765559969228707506857561215268491024097063920337721783673060530181637161577401589126558556182546896783307370517275046522704047385786111489447064794210010802761708615907245523492585896286374996088089317826162798278528296206977900274431829829206103227171839270887476436899494428371323874689055690729986771, 97117), (21711308225346315542706844618441565741046498277716979943478360598053144971379956916575370343448988601905854572029635846626259487297950305231661109855854947494209135205589258643517961521594924368498672064293208230802441077390193682958095111922082677813175804775628884377724377647428385841831277059274172982280545237765559969228707506857561215268491024097063920337721783673060530181637161577401589126558556182546896783307370517275046522704047385786111489447064794210010802761708615907245523492585896286374996088089317826162798278528296206977900274431829829206103227171839270887476436899494428371323874689055690729986771, 103231)]
phi=(p-1)*(q-1)
#writing a loop to find all the d values
c = 20304610279578186738172766224224793119885071262464464448863461184092225736054747976985179673905441502689126216282897704508745403799054734121583968853999791604281615154100736259131453424385364324630229671185343778172807262640709301838274824603101692485662726226902121105591137437331463201881264245562214012160875177167442010952439360623396658974413900469093836794752270399520074596329058725874834082188697377597949405779039139194196065364426213208345461407030771089787529200057105746584493554722790592530472869581310117300343461207750821737840042745530876391793484035024644475535353227851321505537398888106855012746117
for e_values in n_e_values:
d=gmpy2.invert(e_values[1],phi)
c=pow(c,d,n)
# Note: c has to be updated every iteration
print(binascii.unhexlify(hex(c)[2:]))
> Infinite Descent
import binascii
import gmpy2
n = 383347712330877040452238619329524841763392526146840572232926924642094891453979246383798913394114305368360426867021623649667024217266529000859703542590316063318592391925062014229671423777796679798747131250552455356061834719512365575593221216339005132464338847195248627639623487124025890693416305788160905762011825079336880567461033322240015771102929696350161937950387427696385850443727777996483584464610046380722736790790188061964311222153985614287276995741553706506834906746892708903948496564047090014307484054609862129530262108669567834726352078060081889712109412073731026030466300060341737504223822014714056413752165841749368159510588178604096191956750941078391415634472219765129561622344109769892244712668402761549412177892054051266761597330660545704317210567759828757156904778495608968785747998059857467440128156068391746919684258227682866083662345263659558066864109212457286114506228470930775092735385388316268663664139056183180238043386636254075940621543717531670995823417070666005930452836389812129462051771646048498397195157405386923446893886593048680984896989809135802276892911038588008701926729269812453226891776546037663583893625479252643042517196958990266376741676514631089466493864064316127648074609662749196545969926051
e = 65537
c = 98280456757136766244944891987028935843441533415613592591358482906016439563076150526116369842213103333480506705993633901994107281890187248495507270868621384652207697607019899166492132408348789252555196428608661320671877412710489782358282011364127799563335562917707783563681920786994453004763755404510541574502176243896756839917991848428091594919111448023948527766368304503100650379914153058191140072528095898576018893829830104362124927140555107994114143042266758709328068902664037870075742542194318059191313468675939426810988239079424823495317464035252325521917592045198152643533223015952702649249494753395100973534541766285551891859649320371178562200252228779395393974169736998523394598517174182142007480526603025578004665936854657294541338697513521007818552254811797566860763442604365744596444735991732790926343720102293453429936734206246109968817158815749927063561835274636195149702317415680401987150336994583752062565237605953153790371155918439941193401473271753038180560129784192800351649724465553733201451581525173536731674524145027931923204961274369826379325051601238308635192540223484055096203293400419816024111797903442864181965959247745006822690967920957905188441550106930799896292835287867403979631824085790047851383294389
p = 19579267410474709598749314750954211170621862561006233612440352022286786882372619130071639824109783540564512429081674132336811972404563957025465034025781206466631730784516337210291334356396471732168742739790464109881039219452504456611589154349427303832789968502204300316585544080003423669120186095188478480761108168299370326928127888786819392372477069515318179751702985809024210164243409544692708684215042226932081052831028570060308963093217622183111643335692361019897449265402290540025790581589980867847884281862216603571536255382298035337865885153328169634178323279004749915197270120323340416965014136429743252761521
q = 19579267410474709598749314750954211170621862561006233612440352022286786882372619130071639824109783540564512429081674132336811972404563957025465034025781206466631730784516337210291334356396471732168742739790464109881039219452504456611589154349427303832789968502204300316585544080003423669120186095188478480761108168299370326928127888786819392372477069515318179751702985809024210164243409544692708684215042226932081052831028570060308963093217622183111643335692362635203582868526178838018946986792656819885261069890315500550802303622551029821058459163702751893798676443415681144429096989664473705850619792495553724950931
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
m = pow(c,d,n)
print("plain text: \n",binascii.unhexlify(hex(m)[2:]))
'''
plain text:
b'crypto{f3rm47_w45_4_g3n1u5}'
'''
> Marin's Secret
'''
We will Directly Decompose N
'''
from Crypto.Util.number import inverse
import binascii
n = 658416274830184544125027519921443515789888264156074733099244040126213682497714032798116399288176502462829255784525977722903018714434309698108208388664768262754316426220651576623731617882923164117579624827261244506084274371250277849351631679441171018418018498039996472549893150577189302871520311715179730714312181456245097848491669795997289830612988058523968384808822828370900198489249243399165125219244753790779764466236965135793576516193213175061401667388622228362042717054014679032953441034021506856017081062617572351195418505899388715709795992029559042119783423597324707100694064675909238717573058764118893225111602703838080618565401139902143069901117174204252871948846864436771808616432457102844534843857198735242005309073939051433790946726672234643259349535186268571629077937597838801337973092285608744209951533199868228040004432132597073390363357892379997655878857696334892216345070227646749851381208554044940444182864026513709449823489593439017366358869648168238735087593808344484365136284219725233811605331815007424582890821887260682886632543613109252862114326372077785369292570900594814481097443781269562647303671428895764224084402259605109600363098950091998891375812839523613295667253813978434879172781217285652895469194181218343078754501694746598738215243769747956572555989594598180639098344891175879455994652382137038240166358066403475457
e = 65537
c = 400280463088930432319280359115194977582517363610532464295210669530407870753439127455401384569705425621445943992963380983084917385428631223046908837804126399345875252917090184158440305503817193246288672986488987883177380307377025079266030262650932575205141853413302558460364242355531272967481409414783634558791175827816540767545944534238189079030192843288596934979693517964655661507346729751987928147021620165009965051933278913952899114253301044747587310830419190623282578931589587504555005361571572561916866063458812965314474160499067525067495140150092119620928363007467390920130717521169105167963364154636472055084012592138570354390246779276003156184676298710746583104700516466091034510765027167956117869051938116457370384737440965109619578227422049806566060571831017610877072484262724789571076529586427405780121096546942812322324807145137017942266863534989082115189065560011841150908380937354301243153206428896320576609904361937035263985348984794208198892615898907005955403529470847124269512316191753950203794578656029324506688293446571598506042198219080325747328636232040936761788558421528960279832802127562115852304946867628316502959562274485483867481731149338209009753229463924855930103271197831370982488703456463385914801246828662212622006947380115549529820197355738525329885232170215757585685484402344437894981555179129287164971002033759724456
p = 1475979915214180235084898622737381736312066145333169775147771216478570297878078949377407337049389289382748507531496480477281264838760259191814463365330269540496961201113430156902396093989090226259326935025281409614983499388222831448598601834318536230923772641390209490231836446899608210795482963763094236630945410832793769905399982457186322944729636418890623372171723742105636440368218459649632948538696905872650486914434637457507280441823676813517852099348660847172579408422316678097670224011990280170474894487426924742108823536808485072502240519452587542875349976558572670229633962575212637477897785501552646522609988869914013540483809865681250419497686697771007
q = 446087557183758429571151706402101809886208632412859901111991219963404685792820473369112545269003989026153245931124316702395758705693679364790903497461147071065254193353938124978226307947312410798874869040070279328428810311754844108094878252494866760969586998128982645877596028979171536962503068429617331702184750324583009171832104916050157628886606372145501702225925125224076829605427173573964812995250569412480720738476855293681666712844831190877620606786663862190240118570736831901886479225810414714078935386562497968178729127629594924411960961386713946279899275006954917139758796061223803393537381034666494402951052059047968693255388647930440925104186817009640171764133172418132836351
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
pt=pow(c,d,n)
print("plain text: \n",binascii.unhexlify(hex(pt)[2:]))
'''
plain text:
b'crypto{Th3se_Pr1m3s_4r3_t00_r4r3}'
'''
> Fast Primes
PKCS#1 OAEP (RSA) - PyCryptodome 3.15.0 documentation
To view the key.pem
file
from Crypto.PublicKey import RSA
f = open('key.pem','r')
key = RSA.import_key(f.read())
#Get the n and e value
n=key.n
e=key.e
Final Solution
import math
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
from Crypto.Util.number import *
import gmpy2
import binascii
e = 0x10001
p=51894141255108267693828471848483688186015845988173648228318286999011443419469
q=77342270837753916396402614215980760127245056504361515489809293852222206596161
n = p * q
phi = (p - 1) * (q - 1)
d=gmpy2.invert(e,phi)
#Note: don't forget to change the datatype of d from mpz to int
d=int(d)
key = RSA.construct((n, e, d))
cipher = PKCS1_OAEP.new(key)
ct="249d72cd1d287b1a15a3881f2bff5788bc4bf62c789f2df44d88aae805b54c9a94b8944c0ba798f70062b66160fee312b98879f1dd5d17b33095feb3c5830d28"
ct=binascii.unhexlify(ct)
pt = cipher.decrypt(ct)
print("Plaintext: \n",pt)
'''
Plaintext:
b'crypto{p00R_3570n14}'
'''
> Signing Server
#!/usr/bin/env python3
from Crypto.Util.number import bytes_to_long, long_to_bytes
from utils import listener
class Challenge():
def __init__(self):
self.before_input = "Welcome to my signing server. You can get_pubkey, get_secret, or sign.\n"
def challenge(self, your_input):
if not 'option' in your_input:
return {"error": "You must send an option to this server"}
elif your_input['option'] == 'get_pubkey':
return {"N": hex(N), "e": hex(E) }
elif your_input['option'] == 'get_secret':
secret = bytes_to_long(SECRET_MESSAGE)
return {"secret": hex(pow(secret, E, N)) }
elif your_input['option'] == 'sign':
msg = int(your_input['msg'], 16)
return {"signature": hex(pow(msg, D, N)) }
else:
return {"error": "Invalid option"}
listener.start_server(port=13374)
from pwn import *
import json
s=remote('socket.cryptohack.org','13374')
e_n_value=json.dumps({"option": "get_pubkey",}).encode()
ct=json.dumps({"option": "get_secret",}).encode()
print(s.recvline().decode())
s.sendline(ct)
secret=eval(s.recvline().decode())
ciphertext=secret['secret']
flag=json.dumps({"option":"sign","msg":str(ciphertext)}).encode()
s.sendline(flag)
print(s.recvline().decode())
'''
Output:
TODO: audit signing server to make sure that meddling hacker doesn't
get hold of my secret
flag: crypto{d0n7_516n_ju57_4ny7h1n6}
'''
> Additive
from pwn import *
from Crypto.Cipher import AES
import hashlib
import json
s=remote('socket.cryptohack.org', '13373')
#decryption from DH starter 5 challenge
def decrypt_flag(shared_secret: int, iv: str, ciphertext: str):
# Derive AES key from shared secret
sha1 = hashlib.sha1()
sha1.update(str(shared_secret).encode('ascii'))
key = sha1.digest()[:16]
# Decrypt flag
ciphertext = bytes.fromhex(ciphertext)
iv = bytes.fromhex(iv)
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)
return plaintext
alice=s.recvline().decode()
alice=eval(alice[24:])
p=int(alice["p"],16)
g=int(alice["g"],16)
A=int(alice["A"],16)
# Finding a value
a = A * pow(g, -1, p)
bob=s.recvline().decode()
bob=eval(bob[22:])
B=int(bob["B"],16)
shared_secret = (a * B) % p
print(f"shared_secret:{shared_secret}")
aes_value=s.recvline().decode()
aes_value=eval(aes_value[24:])
print(aes_value)
iv=aes_value["iv"]
ciphertext=aes_value["encrypted"]
shared_secret = 781375771286523921682177536065612640494056443200091700967335945135067268298653748996108322420480852844610393628365669516985078401109539826459162980506903623821748901865082257455849415791691881709448350504513673033914283456716068601658189110168981077531264035904750408276794096099693262398008324260587814780721089721047526118391598923434827194939854735798577674170203256314333942485760352085036751905369610326318228197468392759214066509014997981777945415195218141
iv = "c396c71ca5eef7b2b03f359e30de5924"
ciphertext = "5fcf13b8d7e15aed2ac21bbe0ab732e9e75b221a4cba4c90cd63a25d0dda2461d24bc10e7dceffc0fe5a9b4ae00bfaa7"
print(decrypt_flag(shared_secret, iv, ciphertext))
Note: There was some issue with my script… manual decryption works fine.
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up