古典暗号ツールセット
ツール
🔐 古典暗号の一覧と説明
| 暗号名 | 説明 |
|---|---|
| アフィン暗号<br>(Affine Cipher) | アルファベットを数値に変換して、線形変換 E(x) = (a×x + b) mod 26 を使って暗号化する方式。a と 26 が互いに素である必要があるよ。復号には a の逆元が必要! |
| シーザー暗号<br>(Caesar Cipher) | アルファベットを一定の数だけずらすシンプルな暗号。たとえばシフト3なら A→D、B→E、…Z→C。ジュリアス・シーザーが使っていたことで有名! |
| ヴィジュネル暗号<br>(Vigenère Cipher) | キーワードを使って、文字ごとに異なるシフト量で暗号化する方式。シーザー暗号の進化版で、繰り返しのパターンを隠すのが得意! |
| アトバッシュ暗号<br>(Atbash Cipher) | アルファベットを逆順に置き換える暗号。A↔Z、B↔Y、C↔X…という風に、鏡に映したような変換をするよ。とってもシンプル! |
| プレイフェア暗号<br>(Playfair Cipher) | 5×5のマトリクスを使って、2文字ずつペアで暗号化する方式。同じ行・列・長方形の位置関係で文字を入れ替える。J は I と同じ扱いになるよ。 |
| レールフェンス暗号<br>(Rail Fence Cipher) | 文字をジグザグに並べて、上から順に読んで暗号化する方式。レールの数を変えることでパターンが変わるよ。見た目が波みたいで楽しい! |
| スキュタレー暗号<br>(Scytale Cipher) | 古代スパルタで使われた、円筒に巻きつけて書くような暗号。文字列を一定の列数で並べて、縦に読んで暗号化するよ。シンプルだけど効果的! |
?? 古典暗号ツールセット
テキストを入力して、好きな暗号方式でエンコード/デコードしてみよう!
結果:
プログラム
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>古典暗号ツールセット</title>
<style>
body { font-family: sans-serif; line-height: 1.6; padding: 20px; }
fieldset { margin-bottom: 20px; }
#result {
font-weight: bold;
background: #eef;
padding: 5px;
display: inline-block;
margin-top: 5px;
white-space: pre-wrap;
}
</style>
</head>
<body>
<h1>?? 古典暗号ツールセット</h1>
<p>テキストを入力して、好きな暗号方式でエンコード/デコードしてみよう!</p>
<label>テキスト: <input type="text" id="text" size="60"></label><br><br>
<!-- アフィン暗号 -->
<fieldset>
<legend>?? アフィン暗号</legend>
<p>線形変換 E(x) = (a×x + b) mod 26 を使う暗号</p>
<label>a:
<select id="a">
<option value="1">1</option>
<option value="3">3</option>
<option value="5" selected>5</option>
<option value="7">7</option>
<option value="9">9</option>
<option value="11">11</option>
<option value="15">15</option>
<option value="17">17</option>
<option value="19">19</option>
<option value="21">21</option>
<option value="23">23</option>
<option value="25">25</option>
</select>
</label><br>
<label>b:
<input type="range" id="b" min="0" max="25" value="8" oninput="updateBValue(this.value)">
<span id="bValue">8</span>
</label><br>
<button onclick="encryptAffine()">エンコード</button>
<button onclick="decryptAffine()">デコード</button>
</fieldset>
<!-- シーザー暗号 -->
<fieldset>
<legend>?? シーザー暗号</legend>
<p>アルファベットを一定数ずらす単純な暗号</p>
<label>シフト量:
<input type="number" id="shift" value="3" min="1" max="25">
</label><br>
<button onclick="encryptCaesar()">エンコード</button>
<button onclick="decryptCaesar()">デコード</button>
</fieldset>
<!-- ヴィジュネル暗号 -->
<fieldset>
<legend>?? ヴィジュネル暗号</legend>
<p>キーワードに基づいて文字ごとに異なるシフトをかける多段階暗号</p>
<label>キーワード: <input type="text" id="vigenereKey" value="KEY"></label><br>
<button onclick="encryptVigenere()">エンコード</button>
<button onclick="decryptVigenere()">デコード</button>
</fieldset>
<!-- アトバッシュ暗号 -->
<fieldset>
<legend>?? アトバッシュ暗号</legend>
<p>アルファベットを逆順に置き換える鏡文字暗号</p>
<button onclick="atbash()">変換</button>
</fieldset>
<!-- プレイフェア暗号 -->
<fieldset>
<legend>?? プレイフェア暗号</legend>
<p>5×5のマトリクスを使って2文字ずつ変換するペア暗号</p>
<label>キーワード: <input type="text" id="playfairKey" value="MONARCHY"></label><br>
<button onclick="encryptPlayfair()">エンコード</button>
<button onclick="decryptPlayfair()">デコード</button>
</fieldset>
<!-- レールフェンス暗号 -->
<fieldset>
<legend>?? レールフェンス暗号</legend>
<p>文字をジグザグに並べて再構成する波型暗号</p>
<label>レール数: <input type="number" id="rails" value="3" min="2" max="10"></label><br>
<button onclick="encryptRailFence()">エンコード</button>
<button onclick="decryptRailFence()">デコード</button>
</fieldset>
<!-- スキュタレー暗号 -->
<fieldset>
<legend>?? スキュタレー暗号</legend>
<p>文字列を一定の列数で並べて縦読みする古代スパルタの暗号</p>
<label>列数(幅): <input type="number" id="scytaleCols" value="4" min="2" max="20"></label><br>
<button onclick="encryptScytale()">エンコード</button>
<button onclick="decryptScytale()">デコード</button>
</fieldset>
<!-- 逆順 -->
<fieldset>
<legend>?? 逆順ツール</legend>
<p>文字列を逆さに並べ替える単純変換</p>
<button onclick="reverseText()">逆順にする</button>
</fieldset>
<br>
<button onclick="copyResult()">コピー</button>
<p>結果: <span id="result"></span></p>
<script>
const m = 26;
function updateBValue(val) {
document.getElementById("bValue").textContent = val;
}
function modInverse(a, m) {
a = ((a % m) + m) % m;
for (let x = 1; x < m; x++) {
if ((a * x) % m === 1) return x;
}
throw new Error("逆元が存在しません");
}
function encryptAffine() {
const text = document.getElementById("text").value.toLowerCase();
const a = parseInt(document.getElementById("a").value);
const b = parseInt(document.getElementById("b").value);
let result = "";
for (let c of text) {
if (c >= 'a' && c <= 'z') {
const x = c.charCodeAt(0) - 97;
const y = (a * x + b) % m;
result += String.fromCharCode(y + 97);
} else {
result += c;
}
}
document.getElementById("result").textContent = result;
}
function decryptAffine() {
const text = document.getElementById("text").value.toLowerCase();
const a = parseInt(document.getElementById("a").value);
const b = parseInt(document.getElementById("b").value);
const a_inv = modInverse(a, m);
let result = "";
for (let c of text) {
if (c >= 'a' && c <= 'z') {
const y = c.charCodeAt(0) - 97;
const x = (a_inv * (y - b + m)) % m;
result += String.fromCharCode(x + 97);
} else {
result += c;
}
}
document.getElementById("result").textContent = result;
}
function encryptCaesar() {
const text = document.getElementById("text").value.toLowerCase();
const shift = parseInt(document.getElementById("shift").value);
let result = "";
for (let c of text) {
if (c >= 'a' && c <= 'z') {
const x = (c.charCodeAt(0) - 97 + shift) % m;
result += String.fromCharCode(x + 97);
} else {
result += c;
}
}
document.getElementById("result").textContent = result;
}
function decryptCaesar() {
const text = document.getElementById("text").value.toLowerCase();
const shift = parseInt(document.getElementById("shift").value);
let result = "";
for (let c of text) {
if (c >= 'a' && c <= 'z') {
const x = (c.charCodeAt(0) - 97 - shift + m) % m;
result += String.fromCharCode(x + 97);
} else {
result += c;
}
}
document.getElementById("result").textContent = result;
}
function encryptVigenere() {
const text = document.getElementById("text").value.toLowerCase();
const key = document.getElementById("vigenereKey").value.toLowerCase();
let result = "", j = 0;
for (let i = 0; i < text.length; i++) {
const c = text[i];
if (c >= 'a' && c <= 'z') {
const shift = key.charCodeAt(j % key.length) - 97;
const x = (c.charCodeAt(0) - 97 + shift) % 26;
result += String.fromCharCode(x + 97);
j++;
} else {
result += c;
}
}
document.getElementById("result").textContent = result;
}
function decryptVigenere() {
const text = document.getElementById("text").value.toLowerCase();
const key = document.getElementById("vigenereKey").value.toLowerCase();
let result = "", j = 0;
for (let i = 0; i < text.length; i++) {
const c = text[i];
if (c >= 'a' && c <= 'z') {
const shift = key.charCodeAt(j % key.length) - 97;
const x = (c.charCodeAt(0) - 97 - shift + 26) % 26;
result += String.fromCharCode(x + 97);
j++;
} else {
result += c;
}
}
document.getElementById("result").textContent = result;
}
function atbash() {
const text = document.getElementById("text").value.toLowerCase();
let result = "";
for (let c of text) {
if (c >= 'a' && c <= 'z') {
const x = 25 - (c.charCodeAt(0) - 97);
result += String.fromCharCode(x + 97);
} else {
result += c;
}
}
document.getElementById("result").textContent = result;
}
function reverseText() {
const text = document.getElementById("text").value;
document.getElementById("result").textContent = text.split("").reverse().join("");
}
function copyResult() {
const result = document.getElementById("result").textContent;
navigator.clipboard.writeText(result).then(() => {
});
}
function encryptRailFence() {
const text = document.getElementById("text").value.replace(/[^a-zA-Z]/g, "");
const numRails = parseInt(document.getElementById("rails").value);
if (numRails < 2) return alert("レール数は2以上にしてね!");
let rails = Array.from({ length: numRails }, () => []);
let rail = 0, direction = 1;
for (let char of text) {
rails[rail].push(char);
rail += direction;
if (rail === 0 || rail === numRails - 1) direction *= -1;
}
const result = rails.flat().join("");
document.getElementById("result").textContent = result;
}
function decryptRailFence() {
const text = document.getElementById("text").value.replace(/[^a-zA-Z]/g, "");
const numRails = parseInt(document.getElementById("rails").value);
if (numRails < 2) return alert("レール数は2以上にしてね!");
const len = text.length;
let pattern = Array(len).fill(0);
let rail = 0, direction = 1;
for (let i = 0; i < len; i++) {
pattern[i] = rail;
rail += direction;
if (rail === 0 || rail === numRails - 1) direction *= -1;
}
let railCounts = Array(numRails).fill(0);
for (let r of pattern) railCounts[r]++;
let rails = [], pos = 0;
for (let count of railCounts) {
rails.push(text.slice(pos, pos + count).split(""));
pos += count;
}
let result = "";
for (let r of pattern) {
result += rails[r].shift();
}
document.getElementById("result").textContent = result;
}
function encryptScytale() {
const text = document.getElementById("text").value.replace(/[^a-zA-Z]/g, "");
const cols = parseInt(document.getElementById("scytaleCols").value);
const rows = Math.ceil(text.length / cols);
let grid = Array.from({ length: rows }, () => Array(cols).fill(""));
for (let i = 0; i < text.length; i++) {
const row = Math.floor(i / cols);
const col = i % cols;
grid[row][col] = text[i];
}
let result = "";
for (let col = 0; col < cols; col++) {
for (let row = 0; row < rows; row++) {
if (grid[row][col]) result += grid[row][col];
}
}
document.getElementById("result").textContent = result;
}
function decryptScytale() {
const text = document.getElementById("text").value.replace(/[^a-zA-Z]/g, "");
const cols = parseInt(document.getElementById("scytaleCols").value);
const rows = Math.ceil(text.length / cols);
const shortCols = cols * rows - text.length;
let grid = Array.from({ length: rows }, () => []);
let index = 0;
for (let col = 0; col < cols; col++) {
for (let row = 0; row < rows; row++) {
if (col >= cols - shortCols && row === rows - 1) continue;
grid[row][col] = text[index++];
}
}
let result = "";
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
if (grid[row][col]) result += grid[row][col];
}
}
document.getElementById("result").textContent = result;
}
function generatePlayfairMatrix(key) {
key = key.toLowerCase().replace(/[^a-z]/g, "").replace(/j/g, "i");
let seen = new Set();
let matrix = [];
for (let c of key + "abcdefghijklmnopqrstuvwxyz") {
if (c === 'j') c = 'i';
if (!seen.has(c)) {
seen.add(c);
matrix.push(c);
}
}
return matrix.slice(0, 25);
}
function findPosition(matrix, char) {
if (char === 'j') char = 'i';
const index = matrix.indexOf(char);
return [Math.floor(index / 5), index % 5];
}
function getChar(matrix, row, col) {
return matrix[(row + 5) % 5 * 5 + (col + 5) % 5];
}
function prepareText(text) {
text = text.toLowerCase().replace(/[^a-z]/g, "").replace(/j/g, "i");
let result = "";
for (let i = 0; i < text.length; i += 2) {
let a = text[i];
let b = text[i + 1] || 'x';
if (a === b) {
result += a + 'x';
i--;
} else {
result += a + b;
}
}
return result;
}
function encryptPlayfair() {
const key = document.getElementById("playfairKey").value;
const text = prepareText(document.getElementById("text").value);
const matrix = generatePlayfairMatrix(key);
let result = "";
for (let i = 0; i < text.length; i += 2) {
const [r1, c1] = findPosition(matrix, text[i]);
const [r2, c2] = findPosition(matrix, text[i + 1]);
if (r1 === r2) {
result += getChar(matrix, r1, c1 + 1) + getChar(matrix, r2, c2 + 1);
} else if (c1 === c2) {
result += getChar(matrix, r1 + 1, c1) + getChar(matrix, r2 + 1, c2);
} else {
result += getChar(matrix, r1, c2) + getChar(matrix, r2, c1);
}
}
document.getElementById("result").textContent = result;
}
function decryptPlayfair() {
const key = document.getElementById("playfairKey").value;
const text = prepareText(document.getElementById("text").value);
const matrix = generatePlayfairMatrix(key);
let result = "";
for (let i = 0; i < text.length; i += 2) {
const [r1, c1] = findPosition(matrix, text[i]);
const [r2, c2] = findPosition(matrix, text[i + 1]);
if (r1 === r2) {
result += getChar(matrix, r1, c1 - 1) + getChar(matrix, r2, c2 - 1);
} else if (c1 === c2) {
result += getChar(matrix, r1 - 1, c1) + getChar(matrix, r2 - 1, c2);
} else {
result += getChar(matrix, r1, c2) + getChar(matrix, r2, c1);
}
}
document.getElementById("result").textContent = result;
}
</script>
</body>
</html>







ディスカッション
コメント一覧
まだ、コメントがありません