RSAying
XESXOR9/10/20262 min read
#crypto#custom#easy#key-recovery-from-ciphertext-p#known-plaintext-attack-on-vige
RSAying
Platform: spbctf | Category: Crypto | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2026-03-09 | Status: Solved Techniques: Key recovery from ciphertext-plaintext pairs, Known plaintext attack on Vigenere cipher
Summary
Task: Vigenere-encrypted Wikipedia article about RSA. Solution: Known plaintext attack using B.E.I.=R.S.A. mapping to recover the key MISCTRACK.
RSAying — cryptokids20
Description
Vigenere-encrypted Wikipedia article about RSA cryptography.
Analysis
- Task name "RSAying" hints that the content is related to RSA
- Ciphertext looks like an encrypted article (structure, punctuation preserved)
- The ciphertext contains "B.E.I." — this is encrypted "R.S.A." (known plaintext)
- Vigenere is a polyalphabetic cipher with a repeating key
Solution
-
Identifying the cipher type: Text structure and repeating patterns indicate Vigenere
-
Known Plaintext Attack:
- Known: "B.E.I." in ciphertext = "R.S.A." in plaintext
- Calculate shifts: B→R (shift 16=P), E→S (shift 14=N), I→A (shift 8=I)
- But this is only 3 characters, need more context
-
Key recovery:
- Using several known text fragments about RSA
- Key turned out to be: MISCTRACK (9 characters)
-
Decryption:
- Apply Vigenere decryption with key MISCTRACK
- Get the full article text about RSA history
python read-only • copy allowed#!/usr/bin/env python3 """ Vigenere Known Plaintext Attack """ def vigenere_decrypt(ciphertext, key): """Decrypt Vigenere cipher""" result = [] key_len = len(key) key_idx = 0 for c in ciphertext: if c.isalpha(): shift = ord(key[key_idx % key_len].upper()) - ord('A') if c.isupper(): result.append(chr((ord(c) - ord('A') - shift) % 26 + ord('A'))) else: result.append(chr((ord(c) - ord('a') - shift) % 26 + ord('a'))) key_idx += 1 else: result.append(c) return ''.join(result) def find_key_from_known_plaintext(ciphertext, plaintext): """Recover key from known plaintext-ciphertext pair""" key = [] for c, p in zip(ciphertext, plaintext): if c.isalpha() and p.isalpha(): shift = (ord(c.upper()) - ord(p.upper())) % 26 key.append(chr(shift + ord('A'))) return ''.join(key) # Known: B.E.I. -> R.S.A. # Partial key recovery cipher_fragment = "BEI" plain_fragment = "RSA" partial_key = find_key_from_known_plaintext(cipher_fragment, plain_fragment) print(f"Partial key from B.E.I.->R.S.A.: {partial_key}") # Full key (found through analysis) key = "MISCTRACK" # Decrypt ciphertext = "..." # Full ciphertext here plaintext = vigenere_decrypt(ciphertext, key) print(plaintext)