mirror of
https://github.com/elder-plinius/P4RS3LT0NGV3.git
synced 2026-07-25 21:40:49 +02:00
8ff45957c8
Made-with: Cursor
111 lines
4.2 KiB
JavaScript
111 lines
4.2 KiB
JavaScript
// playfair cipher transform
|
|
import BaseTransformer from '../BaseTransformer.js';
|
|
|
|
export default new BaseTransformer({
|
|
name: 'Playfair Cipher',
|
|
priority: 60,
|
|
category: 'cipher',
|
|
key: 'KEYWORD', // Default key
|
|
func: function(text) {
|
|
const key = (this.key || 'KEYWORD').toUpperCase().replace(/[^A-Z]/g, '');
|
|
if (key.length === 0) return text;
|
|
|
|
// Create Playfair square
|
|
const alphabet = 'ABCDEFGHIKLMNOPQRSTUVWXYZ'; // J is combined with I
|
|
const keyChars = [...new Set(key.split(''))];
|
|
const remaining = alphabet.split('').filter(c => !keyChars.includes(c));
|
|
const square = [...keyChars, ...remaining];
|
|
|
|
// Helper to find position in square
|
|
const findPos = (char) => {
|
|
const idx = square.indexOf(char === 'J' ? 'I' : char);
|
|
return { row: Math.floor(idx / 5), col: idx % 5 };
|
|
};
|
|
|
|
// Helper to get char from position
|
|
const getChar = (row, col) => square[row * 5 + col];
|
|
|
|
// Prepare text: remove non-letters, replace J with I, add X between double letters
|
|
let prepared = text.toUpperCase().replace(/[^A-Z]/g, '').replace(/J/g, 'I');
|
|
if (prepared.length % 2 !== 0) prepared += 'X';
|
|
|
|
// Process pairs
|
|
let result = '';
|
|
for (let i = 0; i < prepared.length; i += 2) {
|
|
const a = prepared[i];
|
|
const b = prepared[i + 1];
|
|
const posA = findPos(a);
|
|
const posB = findPos(b);
|
|
|
|
if (posA.row === posB.row) {
|
|
// Same row: shift right
|
|
result += getChar(posA.row, (posA.col + 1) % 5);
|
|
result += getChar(posB.row, (posB.col + 1) % 5);
|
|
} else if (posA.col === posB.col) {
|
|
// Same column: shift down
|
|
result += getChar((posA.row + 1) % 5, posA.col);
|
|
result += getChar((posB.row + 1) % 5, posB.col);
|
|
} else {
|
|
// Rectangle: swap columns
|
|
result += getChar(posA.row, posB.col);
|
|
result += getChar(posB.row, posA.col);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
},
|
|
reverse: function(text) {
|
|
const key = (this.key || 'KEYWORD').toUpperCase().replace(/[^A-Z]/g, '');
|
|
if (key.length === 0) return text;
|
|
|
|
const alphabet = 'ABCDEFGHIKLMNOPQRSTUVWXYZ';
|
|
const keyChars = [...new Set(key.split(''))];
|
|
const remaining = alphabet.split('').filter(c => !keyChars.includes(c));
|
|
const square = [...keyChars, ...remaining];
|
|
|
|
const findPos = (char) => {
|
|
const idx = square.indexOf(char === 'J' ? 'I' : char);
|
|
return { row: Math.floor(idx / 5), col: idx % 5 };
|
|
};
|
|
|
|
const getChar = (row, col) => square[row * 5 + col];
|
|
|
|
let prepared = text.toUpperCase().replace(/[^A-Z]/g, '');
|
|
if (prepared.length % 2 !== 0) prepared += 'X';
|
|
|
|
let result = '';
|
|
for (let i = 0; i < prepared.length; i += 2) {
|
|
const a = prepared[i];
|
|
const b = prepared[i + 1];
|
|
const posA = findPos(a);
|
|
const posB = findPos(b);
|
|
|
|
if (posA.row === posB.row) {
|
|
// Same row: shift left
|
|
result += getChar(posA.row, (posA.col + 4) % 5);
|
|
result += getChar(posB.row, (posB.col + 4) % 5);
|
|
} else if (posA.col === posB.col) {
|
|
// Same column: shift up
|
|
result += getChar((posA.row + 4) % 5, posA.col);
|
|
result += getChar((posB.row + 4) % 5, posB.col);
|
|
} else {
|
|
// Rectangle: swap columns (same as encode)
|
|
result += getChar(posA.row, posB.col);
|
|
result += getChar(posB.row, posA.col);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
},
|
|
preview: function(text) {
|
|
if (!text) return '[playfair]';
|
|
const result = this.func(text.slice(0, 8));
|
|
return result.substring(0, 10) + (result.length > 10 ? '...' : '');
|
|
},
|
|
detector: function(text) {
|
|
const cleaned = text.replace(/[\s]/g, '').toUpperCase();
|
|
return cleaned.length >= 4 && cleaned.length % 2 === 0 && /^[A-Z]+$/.test(cleaned);
|
|
}
|
|
});
|
|
|