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 2 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