使用Playfair密碼加密訊息的Java程式
加密是將資訊轉換為不可讀格式或密文的任務。通常是為了保護資訊的機密性。有很多方法和演算法可以加密資料。Playfair密碼演算法就是一個例子。在本文中,我們將學習如何編寫一個使用Playfair密碼加密訊息的Java程式。
Playfair密碼使用一個5x5的網格或矩陣和一組預定義的規則。要加密,我們需要一個金鑰和要加密的明文。
步驟
現在讓我們看看使用Playfair密碼加密訊息的步驟:
1. 生成金鑰表
這是一個5x5的字母網格,不允許重複。我們首先將金鑰的每個字母放入其中,然後放入所有剩餘的字母。字母i和j被認為佔據網格中的同一個單元格,因為5x5是25,而英語中有26個字母,因此必須做出一些妥協。
2. 將明文分成對
如果明文的長度是奇數,我們在末尾新增字母X使其成為偶數。然後我們將整個明文分成對,即每兩個字母一組。例如:如果明文長度為10,則將有5對字母。
3. 遍歷字母對
對於明文中的每一對字母,我們執行以下操作:
如果兩個連續的字母相同,則在它們之間插入一個X。
在步驟1中建立的網格中找到這兩個字母的位置。
如果字母在同一行,我們將每個字母替換為右側的字母。如果是該行的最後一個元素,我們可以轉到該行的第一個元素。
如果字母在同一列,我們將每個字母替換為其下方的字母。如果是該列的最後一個元素,我們可以轉到該列的第一個元素。
如果字母不在同一列或同一行,我們將每個字母替換為同一行但在另一個字母列中的字母。
4. 上一步獲得的字母集就是加密文字。
現在讓我們看看在Java中的上述實現。
示例
在下面的示例中,我們實現Playfair密碼來加密訊息。
public class PlayfairCipher {
private char[][] keyTable;
private static final int grid_dimension = 5;
private static final char APPEND = 'X';
public PlayfairCipher(String key) {
keyTable = generateKeyTable(key);
}
private char[][] generateKeyTable(String key) {
// Initialize the key table with all ' ' characters
char[][] table = new char[grid_dimension][grid_dimension];
for (int i = 0; i < grid_dimension; i++) {
for (int j = 0; j < grid_dimension; j++) {
table[i][j] = ' ';
}
}
// Fill the key table with the letters of the key
int row = 0;
int col = 0;
boolean[] used = new boolean[26];
for (int i = 0; i < key.length(); i++) {
char ch = Character.toUpperCase(key.charAt(i));
if (ch == 'J') {
ch = 'I';
}
if (!used[ch - 'A']) {
table[row][col] = ch;
used[ch - 'A'] = true;
col++;
if (col == grid_dimension) {
row++;
col = 0;
}
}
}
// Fill the remaining cells of the key table with the remaining letters of the alphabet
for (int i = 0; i < 26; i++) {
char ch = (char) ('A' + i);
if (ch == 'J') {
continue;
}
if (!used[i]) {
table[row][col] = ch;
col++;
if (col == grid_dimension) {
row++;
col = 0;
}
}
}
return table;
}
public String encrypt(String plaintext) {
plaintext = preprocess(plaintext);
StringBuilder ciphertext = new StringBuilder();
for (int i = 0; i < plaintext.length(); i += 2) {
char ch1 = plaintext.charAt(i);
char ch2 = plaintext.charAt(i + 1);
int[] position1 = findPosition(ch1);
int[] position2 = findPosition(ch2);
if (position1[0] == position2[0]) {
// When letters exist in same row
int newCol1 = (position1[1] + 1) % grid_dimension;
int newCol2 = (position2[1] + 1) % grid_dimension;
ciphertext.append(keyTable[position1[0]][newCol1]);
ciphertext.append(keyTable[position2[0]][newCol2]);
} else if (position1[1] == position2[1]) {
// When letters exist in same column
int newRow1 = (position1[0] + 1) % grid_dimension;
int newRow2 = (position2[0] + 1) % grid_dimension;
ciphertext.append(keyTable[newRow1][position1[1]]);
ciphertext.append(keyTable[newRow2][position2[1]]);
} else {
// When letters are not in the same column or in the same row
ciphertext.append(keyTable[position1[0]][position2[1]]);
ciphertext.append(keyTable[position2[0]][position1[1]]);
}
}
return ciphertext.toString();
}
public String decrypt(String ciphertext) {
StringBuilder plaintext = new StringBuilder();
for (int i = 0; i < ciphertext.length(); i += 2) {
char ch1 = ciphertext.charAt(i);
char ch2 = ciphertext.charAt(i + 1);
int[] position1 = findPosition(ch1);
int[] position2 = findPosition(ch2);
if (position1[0] == position2[0]) {
int newCol1 = (position1[1] + grid_dimension - 1) % grid_dimension;
int newCol2 = (position2[1] + grid_dimension - 1) % grid_dimension;
plaintext.append(keyTable[position1[0]][newCol1]);
plaintext.append(keyTable[position2[0]][newCol2]);
} else if (position1[1] == position2[1]) {
int newRow1 = (position1[0] + grid_dimension - 1) % grid_dimension;
int newRow2 = (position2[0] + grid_dimension - 1) % grid_dimension;
plaintext.append(keyTable[newRow1][position1[1]]);
plaintext.append(keyTable[newRow2][position2[1]]);
} else {
plaintext.append(keyTable[position1[0]][position2[1]]);
plaintext.append(keyTable[position2[0]][position1[1]]);
}
}
return postprocess(plaintext.toString());
}
private String preprocess(String text) {
// Replace J with I and add padding if needed
StringBuilder sb = new StringBuilder(text.toUpperCase().replaceAll("[^A-Z]", ""));
for (int i = 1; i < sb.length(); i += 2) {
if (sb.charAt(i) == sb.charAt(i - 1)) {
sb.insert(i, APPEND);
}
}
if (sb.length() % 2 != 0) {
sb.append(APPEND);
}
return sb.toString();
}
private String postprocess(String text) {
// Remove padding and replace X with the original character
StringBuilder sb = new StringBuilder(text);
for (int i = 1; i < sb.length(); i += 2) {
if (sb.charAt(i) == APPEND) {
sb.deleteCharAt(i);
}
}
return sb.toString().replace(APPEND, ' ');
}
private int[] findPosition(char ch) {
int[] pos = new int[2];
for (int i = 0; i < grid_dimension; i++) {
for (int j = 0; j < grid_dimension; j++) {
if (keyTable[i][j] == ch) {
pos[0] = i;
pos[1] = j;
return pos;
}
}
}
return null;
}
public static void main(String[] args) {
String plaintext = "MOSQUE";
String key = "MONARCHY";
PlayfairCipher cipher = new PlayfairCipher(key);
String ciphertext = cipher.encrypt(plaintext);
System.out.println("Plaintext: " + plaintext);
System.out.println("Ciphertext: " + ciphertext);
System.out.println("Decrypted text: " + cipher.decrypt(ciphertext));
}
}
輸出
上述程式將產生以下輸出:
Plaintext: MOSQUE Ciphertext: ONTSML Decrypted text: MOSQUE
結論
Playfair密碼是一種替換密碼,它使用一個5x5的字母網格。它遵循一組基於if-else的規則,不會產生歧義。與簡單的替換密碼相比,它提供了更強的安全性。它易於理解和實現。儘管它也有一些缺點,例如容易受到已知明文攻擊、金鑰管理問題以及無法加密非字母字元等,但它仍然是現代加密演算法中使用的基本概念和技術的有趣且具有歷史意義的示例。它不再用於建立現實生活中的安全通訊,但它提供了對現代加密演算法中使用的基本概念和技術的很好理解。
資料結構
網路
關係資料庫管理系統 (RDBMS)
作業系統
Java
iOS
HTML
CSS
Android
Python
C語言程式設計
C++
C#
MongoDB
MySQL
Javascript
PHP