密码学 - Playfair 密码



Playfair 密码,也称为 Playfair 方格或 Wheatstone-Playfair 密码,是一种手动对称加密方案,是第一个使用文字二元组替换的方案。查尔斯·惠斯通于 1854 年创建了该技术,但它以莱尔德·普莱费尔的名字命名,以促进其使用。

这种方法加密的是字母对,而不是像简单替换密码和以前使用的更复杂的维吉尼亚密码系统那样加密单个字母。因此,Playfair 密码更难破解,因为用于基本替换密码的频率分析不适用于它。二元组的频率分析是可能的,但极其复杂。由于有 600 个可能的二元组,而不是 26 个可能的单字母组(单个符号,在此上下文中通常是字母),因此需要更大的密文才能发挥作用。

历史

Playfair 密码是第一个也是最著名的使用对称加密的二元组替换密码。查尔斯·惠斯通于 1854 年发明了这种密码,莱尔德·普莱费尔倡导使用这种密码,并以他的名字命名。与仅加密单个字母的传统替换密码不同,Playfair 密码方法对二元组或字母片段进行编码。

Playfair 密码速度快,并且不需要任何其他工具即可操作。英国和澳大利亚军队在第一次世界大战、第二次布尔战争和第二次世界大战期间战术性地使用了它。加密的主要目的是在实际战斗中保护非关键但重要的数据。当敌方密码分析员解密它时,这些信息已毫无用处。

了解 Playfair 密码

Playfair 密码包含一个 5x5 的字母矩阵(密钥表),没有重复的字母。字母 I 和 J 被视为同一个字母。我们通过按顺序排列关键字的唯一字母,然后是字母表的其余字母来创建密钥表。

以单词 SECURITY 为例。首先,我们将该短语的字母记录在 5x5 矩阵的第一个方格中 -

Playfair Cipher

然后,矩阵的其余方格用字母表中剩余的字母填充,按字母顺序排列。但是,由于有 26 个字母,而只有 25 个方格可用,因此我们将 I 和 J 分配到同一个方格。

Playfair Cipher Understanding

在选择术语时,请确保没有字母重复,尤其是不应同时出现字母 I 和 J。例如,像 INJURE、JUICE 和 JIGSAW 这样的关键字将被取消资格,因为它们同时包含 I 和 J,这违反了此标准。

加密过程

Playfair 密码的加密过程包括将消息转换为其加密形式的若干步骤。

创建密钥方格

首先,我们将使用指定的关键字创建一个密钥方格。在本例中,我们将使用术语 SECURITY -

Playfair Cipher encryption

准备消息

在加密消息之前,我们必须先对其进行处理。我们将 J 视为 I,因此在加密过程中省略 J。我们还删除任何非字母字符,例如空格和标点符号。

例如,处理字符串 HELLOWORLD 得到 HELOWORLD。

配对字母

我们继续将创建的消息分成字母对(二元组)。如果二元组中两个连续的字母相同,则在它们之间插入一个 X。此外,如果明文长度为奇数,我们会在末尾附加 X 以创建一个完整的二元组。

例如,在处理单词“HELLO WORLD”时,我们将将其分成字母对 -

HE LL OW OR LD

二元组 LL 有相同的连续字母,因此我们在它们之间插入 X -

HE LX LO WO RL D

插入后消息的长度不规则,因此我们在末尾附加 X 以使其长度为偶数 -

HE LX LO WO RL DX

加密规则

主要有三种标准用于加密同一对中的字母。

  • 如果对中的两个字母在密钥方格的同一行中,我们用它们右侧的字母替换它们。

  • 如果对中的两个字母都位于密钥方格的同一列中,我们将用它们下方的字母替换每个字母。

  • 如果字母位于不同的行和列中,我们用它们形成一个矩形,并用相对角上的字母替换每个字母。

使用带有关键字 SECURITY 的矩阵,让我们找到每个对的行和列,并对 HELLOWORLD 应用加密规则,其对为 -

HE LX LO WO RL DX

将加密规则应用于所有字母对后,我们将得到 FUOQMPXNSPHQ。

解密过程

使用 Playfair 密码解密加密的消息时,该方法需要反转加密过程中使用的操作。

密钥方格构建

与加密过程一样,解密方法首先使用关键字 SECURITY 创建密钥方格。密钥方格是帮助解密编码消息的关键参考网格。

此密钥方格为在解密过程中理解加密文本奠定了基础。

加密规则

解密规则只是加密规则的反向。当对中的两个字母都在密钥方格的同一行中时,我们用它们左侧的字母替换它们。

同样,假设对中的两个字母都位于密钥方格的同一列中。在这种情况下,我们将每个字母替换为其正上方的字母。当字母位于不同的行和列中时,我们使用字母对形成一个矩形,并用相对角上的字母替换每个字母。

过程

让我们借助上述解密规则解密消息 FUOQMPXNSPHQ。因此,我们将逐一处理它们。

F 和 U 位于不同的行和列中,从而形成了一个以 E、U、F 和 H 为角的矩形。将 F 与其相对角 H 交换,将 U 与其相对角 E 交换,得到 HEOQMPXNSPHQ。

O 和 Q 位于不同的行和列中,从而形成了一个以 L、O、X 和 O 为角的矩形。将 O 与其相对角 L 交换,将 Q 与其相对角 X 交换,得到 HELXMPXNSPHQ。

继续使用这种技术会产生HELXLOWORLDX。此时,我们拥有HELXLOWORLDX。去除X后,我们得到HELLOWORLD。

Playfair 密码的重要性

在第一次和第二次世界大战期间,由于 Playfair 密码相较于当时其他密码的相对复杂性,它获得了普及。此外,数据加密和解密都不需要任何专门的设备或方法。然而,随着计算机的引入,Playfair 密码变得过时,因为计算机可以轻松破解代码以解密 Playfair 密码。

因此,随着数字加密的改进和时间的推移,由于数据落入非预期人员手中的风险,Playfair 密码不再是一种可接受的消息编码方法。因此,不建议企业使用 Playfair 密码。

使用 Python 实现

Playfair 密码使用原始文本(明文)中的字母对(二元组)进行操作。它使用一个 5x5 的密钥方阵来加密这些二元组。密钥方阵由一个关键字和英文字母表创建。在加密之前,明文转换为小写,空格被移除,双字母由占位符字母('x')分隔。然后将明文拆分为二元组。对于每个二元组,使用基于字母在密钥方阵中位置的特定规则找到相应的加密二元组。然后将加密的二元组连接在一起,形成最终的加密消息。密钥和明文都可以更改,从而创建不同的加密选项。

示例

以下是 Playfair 密码在 Python 中的实现:

# List of alphabets
alphabet_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

# Function to convert the string to lowercase
def to_lowercase(text):
   return text.lower()

# Function to remove all spaces in a string
def remove_spaces(text):
   new_text = ""
   for char in text:
      if char != " ":
         new_text += char
   return new_text

# Function to group 2 elements of a string
def group_characters(text):
   groups = []
   group_start = 0
   for i in range(2, len(text), 2):
      groups.append(text[group_start:i])
      group_start = i
   groups.append(text[group_start:])
   return groups

# Function to fill a letter in a string element
def fill_letter(text):
   k = len(text)
   if k % 2 == 0:
      for i in range(0, k, 2):
         if text[i] == text[i+1]:
            new_word = text[0:i+1] + str('x') + text[i+1:]
            new_word = fill_letter(new_word)
            break
         else:
            new_word = text
   else:
      for i in range(0, k-1, 2):
         if text[i] == text[i+1]:
            new_word = text[0:i+1] + str('x') + text[i+1:]
            new_word = fill_letter(new_word)
            break
         else:
            new_word = text
   return new_word

# Generating the 5x5 key square matrix
def generate_key_matrix(word, alphabet_list):
   key_letters = []
   for char in word:
      if char not in key_letters:
         key_letters.append(char)

   complementary_elements = []
   for char in key_letters:
      if char not in complementary_elements:
         complementary_elements.append(char)
   for char in alphabet_list:
      if char not in complementary_elements:
         complementary_elements.append(char)

   matrix = []
   while complementary_elements != []:
      matrix.append(complementary_elements[:5])
      complementary_elements = complementary_elements[5:]

   return matrix

# Searching for an element in the matrix
def search_element(matrix, element):
   for i in range(5):
      for j in range(5):
         if matrix[i][j] == element:
            return i, j

# Encryption using Row Rule
def encrypt_row_rule(matrix, e1_row, e1_column, e2_row, e2_column):
   char1 = ''
   if e1_column == 4:
      char1 = matrix[e1_row][0]
   else:
      char1 = matrix[e1_row][e1_column+1]

   char2 = ''
   if e2_column == 4:
      char2 = matrix[e2_row][0]
   else:
      char2 = matrix[e2_row][e2_column+1]

   return char1, char2

# Encryption using Column Rule
def encrypt_column_rule(matrix, e1_row, e1_column, e2_row, e2_column):
   char1 = ''
   if e1_row == 4:
      char1 = matrix[0][e1_column]
   else:
      char1 = matrix[e1_row+1][e1_column]

   char2 = ''
   if e2_row == 4:
      char2 = matrix[0][e2_column]
   else:
      char2 = matrix[e2_row+1][e2_column]

   return char1, char2

# Encryption using Rectangle Rule
def encrypt_rectangle_rule(matrix, e1_row, e1_column, e2_row, e2_column):
   char1 = matrix[e1_row][e2_column]
   char2 = matrix[e2_row][e1_column]

   return char1, char2

# Encrypting text using the Playfair Cipher
def encrypt_playfair_cipher(matrix, plaintext_list):
   cipher_text = []
   for i in range(0, len(plaintext_list)):
      char1 = 0
      char2 = 0
      ele1_x, ele1_y = search_element(matrix, plaintext_list[i][0])
      ele2_x, ele2_y = search_element(matrix, plaintext_list[i][1])

      if ele1_x == ele2_x:
         char1, char2 = encrypt_row_rule(matrix, ele1_x, ele1_y, ele2_x, ele2_y)
      elif ele1_y == ele2_y:
         char1, char2 = encrypt_column_rule(matrix, ele1_x, ele1_y, ele2_x, ele2_y)
      else:
         char1, char2 = encrypt_rectangle_rule(matrix, ele1_x, ele1_y, ele2_x, ele2_y)

      cipher = char1 + char2
      cipher_text.append(cipher)
   return cipher_text

# Main function
text_plain = 'tutorialspoint'
text_plain = remove_spaces(to_lowercase(text_plain))
plaintext_list = group_characters(fill_letter(text_plain))
if len(plaintext_list[-1]) != 2:
   plaintext_list[-1] = plaintext_list[-1]+'z'

key = "bestkey"
print("The Key text:", key)
key = to_lowercase(key)
matrix = generate_key_matrix(key, alphabet_list)

print("The Plain Text:", text_plain)
cipher_list = encrypt_playfair_cipher(matrix, plaintext_list)

cipher_text = ""
for i in cipher_list:
   cipher_text += i
print("The CipherText:", cipher_text)

以下是上述示例的输出:

输入/输出

The Key text: bestkey
The Plain Text: tutorialspoint
The CipherText: bxeqpmdhcwphqb

优点

  • 如果我们仔细检查算法,我们可以看到该过程的每个阶段都会产生唯一的密文,这使得密码分析师更难破解。

  • 它对蛮力攻击不敏感。

  • 密码分析是不可能的(在不知道密钥的情况下解码密码)。

  • 消除了简单 Playfair 方阵密码中的一个缺陷。

  • 替换操作很简单。

缺点

Playfair 密码存在以下缺点:

  • 仅支持 25 个字母。

  • 它与该数量的字符不兼容。

  • 仅接受大写和小写字母。

  • 不允许使用空格、换行符和标点等特殊字符。

总结

Playfair 密码被认为是最古老和最有效的数据加密方法之一。深入理解 Playfair 密码是数据加密和机器学习的基础。

广告