Caesar Cipher
A substitution cipher where each letter is shifted by a fixed number of positions in the alphabet.
How it works:
Formula: E(x) = (x + n) mod 26 for encryption
Example: With shift=3, 'A' becomes 'D', 'B' becomes 'E', etc.
Security Demonstration:
Vigenère Cipher
A polyalphabetic substitution cipher using a keyword to vary the Caesar shift.
How it works:
Formula: E(i) = (P(i) + K(i mod m)) mod 26
Key repeating: The key repeats to match the text length
Security Demonstration:
Security Analysis & Cryptanalysis
Frequency Analysis
Analyze letter frequencies in your text to identify patterns
Vulnerability Comparison
| Algorithm | Key Space | Security Level | Main Vulnerabilities |
|---|---|---|---|
| Caesar | 25 | Very Low | Brute Force, Frequency Analysis |
| Vigenère | 26^m | Low-Medium | Kasiski, Index of Coincidence |
Attack Methods
Brute Force Attack
Effectiveness: 100% against Caesar (25 keys), exponential time for Vigenère
Frequency Analysis
Most common letters: E(12.7%), T(9.1%), A(8.2%), O(7.5%)
Kasiski Examination
Finds repeated sequences to determine Vigenère key length
Implementation Code
Well-commented implementations for educational purposes
/**
* Caesar Cipher Implementation
* Simple substitution cipher with fixed shift
* Time Complexity: O(n) where n is text length
*/
function caesarCipher(text, shift, decrypt = false) {
// Adjust shift for decryption
if (decrypt) shift = 26 - shift;
return text.split('').map(char => {
// Only process alphabetic characters
if (/[A-Za-z]/.test(char)) {
// Get character code and normalize to 0-25
const code = char.toUpperCase().charCodeAt(0) - 65;
// Apply Caesar shift with modulo wrap-around
const shifted = (code + shift) % 26;
// Convert back to character, preserving original case
const newChar = String.fromCharCode(shifted + 65);
return char === char.toLowerCase() ? newChar.toLowerCase() : newChar;
}
// Return non-alphabetic characters unchanged
return char;
}).join('');
}
// Brute force attack simulation
function bruteForceCaesar(ciphertext) {
const results = [];
// Try all possible shifts (1-25)
for (let shift = 1; shift <= 25; shift++) {
const decrypted = caesarCipher(ciphertext, shift, true);
results.push({ shift, text: decrypted });
}
return results;
}
/**
* Vigenère Cipher Implementation
* Polyalphabetic substitution using keyword
* Time Complexity: O(n) where n is text length
*/
function vigenereCipher(text, key, decrypt = false) {
// Normalize key to uppercase
key = key.toUpperCase().replace(/[^A-Z]/g, '');
if (key.length === 0) return text;
let keyIndex = 0;
return text.split('').map(char => {
// Only process alphabetic characters
if (/[A-Za-z]/.test(char)) {
const textCode = char.toUpperCase().charCodeAt(0) - 65;
const keyCode = key[keyIndex % key.length].charCodeAt(0) - 65;
// Apply Vigenère formula
let shifted;
if (decrypt) {
shifted = (textCode - keyCode + 26) % 26;
} else {
shifted = (textCode + keyCode) % 26;
}
// Increment key position for alphabetic chars only
keyIndex++;
// Convert back to character, preserving case
const newChar = String.fromCharCode(shifted + 65);
return char === char.toLowerCase() ? newChar.toLowerCase() : newChar;
}
return char;
}).join('');
}
// Key length analysis using Index of Coincidence
function indexOfCoincidence(text) {
const counts = {};
let total = 0;
// Count letter frequencies
for (const char of text.toUpperCase()) {
if (/[A-Z]/.test(char)) {
counts[char] = (counts[char] || 0) + 1;
total++;
}
}
// Calculate IC = Σ(ni * (ni-1)) / (N * (N-1))
let sum = 0;
for (const count of Object.values(counts)) {
sum += count * (count - 1);
}
return total > 1 ? sum / (total * (total - 1)) : 0;
}
/**
* Cryptanalysis Attack Methods
* Educational implementations of common attacks
*/
// Frequency analysis for single substitution ciphers
function frequencyAnalysis(text) {
const frequencies = {};
let totalLetters = 0;
// Count each letter
for (const char of text.toUpperCase()) {
if (/[A-Z]/.test(char)) {
frequencies[char] = (frequencies[char] || 0) + 1;
totalLetters++;
}
}
// Convert to percentages
const analysis = [];
for (const [letter, count] of Object.entries(frequencies)) {
analysis.push({
letter,
count,
frequency: ((count / totalLetters) * 100).toFixed(2)
});
}
// Sort by frequency (descending)
return analysis.sort((a, b) => b.count - a.count);
}
// Kasiski Examination for Vigenère cipher
function kasiskiExamination(ciphertext) {
const text = ciphertext.toUpperCase().replace(/[^A-Z]/g, '');
const trigrams = {};
const distances = [];
// Find all trigrams and their positions
for (let i = 0; i <= text.length - 3; i++) {
const trigram = text.substr(i, 3);
if (!trigrams[trigram]) {
trigrams[trigram] = [];
}
trigrams[trigram].push(i);
}
// Calculate distances between repeated trigrams
for (const [trigram, positions] of Object.entries(trigrams)) {
if (positions.length > 1) {
for (let i = 1; i < positions.length; i++) {
distances.push(positions[i] - positions[i-1]);
}
}
}
// Find GCD of distances to estimate key length
return distances.length > 0 ? gcd(...distances) : null;
}
// Greatest Common Divisor helper function
function gcd(a, b) {
return b === 0 ? a : gcd(b, a % b);
}