Klassik Shifrlar
Caesar, Vigenere, Affine, Rail Fence — tarix boylab qo'llanilgan klassik shifrlash usullari, ularning matematik asoslari va Python bilan qanday buzish mumkinligi.
1 Klassik Shifrlarga Kirish
Klassik vs Zamonaviy
Klassik shifrlar kompyuterdan oldin qo'lda yoki oddiy mexanik qurilmalar bilan ishlatilar edi. Ular bugun kriptografik jihatdan xavfli — lekin CTF musobaqalarida va kriptografiya asoslarini o'rganishda juda muhim.
Nima uchun o'rganamiz?
- CTF musobaqalarida eng ko'p uchraydigan shifr turi
- Zamonaviy kriptografiya tushunchalarini tushuntiradi
- Chastota tahlilini o'rgatadi
- Matematik asoslarni (mod arifmetika) ko'rsatadi
- Kriptotahlil (kriptoanaliz) asoslari
2 Caesar Shifri (Siljish Shifri)
Matematik ta'rif
Shifrlash (Encryption):
Deshifrlash (Decryption):
ROT13 (k=13, o'zi-o'ziga teskari):
x = harf raqami (A=0, B=1, ..., Z=25), k = siljish (kalit)
Qanday buziladi?
Caesar shifri juda zaif — faqat 25 ta kalitni sinab ko'rish yetarli (brute force).
Python Implementatsiya
def caesar_encrypt(text, shift):
result = []
for ch in text.upper():
if ch.isalpha():
result.append(chr((ord(ch) - ord('A') + shift) % 26 + ord('A')))
else:
result.append(ch)
return ''.join(result)
def caesar_decrypt(text, shift):
return caesar_encrypt(text, -shift)
def caesar_brute_force(ciphertext):
# Barcha 25 ta variantni ko'rsatish
for k in range(1, 26):
print(f"k={k:2d}: {caesar_decrypt(ciphertext, k)}")
# Misol
cipher = caesar_encrypt("HELLO WORLD", 13)
print(f"ROT13: {cipher}") # URYYB JBEYQ
print(caesar_decrypt(cipher, 13)) # HELLO WORLD
# CTF: shifrlangan matnni buzish
caesar_brute_force("KHOOR ZRUOG")
3 Affine Shifri
Affine shifri Caesar shifrini umumlashtiradi — siljish (shift) o'rniga ko'paytirish ham qo'shiladi.
Kalit juft: (a, b) — bu ko'proq imkoniyat beradi, lekin baribir zaif.
Formula
Shifrlash:
E(x) = (a·x + b) mod 26
Deshifrlash:
D(x) = a⁻¹·(x - b) mod 26
Shart: GCD(a, 26) = 1
a ∈ {1,3,5,7,9,11,15,17,19,21,23,25}
b ∈ {0, 1, ..., 25}
Jami kalit soni: 12 × 26 = 312
Misol: a=5, b=8
from math import gcd
def mod_inverse(a, m):
if gcd(a, m) != 1:
raise ValueError(f"GCD({a},{m})≠1, teskari yo'q")
for x in range(1, m):
if (a * x) % m == 1:
return x
def affine_encrypt(text, a, b):
assert gcd(a, 26) == 1, "a va 26 o'zaro tub bo'lishi kerak"
result = []
for ch in text.upper():
if ch.isalpha():
x = ord(ch) - ord('A')
result.append(chr((a * x + b) % 26 + ord('A')))
else:
result.append(ch)
return ''.join(result)
def affine_decrypt(text, a, b):
a_inv = mod_inverse(a, 26)
result = []
for ch in text.upper():
if ch.isalpha():
x = ord(ch) - ord('A')
result.append(chr(a_inv * (x - b) % 26 + ord('A')))
else:
result.append(ch)
return ''.join(result)
# CTF brute-force
def affine_brute(ciphertext):
valid_a = [x for x in range(1, 26) if gcd(x, 26) == 1]
for a in valid_a:
for b in range(26):
plain = affine_decrypt(ciphertext, a, b)
if "THE" in plain or "CTF" in plain:
print(f"a={a}, b={b}: {plain}")
4 Vigenere Shifri (Polyalphabetik)
Tarix: 1553-yilda Giovan Battista Bellaso tomonidan ixtiro qilingan, keyinchalik Blaise de Vigenere nomi bilan mashhur bo'lgan. "Le Chiffre indéchiffrable" (buzib bo'lmaydigan shifr) deb atalgan — lekin 1863-yilda Kasiski uni buzdi!
Vigenere Qanday Ishlaydi?
Kasiski Testi (Buzish usuli)
Kalit uzunligini topish uchun shifr matnidagi takrorlanuvchi 3+ harfli ketma-ketliklar orasidagi masofalar hisoblanadi. Ularning GCD'si kalit uzunligiga teng.
Index of Coincidence (IC)
IC formulasi kalit uzunligini aniqlashda yordam beradi:
IC = Σ fᵢ(fᵢ-1) / N(N-1)
fᵢ = i-harfning chastotasi, N = umumiy uzunlik
def vigenere_encrypt(text, key):
text = text.upper()
key = key.upper()
result, ki = [], 0
for ch in text:
if ch.isalpha():
shift = ord(key[ki % len(key)]) - ord('A')
result.append(chr((ord(ch) - ord('A') + shift) % 26 + ord('A')))
ki += 1
else:
result.append(ch)
return ''.join(result)
def vigenere_decrypt(text, key):
text = text.upper()
key = key.upper()
result, ki = [], 0
for ch in text:
if ch.isalpha():
shift = ord(key[ki % len(key)]) - ord('A')
result.append(chr((ord(ch) - ord('A') - shift + 26) % 26 + ord('A')))
ki += 1
else:
result.append(ch)
return ''.join(result)
def kasiski_test(ciphertext, min_len=3):
# Takrorlanuvchi ketma-ketliklar va masofalar
from math import gcd
from functools import reduce
text = ciphertext.upper().replace(' ', '')
distances = []
for i in range(len(text) - min_len):
seq = text[i:i+min_len]
j = text.find(seq, i + min_len)
if j != -1:
distances.append(j - i)
if distances:
common_gcd = reduce(gcd, distances)
print(f"Masofalar: {distances}")
print(f"GCD → ehtimol kalit uzunligi: {common_gcd}")
# Misol
c = vigenere_encrypt("ATTACK AT DAWN", "KEY")
print(c) # KXIASK KX NGQR
print(vigenere_decrypt(c, "KEY")) # ATTACK AT DAWN
5 Chastota Tahlili (Frequency Analysis)
Ingliz tilida har bir harfning taxminiy chastotasi ma'lum. Substitution shifrlarda harflar almashinadi, lekin chastotalar saqlanib qoladi. Bu — barcha oddiy substitution shifrlarni buzishning asosiy kaliti.
ETAOIN SHRDLU
Ingliz tilidagi eng ko'p ishlatiladigan harflar tartibi:
CTF'da shifrlangan matnning eng ko'p harfi E'ga mos kelishi ehtimoli yuqori
Python: Chastota Tahlili
from collections import Counter
def freq_analysis(text):
text = text.upper()
letters = [c for c in text if c.isalpha()]
total = len(letters)
counts = Counter(letters)
sorted_by_freq = counts.most_common()
print("Harf | Son | %")
for letter, count in sorted_by_freq:
pct = count / total * 100
bar = '█' * int(pct)
print(f" {letter} | {count:3d} | {pct:.1f}% {bar}")
def simple_substitution_crack(cipher, mapping):
# mapping = {'X': 'E', 'K': 'T', ...}
result = []
for ch in cipher.upper():
result.append(mapping.get(ch, ch.lower()))
return ''.join(result)
6 Oddiy Substitution Shifri
Har bir harf boshqa bir harf bilan almashtiriladi — lekin tartibsiz (Caesar kabi sistemali emas). 26! ≈ 4×10²⁶ ta mumkin bo'lgan kalit bor, lekin chastota tahlili bilan yechiladi.
Kalit misoli (alifbo → shifr alifbo):
7 Rail Fence Shifri (Transposition)
Rail Fence — transposition (ko'chirish) shifri. Harflar almashtirilmaydi, faqat joyi o'zgartiriladi. Matn diagonal "to'lqin" shaklida yoziladi, keyin qator-qator o'qiladi.
def rail_fence_encrypt(text, rails):
fence = [[] for _ in range(rails)]
rail, direction = 0, 1
for char in text:
fence[rail].append(char)
if rail == 0: direction = 1
elif rail == rails - 1: direction = -1
rail += direction
return ''.join(''.join(r) for r in fence)
def rail_fence_decrypt(cipher, rails):
n = len(cipher)
pattern = [0] * n
rail, direction = 0, 1
for i in range(n):
pattern[i] = rail
if rail == 0: direction = 1
elif rail == rails - 1: direction = -1
rail += direction
indices = sorted(range(n), key=lambda i: (pattern[i], i))
result = [''] * n
for idx, char in zip(indices, cipher):
result[idx] = char
return ''.join(result)
# Misol
enc = rail_fence_encrypt("HELLOWORLD", 3)
print(enc) # HOLELWRDLO → HLODEROLWL
print(rail_fence_decrypt(enc, 3)) # HELLOWORLD
8 CTF'da Klassik Shifr Masalalarini Yechish
Belgi tanish algoritmi
Foydali Vositalar
Umumiy CTF naqshlari
# CTF uchun foydali funksiyalar to'plami
import string
def rot13(text):
result = []
for c in text:
if c.isalpha():
base = ord('A') if c.isupper() else ord('a')
result.append(chr((ord(c) - base + 13) % 26 + base))
else:
result.append(c)
return ''.join(result)
def atbash(text):
result = []
for c in text:
if c.isalpha():
base = ord('A') if c.isupper() else ord('a')
result.append(chr(base + 25 - (ord(c) - base)))
else:
result.append(c)
return ''.join(result)
def index_of_coincidence(text):
text = [c for c in text.upper() if c.isalpha()]
N = len(text)
if N < 2: return 0
counts = Counter(text)
ic = sum(f * (f - 1) for f in counts.values()) / (N * (N - 1))
return ic
# IC interpretatsiya:
# 0.065 → Ingliz matni (monoalphabetik)
# 0.038 → Tasodifiy (polyalphabetik, Vigenere)
# Oraliqda → Ehtimol kalit uzunligiga qarab guruhlash kerak
Bilimni Sinash
1. Caesar shifri bilan k=7 da "HELLO" ni shifrlasangiz natija nima?
2. Affine shifri uchun qaysi a qiymatlari ruxsat etiladi (mod 26)?
3. IC ≈ 0.065 bo'lsa, bu nimani anglatadi?