密码学 - 列置换密码



一种以矩阵形式表示明文的换位密码称为列置换密码。将明文按行写入,然后逐列读取密文称为列置换。在本教程中,我们描述了列置换密码的加密和解密方法。列置换可能是研究最多的换位密码。

Columnar Transposition

它是如何工作的?

消息被构造为一个二维数组。消息的长度决定了将有多少行和列。如果消息长 30 个字符(包括空格),则有 50% 的概率会有 15 行 2 列、10 行 3 列、5 行 6 列或 6 行 5 列。

请记住,如果消息长度超过 29,我们必须在消息末尾附加一个虚拟字母。

加密

请参阅下面列置换密码的加密过程:

  • 首先,明文按预先定义的行写入,密钥确定长度。
  • 可以使用密钥确定明文列的转置顺序。
  • 然后通过逐列读取转置后的明文来创建密文。

解密

因此,列置换密码的解密过程如下:

  • 使用与加密相同的密钥,首先按列转置密文。
  • 可以通过逐行读取转置后的密文来检索明文。

列置换示例

如果消息为“The attack will start on Monday”,那么我们可以看到它有 28 个字符。但是,如果我们在末尾添加虚拟字母“x”和“x”,则消息将为 30 个字符。我们可以计算出 30 = 10 X 3,如果密钥为 (2,3,1),则列排列如下:

明文:“the attack will start on Monday”

Columnar Transposition Example

密文 - “HAA LSROMDXETCWLTTNOAXT TKI A NY” 是密文,它是根据表格按列读取计算得出的。为了更容易记住密钥,我们对关键字(如“TWO”)的字母进行重新排列,使其按字母顺序排列。因此,数组列将使用密钥 (2,3,1) 进行重新排列。

主要特征

列置换密码的主要特征如下:

  • 列置换密码是一种换位密码,它需要在加密之前将明文重新排列成列。
  • 由于密钥是对称的,因此它可以用于加密和解密。
  • 列置换密码允许使用可变的密钥大小。密钥包含 1 到 N 的整数的排列,其中 N 是明文的长度。
  • 密码分析可以破解列置换密码,尤其是在明文具有重复模式或密钥较短的情况下。

列置换密码的用例

  • 列置换密码的应用非常广泛,例如数据保护、军事通信和间谍活动。
  • 它在明文包含长重复模式(如二进制数据或 DNA 序列)的情况下特别有效。
  • 为了提高加密数据的安全性,列置换密码还可以与其他加密技术(如替换密码)结合使用。

实施

现在,我们将使用 Python、Java、C++ 和 Javascript 实现列置换密码。

使用 Python 实现

该代码将演示如何使用 Python 编程语言中的列置换密码加密明文消息,然后将密文解密回明文。

示例

def columnar_encrypt(plaintext, keyword):
   matrix = create_encryption_matrix(len(keyword), plaintext)
   keyword_sequence = get_keyword_sequence(keyword)

   ciphertext = ""
   for num in range(len(keyword_sequence)):
      pos = keyword_sequence.index(num + 1)
      for row in range(len(matrix)):
         if len(matrix[row]) > pos:
            ciphertext += matrix[row][pos]
   return ciphertext

def create_encryption_matrix(width, plaintext):
   r = 0
   c = 0
   matrix = [[]]
   for pos, ch in enumerate(plaintext):
      matrix[r].append(ch)
      c += 1
      if c >= width:
         c = 0
         r += 1
         matrix.append([])

   return matrix

def get_keyword_sequence(keyword):
   sequence = []
   for pos, ch in enumerate(keyword):
      previous_letters = keyword[:pos]
      new_number = 1
      for previous_pos, previous_ch in enumerate(previous_letters):
         if previous_ch > ch:
            sequence[previous_pos] += 1
         else:
            new_number += 1
      sequence.append(new_number)
   return sequence

def columnar_decrypt(ciphertext, keyword):
   matrix = create_encryption_matrix(len(keyword), ciphertext)
   keyword_sequence = get_keyword_sequence(keyword)

   plaintext = ""
   index = 0
   for num in range(len(keyword_sequence)):
      pos = keyword_sequence.index(num + 1)
      for row in range(len(matrix)):
         if len(matrix[row]) > pos:
            matrix[row][pos] = ciphertext[index]
            index += 1

   for row in range(len(matrix)):
      for col in range(len(matrix[row])):
         plaintext += matrix[row][col]

   return plaintext

# Execution of the functions
plaintext = "Tutorialspoint is best"
keyword = "railfence"
ciphertext = columnar_encrypt(plaintext, keyword)
print("The Encrypted Text:", ciphertext)
decrypted_text = columnar_decrypt(ciphertext, keyword)
print("The Decrypted Text:", decrypted_text)

以下是上述示例的输出:

输入/输出
The Encrypted Text: uoelsi s rttisontaiTpb
The Decrypted Text: Tutorialspoint is best

使用 Java 实现

现在,我们将使用 Java 编程语言实现列置换密码。我们将使用 Java 的 util 包,该包用于导入 Map 接口和 HashMap 类。代码如下:

示例

import java.util.*;

public class ColumnarCipher {
   // Define the Key 
   static final String encryptionKey = "BEST";
   static Map<Character, Integer> keyMap = new HashMap<>();

   static void setPermutationOrder() {
      // Add the permutation order into the map
      for (int i = 0; i < encryptionKey.length(); i++) {
         keyMap.put(encryptionKey.charAt(i), i);
      }
   }

   // Encryption Function
   static String encrypt(String plaintext) {
   int rows, columns;
   StringBuilder ciphertext = new StringBuilder();

   // Number of columns in the matrix
   columns = encryptionKey.length();

   // Maximum number of rows in the matrix 
   rows = (int) Math.ceil((double) plaintext.length() / columns);

   char[][] matrix = new char[rows][columns];

   for (int i = 0, k = 0; i < rows; i++) {
      for (int j = 0; j < columns; ) {
         if (k < plaintext.length()) {
            char ch = plaintext.charAt(k);
            if (Character.isLetter(ch) || ch == ' ') {
            matrix[i][j] = ch;
            j++;
            }
            k++;
         } else {
            /* Add padding character '_' */
            matrix[i][j] = '_';
            j++;
         }
      }
   }

      for (Map.Entry<Character, Integer> entry : keyMap.entrySet()) {
         int columnIndex = entry.getValue();

         // Get the cipher text 
         for (int i = 0; i < rows; i++) {
            if (Character.isLetter(matrix[i][columnIndex]) || matrix[i][columnIndex] == ' ' || matrix[i][columnIndex] == '_') {
               ciphertext.append(matrix[i][columnIndex]);
            }
         }
      }
      return ciphertext.toString();
   }

   // Decryption Function
   static String decrypt(String ciphertext) {
      int columns = encryptionKey.length();

      int rows = (int) Math.ceil((double) ciphertext.length() / columns);
      char[][] cipherMat = new char[rows][columns];

      // Add characters into the matrix column-wise 
      int k = 0;
      for (int j = 0; j < columns; j++) {
         for (int i = 0; i < rows; i++) {
            if (k < ciphertext.length()) {
               cipherMat[i][j] = ciphertext.charAt(k);
               k++;
            } else {
               cipherMat[i][j] = '_'; 
            }
         }
      }

      // Update the order of the key 
      int index = 0;
      for (Map.Entry<Character, Integer> entry : keyMap.entrySet()) {
         entry.setValue(index++);
      }

      char[][] decCipher = new char[rows][columns];
      for (int l = 0; l < encryptionKey.length(); l++) {
         int columnIndex = keyMap.get(encryptionKey.charAt(l));
         for (int i = 0; i < rows; i++) {
            decCipher[i][l] = cipherMat[i][columnIndex];
         }
      }

      // Get the message with the help of the matrix
      StringBuilder msg = new StringBuilder();
      for (int i = 0; i < rows; i++) {
         for (int j = 0; j < columns; j++) {
            if (decCipher[i][j] != '_') {
               msg.append(decCipher[i][j]);
            }
         }
      }
      return msg.toString();
   }


   public static void main(String[] args) {
      /* Plain text message */
      String plaintext = "This is a secret message.";

      setPermutationOrder();

      // Call the encryption function
      String ciphertext = encrypt(plaintext);
      System.out.println("The Encrypted Message: " + ciphertext);

      // Call the Decryption function
      System.out.println("The Decrypted Message: " + decrypt(ciphertext));
   }
}

以下是上述示例的输出:

输入/输出
The Encrypted Message: T ac s_isseeg_s etse_hi rma_
The Decrypted Message: This is a secret message

使用 C++ 实现

现在,我们将使用相同的概念并在 C++ 中为列置换密码实现代码。请查看下面的代码:

示例

#include<bits/stdc++.h>
using namespace std;

// Encryption key
string const encryptionKey = "BEST"; 
map<int,int> keyMap;

// Set the permutation order 
void setPermutationOrder() {			 
	// Add the permutation order into map 
	for(int i=0; i < encryptionKey.length(); i++) {
		keyMap[encryptionKey[i]] = i;
	}
}

// Encryption function
string encrypt(string plaintext) {
	int numRows, numCols, j;
	string ciphertext = "";
	
    // Calculate the number of columns in the matrix
	numCols = encryptionKey.length(); 
	
	// Calculate the maximum number of rows in the matrix 
	numRows = plaintext.length() / numCols; 
	
	if (plaintext.length() % numCols)
		numRows += 1;

	char matrix[numRows][numCols];

	for (int i=0, k=0; i < numRows; i++){
		for (int j=0; j < numCols; ){
			if(plaintext[k] == '\0'){
				// Add the padding character
				matrix[i][j] = '_';	 
				j++;
			}
			
			if(isalpha(plaintext[k]) || plaintext[k] == ' '){ 
				// Add only spaces and alphabets
				matrix[i][j] = plaintext[k];
				j++;
			}
			k++;
		}
	}

	for (map<int,int>::iterator it = keyMap.begin(); it != keyMap.end(); ++it){
		j = it->second;
		
		for (int i = 0; i < numRows; i++){
         if(isalpha(matrix[i][j]) || matrix[i][j] == ' ' || matrix[i][j] == '_')
            ciphertext += matrix[i][j];
		}
	}
	return ciphertext;
}

// Decryption function
string decrypt(string ciphertext){
	// Calculate the row and column 
	int numCols = encryptionKey.length();

	int numRows = ciphertext.length() / numCols;
	char cipherMat[numRows][numCols];

    // Add characters into the matrix column-wise
	for (int j = 0, k = 0; j < numCols; j++)
		for (int i = 0; i < numRows; i++)
			cipherMat[i][j] = ciphertext[k++];

	// Update the order of the key 
	int index = 0;
	for(map<int,int>::iterator it = keyMap.begin(); it != keyMap.end(); ++it)
		it->second = index++;

	// Arrange the matrix column-wise 
	char decCipher[numRows][numCols];
	map<int,int>::iterator it = keyMap.begin();
	int k = 0;
	for(int l = 0, j; encryptionKey[l] != '\0'; k++){
		j = keyMap[encryptionKey[l++]];
		for(int i = 0; i < numRows; i++){
			decCipher[i][k] = cipherMat[i][j];
		}
	}

	// Get the plaintext message 
	string plaintext = "";
	for(int i = 0; i < numRows; i++){
		for(int j = 0; j < numCols; j++){
			if(decCipher[i][j] != '_')
				plaintext += decCipher[i][j];
		}
	}
	return plaintext;
}

// Driver program
int main(void){
   string plaintext = "I am using Tutorialspoint"; 

   setPermutationOrder();
   string ciphertext = encrypt(plaintext);
   cout << "The Encrypted Message: " << ciphertext << endl;
   cout << "The Decrypted Message: " << decrypt(ciphertext) << endl;

   return 0;
}

以下是上述示例的输出:

输入/输出

The Encrypted Message: I nuipt ugtao_as oli_miTrsn_
The Decrypted Message: I am using Tutorialspoint

列置换的安全性

直到 20 世纪上半叶,列置换在全世界范围内被广泛使用。

为了破译密文,攻击者应该尝试制作各种大小的表格,将加密的消息输入到列中,并在每个表格中搜索行中存在的字谜。

优点

与任何加密方法一样,列置换密码也有其自身的优点。

  • 列置换密码通过重新排列给定明文中的字符顺序提供基本的安全性。此属性使未经授权的用户难以在不知情密钥的情况下破译。
  • 列置换密码算法非常易于实现,因为它需要最少的资源。
  • 它支持多种密钥长度,这意味着它允许用户根据其特定需求自定义安全级别。
  • 与其他替换密码不同,列置换密码不会保留字符的频率,这使得它对频率分析攻击具有很强的抵抗力。

缺点

尽管有优点,但列置换密码也有一些缺点:

  • 列置换密码提供基本的安全性,但容易受到暴力攻击,尤其是在密钥空间有限或选择不佳的情况下。
  • 适当的管理对于该保护至关重要,但在大型系统中很难做到。
  • 已知明文攻击可以通过揭示加密密钥的详细信息来破坏密码的安全性。

  • 尽管列置换密码适用于基本的加密需求,但它无法抵御意志坚定的对手或高级的密码分析技术。
  • 此外,当使用明文文本量较大时,其性能会下降,尤其是在使用手动保存方法时,因为矩阵的创建和转换非常复杂。

结论

列置换密码是一种置换密码,在加密前会将明文按列重新排列。它是一种常用的加密技术,易于使用,并且可以有效地用于各种目的,例如数据保护和军事通信。它可以与其他加密技术结合使用,以提高加密数据的安全性,但同时也容易受到密码分析的攻击。因此,选择性地使用列置换密码并采取适当的预防措施以降低其漏洞至关重要。

广告

© . All rights reserved.