from Crypto.Util.number import bytes_to_long, long_to_bytes, inverse, isPrime

def Task1():
    p = 991
    g = 209
    print(inverse(g, p))

def is_generator(k, p):
    for n in range(2, p):
        if pow(k, n, p) == k:
            return False
    return True

def Task2():
    p = 28151
    k = 1
    while True:
        if is_generator(k, p):
            print(k)
            break;
        k += 1

def Task3():
    g = 2
    p = 2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919
    a = 972107443837033796245864316200458246846904598488981605856765890478853088246897345487328491037710219222038930943365848626194109830309179393018216763327572120124760140018038673999837643377590434413866611132403979547150659053897355593394492586978400044375465657296027592948349589216415363722668361328689588996541370097559090335137676411595949335857341797148926151694299575970292809805314431447043469447485957669949989090202320234337890323293401862304986599884732815

    print(pow(g, a, p))

def Task4():
    g = 2
    p = 2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919
    A = 70249943217595468278554541264975482909289174351516133994495821400710625291840101960595720462672604202133493023241393916394629829526272643847352371534839862030410331485087487331809285533195024369287293217083414424096866925845838641840923193480821332056735592483730921055532222505605661664236182285229504265881752580410194731633895345823963910901731715743835775619780738974844840425579683385344491015955892106904647602049559477279345982530488299847663103078045601
    b = 12019233252903990344598522535774963020395770409445296724034378433497976840167805970589960962221948290951873387728102115996831454482299243226839490999713763440412177965861508773420532266484619126710566414914227560103715336696193210379850575047730388378348266180934946139100479831339835896583443691529372703954589071507717917136906770122077739814262298488662138085608736103418601750861698417340264213867753834679359191427098195887112064503104510489610448294420720
    B = 518386956790041579928056815914221837599234551655144585133414727838977145777213383018096662516814302583841858901021822273505120728451788412967971809038854090670743265187138208169355155411883063541881209288967735684152473260687799664130956969450297407027926009182761627800181901721840557870828019840218548188487260441829333603432714023447029942863076979487889569452186257333512355724725941390498966546682790608125613166744820307691068563387354936732643569654017172

    print(pow(A, b, p))

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import hashlib


def is_pkcs7_padded(message):
    padding = message[-message[-1]:]
    return all(padding[i] == len(padding) for i in range(0, len(padding)))


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)

    if is_pkcs7_padded(plaintext):
        return unpad(plaintext, 16).decode('ascii')
    else:
        return plaintext.decode('ascii')

def Task5():
    g = 2
    p = 2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919
    A = 112218739139542908880564359534373424013016249772931962692237907571990334483528877513809272625610512061159061737608547288558662879685086684299624481742865016924065000555267977830144740364467977206555914781236397216033805882207640219686011643468275165718132888489024688846101943642459655423609111976363316080620471928236879737944217503462265615774774318986375878440978819238346077908864116156831874695817477772477121232820827728424890845769152726027520772901423784
    b = 197395083814907028991785772714920885908249341925650951555219049411298436217190605190824934787336279228785809783531814507661385111220639329358048196339626065676869119737979175531770768861808581110311903548567424039264485661330995221907803300824165469977099494284722831845653985392791480264712091293580274947132480402319812110462641143884577706335859190668240694680261160210609506891842793868297672619625924001403035676872189455767944077542198064499486164431451944
    B = 1241972460522075344783337556660700537760331108332735677863862813666578639518899293226399921252049655031563612905395145236854443334774555982204857895716383215705498970395379526698761468932147200650513626028263449605755661189525521343142979265044068409405667549241125597387173006460145379759986272191990675988873894208956851773331039747840312455221354589910726982819203421992729738296452820365553759182547255998984882158393688119629609067647494762616719047466973581


    shared_secret = pow(A, b, p)
    iv = "737561146ff8194f45290f5766ed6aba"
    ciphertext = "39c99bf2f0c14678d6a5416faef954b5893c316fc3c48622ba1fd6a9fe85f3dc72a29c394cf4bc8aff6a7b21cae8e12c"

    print(decrypt_flag(shared_secret, iv, ciphertext))

from pwn import *
import json
import codecs
import hashlib
from Crypto.Cipher import AES

def Task6():
    r = remote('socket.cryptohack.org', 13371, level = 'debug')

    r.readuntil(": ")
    line = json.loads(r.readline().strip().decode())

    p = int(line["p"], 16)
    g = int(line["g"], 16)
    A = int(line["A"], 16)

    payload = json.dumps({"p":hex(p),"g":hex(g),"A":hex(A)})
    r.sendlineafter(": ", payload)

    r.readuntil(": ")
    line = json.loads(r.readline().strip().decode())
    B = int(line['B'], 16)

    payload = json.dumps({"B":hex(1)})
    #
    # s = B^a mod p
    #
    # B==1 => B^n == 1 => s = 1
    #
    r.sendlineafter(": ", payload)

    r.readuntil(": ")
    line = json.loads(r.readline().strip().decode())

    ciphertext = line['encrypted_flag']
    iv = line['iv']
    shared_secret = 1
    print(decrypt_flag(shared_secret, iv, ciphertext))

    r.close()

def Task7():
    
    #Intercepted from Alice: {"supported": ["DH1536", "DH1024", "DH512", "DH256", "DH128", "DH64"]}
    #Send to Bob: {"supported": ["DH64"]}
    #Intercepted from Bob: {"chosen": "DH64"}
    #Send to Alice: {"chosen": "DH64"}
    #Intercepted from Alice: {"p": "0xde26ab651b92a129", "g": "0x2", "A": "0x9bf1d8558e7b6768"}
    #Intercepted from Bob: {"B": "0x97e38f7cb7602367"}
    #Intercepted from Alice: {"iv": "427517171ebdc1eb2676462b29c82cab", "encrypted_flag": "a515316381f3af3b965172c99c8a717d5972f2965fb0929245ce42874c15b1b0"}
    
    
    p = "0xde26ab651b92a129"
    g = "0x2"
    A = "0x9bf1d8558e7b6768"
    B = "0x97e38f7cb7602367"
    iv =  "427517171ebdc1eb2676462b29c82cab"
    ciphertext = "a515316381f3af3b965172c99c8a717d5972f2965fb0929245ce42874c15b1b0"

    p = int(p, 16)
    g = int(g, 16)
    A = int(A, 16)
    B = int(B, 16)

    #https://www.alpertron.com.ar/DILOG.HTM
	#Base g = 2
	#Power A = 11237000407240370024
	#Modulus p = 16007670376277647657
    a = 1947894555882764334
    shared_secret = pow(B, a, p)
    print(decrypt_flag(shared_secret, iv, ciphertext))

Task6()
