Writeups
  • ℹ️Infos
  • 🗓️2021
    • DvCTF (to join DaVinciCode)
      • Crypto
        • Baby RSA
        • Ressaye
        • Unbreakable encryption
      • Forensics
        • Broken Portrait
        • Russian Dolls
        • Sus USB
      • Misc
        • Jus de Flag
        • Welcome
      • OSINT
        • Absolutely Nuts
      • Progra
        • Snoop's Mission
      • Reverse
        • Baby Reverse
        • Basic Cracking
        • Code Pyn
      • Steganography
        • Colorful Code
        • Hurt Your Eyes
        • Orchestra of Flags
        • Tyger
      • Web
        • Have I Been Pwned
        • What's Up ?
  • 🗓️2022
    • DvCTF 2022
      • Crypto
        • Cwryptographic Owacle
        • Secure Or Not Secure
        • small weiner
      • Forensics
        • Very Bad Script
      • Misc
        • Data Leak
        • Going postal
        • The Hacker Man
      • OSINT
        • Elon Musk
        • Monkeey
        • Painting Spot
        • Welcome to the DaVinciCTF!
      • Pentest
        • DaVinci's Playlist : Part 1
        • DaVinci's Playlist : Part 2.5
        • DaVinci's Playlist : Part 2
      • Programming
        • Heaven's Gate
        • Sudoku
        • TicTacToe
      • Reverse
        • CryptoVault
        • Mine Game
        • Obfuscated
        • Peripheral Interface Controller XVI
      • Steganography
        • ICMP
        • The Arts of Details
        • Treasure
      • Warmup
        • EBG13
        • FrenchFlag
        • MP3
        • QmFzZTY0
        • RSA
        • Welcome
      • Web
        • CyberStreak v1.0
        • 🎵
    • picoCTF 2022
      • Challs WU
    • @HackDay - Qualifications
      • Crypto
        • Francis Bacon
        • Francs Maçons
        • Rotate-me!
        • Un message codé ?
      • Forensics
        • bad_timing_for_reversing
      • Hardware
        • Cubik'cipher
        • WebSDR
      • Reverse
        • Calling Conventions
        • Memory Investigation
      • Steganography
        • I can make pictures
        • J'ai perdu le flag :(
        • Pokémons
        • Un coup de maître
        • Un logo cachotier
      • Web
        • GIT!
        • Part. 1 - Uploads
        • Part. 2 - Old md5
        • Part. 3 - sudo python
    • 404CTF
      • Crypto
        • Un simple oracle [1/2]
        • Un simple oracle [2/2]
      • Misc
        • Je suis une théière
        • Pierre-papier-Hallebarde
        • GoGOLFplex
      • OSINT
        • À l'aube d'un échange
        • Collaborateur suspect
        • Equipement désuet
      • Reverse
        • Mot de passe ?
      • Steganography
        • La plume à la main
        • PNG : Un logo obèse [1/4]
        • PNG : Drôles de chimères [2/4]
        • Toujours obèse [3/4]
      • Web
        • Fiché JS
        • Le braquage
        • Du gâteau
        • En construction !
    • Operation Kernel
      • Crypto
        • Scytale
      • Forensics
        • Research Paper
        • Excel Confidential
      • Reverse
        • CryptoLocker
        • What_If_CryptoLocker
      • Social Engineering
        • Pour vivre secure vivons caché
        • Pour vivre secure vivons caché Part 2
      • Stegano
        • AudioSpectre
        • Datacenter
        • Takazume
      • WEB
        • Research paper blog
        • SQL Project 1
        • SQL Project 2
        • SQL Project 3
        • Tenue de soirée requise
  • 🗓️2023
    • 404CTF 2023
      • Résultats
      • Analyse forensique
        • Pêche au livre
        • Le Mystère du roman d'amour
        • Les Mystères du cluster de la Comtesse de Ségur [1/2]
        • Lettres volatiles
        • Note de bas de page
      • Cloud
        • Le Sot
        • Le Cluster de Madame Bovary
        • Harpagon et le magot
        • Les nuages menaçants 1/3
        • Les nuages menaçants 2/3
      • Cryptanalyse
        • Recette
        • ASCON Marchombre
      • Divers
        • Bienvenue
        • Exemple de connexion à distance
        • Discord
        • À vos plumes !
      • Exploitation de binaires
        • Je veux la lune !
      • Programmation
        • L'Inondation
        • Des mots, des mots, des mots
      • Radio-Fréquence
        • Navi
        • Avez-vous vu les cascades du hérisson ?
        • Le Plombier du câble
        • Ballistic Missile Submarine
      • Renseignement en sources ouvertes
        • Le Tour de France
        • Les OSINTables [1/3]
        • Un vol ?
        • L'âme d'un poète et le coeur d'une femme [1/4]
        • L'âme d'un poète et le coeur d'une femme [2/4]
        • L'âme d'un poète et le coeur d'une femme [3/4]
        • L'âme d'un poète et le coeur d'une femme [4/4]
      • Rétro Ingénierie
        • Le Divin Crackme
        • L'Inspiration en images
      • Sécurité Matérielle
        • Un courrier suspect
        • Un réveil difficile
      • Stéganographie
        • Odobenus Rosmarus
        • L'Œuvre
        • Les Félicitations
        • En Profondeur
        • Le Rouge et le vert, avec un soupçon de bleu
      • Web
        • Le Loup et le renard
        • L'Académie du détail
        • La Vie Française
        • Fuite en 1791
        • L'Épistolaire moderne
        • Chanson d'Inde
      • Web3
        • Art
        • L'Antiquaire, tête en l'air
  • 🗓️2025
    • 404CTF 2025
      • Résultats
      • Algorithmique Quantique
        • Machinerie quantique
        • Grover (1/2)
        • Grover (2/2)
      • Analyse forensique
        • USB 51
        • Forensic et Mat [1/2]
        • Apprenti Carver [1/2]
        • Dockerflag
        • Forensic et Mat [2/2]
        • Apprenti Carver [2/2]
        • Tape ton MDP
        • Toortik Triflexation [1/2]
        • Toortik Triflexation [2/2]
      • Cryptanalyse
        • Message lointain
        • Entretien galactique
        • R1R2
        • Saturn Cipher
        • Planètes anormales
        • Spacemark
        • You spin me round
        • Dérive dans l'espace
        • Lunette cosmico galactique
        • Jupiter Cipher
        • Courbe de Lancement
        • More Space
      • Divers
        • Bienvenue
        • Pix2Num
        • Politique de confidentialité
        • Space Traveller
        • Satellisation
        • Étoile binaire [2/2]
      • Exploitation de binaires
        • Gorfou en danger [1/3]
        • Gorfou en danger [2/3]
        • Gorfou en danger [3/3]
        • Spaaaaaaace
        • KerberINT Space Program
        • 22 bytes pour sauver l'univers
        • Bounty Machine
        • Space Odyssey
        • Solaris
        • Cosmic-Base
        • Kalaxy
        • Bokit
      • Intelligence Artificielle
        • Gorfoustral (1/3)
        • Gorfoustral (2/3)
        • Gorfoustral (3/3)
        • Du tatouage
      • Renseignement en sources ouvertes
        • L'addition est salée
        • Une mission inconnue
        • Earth Attack (0/2)
        • Un satellite qui vaut de l'or
        • Un peu de vacances
        • La ville en rose
        • Earth Attack (1/2)
        • La tête dans les étoiles
        • En eaux sombres
        • Earth Attack (2/2)
        • DPOsint
      • Réaliste
        • The LDAP Chronicles
        • Houston, we have a problem
        • Named Resolve
        • The AD Guardians
        • The GPO Mission
        • Ghost Membership
      • Rétro-Ingénierie
        • Cbizarre [1/2]
        • Cbizarre [2/2]
        • Reversconstrictor
        • 3x3cut3_m3
        • Inscription
        • Étoile binaire [1/2]
        • RFC 9452 bis: IP over Rockets with Quality of Service
      • Sécurité matérielle
        • Trop d'IQ
        • Space Radio
        • R16D4
        • Comment est votre température ?
        • Code Radiospatial n°1
        • Unidentified Serial Bus [1/2]
        • Unidentified Serial Bus [2/2]
      • Sécurité Web
        • Cheese Chess
        • Rainbow Rocket
        • Fire Server
        • Sideral Noise
        • Space Fleet Command
Powered by GitBook
On this page

Was this helpful?

  1. 2025
  2. 404CTF 2025
  3. Cryptanalyse

R1R2

PreviousEntretien galactiqueNextSaturn Cipher

Last updated 19 days ago

Was this helpful?

Catégorie: Cryptanalyse - Difficulté: Facile

Description:

Solution:

Ici il s'agit d'un chall assez simple où le flag a été chiffré avec la fonction encrypt_password :

Le but ici est de créer une fonction decrypt_password afin de lui donner notre flag et retrouver l'original. Avec les infos recueillies dans la fonction encrypt, le script inverse est assez simple à faire (avec un coup de pouce de ChatGPT si on veut aller plus vite) :

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import random as rd
from math import isqrt

# ----------------------------------------------------------------------
#  Construction d’un entier 1023 bits (fonction ci originale)
# ----------------------------------------------------------------------
def ci(z: int, info_1: int, info_2: int) -> int:
    assert info_1.bit_length() <= 511 and info_2.bit_length() <= 511
    return ((z & 1) << 1022) | ((info_1 & ((1 << 511) - 1)) << 511) | (info_2 & ((1 << 511) - 1))


# ----------------------------------------------------------------------
#  Chiffrement (identique au code fourni dans l’énoncé)
# ----------------------------------------------------------------------
def encrypt_password(password: str) -> bytes:
    a = b''
    b, c = password[::2], password[1::2]
    b = int.from_bytes(b.encode(), 'big')
    c = int.from_bytes(c.encode(), 'big')
    assert b > c
    d = b + c
    e = b * c
    r = []
    for _ in range(3):
        x = rd.randint(0, 2 ** b.bit_length())
        y = x * x - d * x + e
        z = y < 0
        t = ci(z, abs(y), x)
        r.append(t)
    for i in range(3):
        a += r[i].to_bytes((r[i].bit_length() + 7) // 8, 'big').rjust(128, b'\x00')
    return a


# ----------------------------------------------------------------------
#  Déchiffrement – partie demandée
# ----------------------------------------------------------------------
def _decode_block(block: bytes) -> tuple[int, int]:
    """Extrait (x, y) depuis un bloc de 128 octets issu de ci(...)."""
    if len(block) != 128:
        raise ValueError("Un bloc doit faire exactement 128 octets.")
    t = int.from_bytes(block, 'big')
    sign = (t >> 1022) & 1
    mask = (1 << 511) - 1
    abs_y = (t >> 511) & mask
    x = t & mask
    y = -abs_y if sign else abs_y
    return x, y


def decrypt_password(cipher: bytes) -> str:
    """
    Inverse encrypt_password.  Attend 384 octets (3 blocs de 128) et rend
    la chaîne de caractères du mot de passe en clair.
    """
    if len(cipher) != 3 * 128:
        raise ValueError("Le chiffré doit faire 384 octets (3 blocs).")

    # 1) extraction des triplets (xᵢ, yᵢ)
    blocks = [cipher[i * 128:(i + 1) * 128] for i in range(3)]
    xs, ys = zip(*(_decode_block(b) for b in blocks))
    x1, x2, x3 = xs
    y1, y2, y3 = ys

    # 2) résolution linéaire pour d et e :  y = x² − d·x + e
    num = (y1 - x1 * x1) - (y2 - x2 * x2)
    den = x2 - x1
    if den == 0 or num % den:
        raise ValueError("Blocs incohérents (division impossible).")
    d = num // den
    e = y1 - x1 * x1 + d * x1

    # 3) contrôle avec le 3ᵉ bloc
    if y3 != x3 * x3 - d * x3 + e:
        raise ValueError("Le troisième bloc ne colle pas : données corrompues ?")

    # 4) racines de t² − d·t + e = 0  →  b et c
    delta = d * d - 4 * e
    sqrt_delta = isqrt(delta)
    if sqrt_delta * sqrt_delta != delta:
        raise ValueError("Δ n'est pas un carré parfait – impossible de factoriser.")
    b = (d + sqrt_delta) // 2
    c = (d - sqrt_delta) // 2
    if b < c:                       # la convention imposait b > c
        b, c = c, b

    # 5) conversion int → bytes → str
    def int_to_bytes(n: int) -> bytes:
        return b'\x00' if n == 0 else n.to_bytes((n.bit_length() + 7) // 8, 'big')

    b_str = int_to_bytes(b).decode()
    c_str = int_to_bytes(c).decode()

    # 6) ré-entrelacement des caractères (pairs / impairs)
    pw_chars: list[str] = []
    for i in range(max(len(b_str), len(c_str))):
        if i < len(b_str):
            pw_chars.append(b_str[i])
        if i < len(c_str):
            pw_chars.append(c_str[i])
    return ''.join(pw_chars)


# ----------------------------------------------------------------------
#  Données fournies + démonstration
# ----------------------------------------------------------------------
ENCRYPTED_FLAG_HEX = (
    "40f1b6e577b2bb6aa703387a15d2738ad50c795972342bdbb4b32946bcf7b72f"
    "bbdfb41884883df6589bf0e1e73a01f4f0d13a60146ac87c146de846bb98407d8"
    "0000000000000000000000000000000000000000000000000000000000000000"
    "c4df9ca82064c5b97e3e5013732439d6139195456b94e581b7a22f1510f926c4"
    "117ca4ed6a10c5d37b5d400dca883d001564774dbbce5c198c5ff83fe7af851f"
    "c3820a17947e71689812f6113dd3893250a14320a8f49c46bde754a188efd300"
    "0000000000000000000000000000000000000000000000000000000000000000"
    "f6336ee243e9a18cd74b182ff23f87f8bbac8912b57cd3ab25faffcaa18ea394"
    "0d748f2696de5597ec5df6d12826fc2b37d8e926af7a39afe74cb0950460da1a"
    "33112d89029e1a9334ea4c19d36cab027d4b360f240139de4ebd58ebfb056818"
    "0000000000000000000000000000000000000000000000000000000000000002"
    "9e03851f31bd96e478b63347dc9a369a5d0569dc00ffe07cc3ad2d8293a9bf0"
)

if __name__ == "__main__":
    encrypted_flag = bytes.fromhex(ENCRYPTED_FLAG_HEX)
    flag_clear = decrypt_password(encrypted_flag)
    print(flag_clear)

Et voilà le résultat :

🚩FLAG

404CTF{B1p_bOuP_B6M!aU70d35crUt1oN_pR0g6aM_aC7Iv8t3d!321-B0om!}

🗓️
2KB
encrypt.py