$npx -y skills add Prohao42/aimy-skill --skill classical-cipher-analysisClassical cipher analysis playbook. Use when encountering substitution ciphers, Vigenere, transposition, XOR, or encoded text in CTF challenges that requires frequency analysis, Kasiski examination, or known-plaintext cryptanalysis.
| 1 | # SKILL: Classical Cipher Analysis — Expert Cryptanalysis Playbook |
| 2 | |
| 3 | > **AI LOAD INSTRUCTION**: Expert classical cipher identification and breaking techniques for CTF. Covers cipher identification methodology (frequency analysis, IC, Kasiski), monoalphabetic substitution, Caesar/ROT, Vigenere, Enigma, affine, Hill, transposition ciphers, Bacon/Polybius/Playfair, and XOR ciphers. Base models often skip the identification step and jump to the wrong cipher type, or fail to recognize encoded (base64/hex) ciphertext that needs decoding before analysis. |
| 4 | |
| 5 | ## 0. RELATED ROUTING |
| 6 | |
| 7 | - [symmetric-cipher-attacks](../symmetric-cipher-attacks/SKILL.md) when dealing with modern symmetric ciphers (AES/DES) rather than classical |
| 8 | - [hash-attack-techniques](../hash-attack-techniques/SKILL.md) when the challenge involves hash-based constructions |
| 9 | - [lattice-crypto-attacks](../lattice-crypto-attacks/SKILL.md) when knapsack-based ciphers are encountered |
| 10 | |
| 11 | ### Quick identification guide |
| 12 | |
| 13 | | Observation | Likely Cipher | First Action | |
| 14 | |---|---|---| |
| 15 | | All uppercase letters, uneven frequency | Monoalphabetic substitution | Frequency analysis | |
| 16 | | All uppercase, flat frequency distribution | Polyalphabetic (Vigenere) | IC + Kasiski | |
| 17 | | Only A-Z shifted uniformly | Caesar/ROT | Brute force 25 shifts | |
| 18 | | Base64 alphabet (A-Za-z0-9+/=) | Base64 encoded (decode first) | Base64 decode | |
| 19 | | Hex string (0-9a-f) | Hex encoded (decode first) | Hex decode | |
| 20 | | Binary (0s and 1s) | Binary encoded | Convert to ASCII | |
| 21 | | Dots and dashes | Morse code | Morse decode | |
| 22 | | Raised/normal text pattern | Bacon cipher | Map to A/B, decode | |
| 23 | | 2-digit number pairs (11-55) | Polybius square | Grid lookup | |
| 24 | | Text appears scrambled (right letters, wrong order) | Transposition | Anagram analysis | |
| 25 | | Non-printable bytes XOR-like | XOR cipher | Single/repeating key XOR analysis | |
| 26 | |
| 27 | --- |
| 28 | |
| 29 | ## 1. CIPHER IDENTIFICATION METHODOLOGY |
| 30 | |
| 31 | ### 1.1 Step 1: Character Set Analysis |
| 32 | |
| 33 | ```python |
| 34 | def analyze_charset(ciphertext): |
| 35 | """Identify encoding/cipher by character set.""" |
| 36 | chars = set(ciphertext.strip()) |
| 37 | |
| 38 | if chars <= set('01 \n'): |
| 39 | return "Binary encoding" |
| 40 | if chars <= set('.-/ \n'): |
| 41 | return "Morse code" |
| 42 | if chars <= set('0123456789abcdef \n'): |
| 43 | return "Hex encoding" |
| 44 | if chars <= set('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n'): |
| 45 | if '=' in ciphertext or len(ciphertext) % 4 == 0: |
| 46 | return "Base64 encoding" |
| 47 | if chars <= set('ABCDEFGHIJKLMNOPQRSTUVWXYZ \n'): |
| 48 | return "Uppercase only — classical cipher" |
| 49 | if all(c in '12345' for c in ciphertext.replace(' ', '').replace('\n', '')): |
| 50 | return "Polybius square (digits 1-5)" |
| 51 | |
| 52 | return "Mixed charset — needs further analysis" |
| 53 | ``` |
| 54 | |
| 55 | ### 1.2 Step 2: Frequency Analysis |
| 56 | |
| 57 | ```python |
| 58 | from collections import Counter |
| 59 | |
| 60 | def frequency_analysis(text): |
| 61 | """Compute letter frequency distribution.""" |
| 62 | text = text.upper() |
| 63 | letters = [c for c in text if c.isalpha()] |
| 64 | total = len(letters) |
| 65 | freq = Counter(letters) |
| 66 | |
| 67 | print("Letter frequencies:") |
| 68 | for letter, count in freq.most_common(): |
| 69 | pct = count / total * 100 |
| 70 | bar = '#' * int(pct) |
| 71 | print(f" {letter}: {pct:5.1f}% {bar}") |
| 72 | |
| 73 | return freq |
| 74 | |
| 75 | # English letter frequency (for comparison): |
| 76 | # E T A O I N S H R D L C U M W F G Y P B V K J X Q Z |
| 77 | # 12.7 9.1 8.2 7.5 7.0 6.7 6.3 6.1 6.0 4.3 4.0 2.8 ... |
| 78 | ``` |
| 79 | |
| 80 | ### 1.3 Step 3: Index of Coincidence (IC) |
| 81 | |
| 82 | ```python |
| 83 | def index_of_coincidence(text): |
| 84 | """ |
| 85 | IC ≈ 0.065 → English / monoalphabetic substitution |
| 86 | IC ≈ 0.038 → random / polyalphabetic cipher |
| 87 | """ |
| 88 | text = [c for c in text.upper() if c.isalpha()] |
| 89 | N = len(text) |
| 90 | freq = Counter(text) |
| 91 | |
| 92 | ic = sum(f * (f - 1) for f in freq.values()) / (N * (N - 1)) |
| 93 | return ic |
| 94 | |
| 95 | # Interpretation: |
| 96 | # IC > 0.060 → monoalphabetic (Caesar, simple substitution, Playfair) |
| 97 | # IC ≈ 0.045-0.055 → polyalphabetic with short key (Vigenere key < 10) |
| 98 | # IC ≈ 0.038-0.042 → polyalphabetic with long key or random |
| 99 | ``` |
| 100 | |
| 101 | ### 1.4 Step 4: Kasiski Examination (for Polyalphabetic) |
| 102 | |
| 103 | ```python |
| 104 | from math import gcd |
| 105 | from functools import reduce |
| 106 | |
| 107 | def kasiski(ciphertext, min_len=3): |
| 108 | """Find repeated sequences and their distances → key length.""" |
| 109 | text = ''.join(c for c in ciphertext.upper() if c.isalpha()) |
| 110 | distances = [] |
| 111 | |
| 112 | for length in range(min_len, min(20, len(text) // 3)): |
| 113 | for i in range(len(text) - length): |
| 114 | seq = text[i:i+length] |
| 115 | j = text.find(seq, i + 1) |
| 116 | while j != -1: |
| 117 | distances.append(j - i) |
| 118 | j = text.find(seq, j + 1) |
| 119 | |
| 120 | if not distances: |
| 121 | return None |
| 122 | |
| 123 | # Key length is likely GCD of common distances |
| 124 | common_gcds = |