c++ 希尔密码

发布时间:2024年01月11日

希尔密码(Hill Cipher)是一种替代密码方法,它使用矩阵运算来对明文进行加密和解密。

示例一:

/**
?* @file hill_cipher.cpp
?* @brief Implementation of [Hill
?* cipher](https://en.wikipedia.org/wiki/Hill_cipher) algorithm.
?*
?* Program to generate the encryption-decryption key and perform encryption and
?* decryption of ASCII text using the famous block cipher algorithm. This is a
?* powerful encryption algorithm that is relatively easy to implement with a
?* given key. The strength of the algorithm depends on the size of the block
?* encryption matrix key; the bigger the matrix, the stronger the encryption and
?* more difficult to break it. However, the important requirement for the matrix
?* is that:
?* 1. matrix should be invertible - all inversion conditions should be satisfied
?* and
?* 2. its determinant must not have any common factors with the length of
?* character set
?* Due to this restriction, most implementations only implement with small 3x3
?* encryption keys and a small subset of ASCII alphabets.
?*
?* In the current implementation, I present to you an implementation for
?* generating larger encryption keys (I have attempted upto 10x10) and an ASCII
?* character set of 97 printable characters. Hence, a typical ASCII text file
?* could be easily encrypted with the module. The larger character set increases
?* the modulo of cipher and hence the matrix determinants can get very large
?* very quickly rendering them ill-defined.
?*
?* \note This program uses determinant computation using LU decomposition from
?* the file lu_decomposition.h
?* \note The matrix generation algorithm is very rudimentary and does not
?* guarantee an invertible modulus matrix. \todo Better matrix generation
?* algorithm.
?*
?* @author [Krishna Vedala](https://github.com/kvedala)
?*/

#include <cassert>
#include <cmath>
#include <cstring>
#include <ctime>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <string>
#ifdef _OPENMP
#include <omp.h>
#endif

#include "../numerical_methods/lu_decomposition.h"

/**
?* operator to print a matrix
?*/
template <typename T>
static std::ostream &operator<<(std::ostream &out, matrix<T> const &v) {
? ? const int width = 15;
? ? const char separator = ' ';

? ? for (size_t row = 0; row < v.size(); row++) {
? ? ? ? for (size_t col = 0; col < v[row].size(); col++)
? ? ? ? ? ? out << std::left << std::setw(width) << std::setfill(separator)
? ? ? ? ? ? ? ? << v[row][col];
? ? ? ? out << std::endl;
? ? }

? ? return out;
}

/** \namespace ciphers
?* \brief Algorithms for encryption and decryption
?*/
namespace ciphers {
/** dictionary of characters that can be encrypted and decrypted */
static const char *STRKEY =
? ? "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!@#$%^&"
? ? "*()_+`-=[]{}|;':\",./<>?\\\r\n \0";

/**
?* @brief Implementation of [Hill
?* Cipher](https://en.wikipedia.org/wiki/Hill_cipher) algorithm
?*/
class HillCipher {
?private:
? ? /**
? ? ?* @brief Function to generate a random integer in a given interval
? ? ?*
? ? ?* @param a lower limit of interval
? ? ?* @param b upper limit of interval
? ? ?* @tparam T type of output
? ? ?* @return random integer in the interval \f$[a,b)\f$
? ? ?*/
? ? template <typename T1, typename T2>
? ? static const T2 rand_range(T1 a, T1 b) {
? ? ? ? // generate random number between 0 and 1
? ? ? ? long double r = static_cast<long double>(std::rand()) / RAND_MAX;

? ? ? ? // scale and return random number as integer
? ? ? ? return static_cast<T2>(r * (b - a) + a);
? ? }

? ? /**
? ? ?* @brief Function overload to fill a matrix with random integers in a given
? ? ?* interval
? ? ?*
? ? ?* @param M pointer to matrix to be filled with random numbers
? ? ?* @param a lower limit of interval
? ? ?* @param b upper limit of interval
? ? ?* @tparam T1 type of input range
? ? ?* @tparam T2 type of matrix
? ? ?* @return determinant of generated random matrix
? ? ?*
? ? ?* @warning There will need to be a balance between the matrix size and the
? ? ?* range of random numbers. If the matrix is large, the range of random
? ? ?* numbers must be small to have a well defined keys. Or if the matrix is
? ? ?* smaller, the random numbers range can be larger. For an 8x8 matrix, range
? ? ?* should be no more than \f$[0,10]\f$
? ? ?*/
? ? template <typename T1, typename T2>
? ? static double rand_range(matrix<T2> *M, T1 a, T1 b) {
? ? ? ? for (size_t i = 0; i < M->size(); i++) {
? ? ? ? ? ? for (size_t j = 0; j < M[0][0].size(); j++) {
? ? ? ? ? ? ? ? M[0][i][j] = rand_range<T1, T2>(a, b);
? ? ? ? ? ? }
? ? ? ? }

? ? ? ? return determinant_lu(*M);
? ? }

? ? /**
? ? ?* @brief Compute
? ? ?* [GCD](https://en.wikipedia.org/wiki/Greatest_common_divisor) of two
? ? ?* integers using Euler's algorithm
? ? ?*
? ? ?* @param a first number
? ? ?* @param b second number
? ? ?* @return GCD of \f$a\f$ and \f$b\f$
? ? ?*/
? ? template <typename T>
? ? static const T gcd(T a, T b) {
? ? ? ? if (b > a) ?// ensure always a < b
? ? ? ? ? ? std::swap(a, b);

? ? ? ? while (b != 0) {
? ? ? ? ? ? T tmp = b;
? ? ? ? ? ? b = a % b;
? ? ? ? ? ? a = tmp;
? ? ? ? }

? ? ? ? return a;
? ? }

? ? /**
? ? ?* @brief helper function to perform vector multiplication with encryption
? ? ?* or decryption matrix
? ? ?*
? ? ?* @param vector vector to multiply
? ? ?* @param key encryption or decryption key matrix
? ? ?* @return corresponding encrypted or decrypted text
? ? ?*/
? ? static const std::valarray<uint8_t> mat_mul(
? ? ? ? const std::valarray<uint8_t> &vector, const matrix<int> &key) {
? ? ? ? std::valarray<uint8_t> out(vector); ?// make a copy

? ? ? ? size_t L = std::strlen(STRKEY);

? ? ? ? for (size_t i = 0; i < key.size(); i++) {
? ? ? ? ? ? int tmp = 0;
? ? ? ? ? ? for (size_t j = 0; j < vector.size(); j++) {
? ? ? ? ? ? ? ? tmp += key[i][j] * vector[j];
? ? ? ? ? ? }
? ? ? ? ? ? out[i] = static_cast<uint8_t>(tmp % L);
? ? ? ? }

? ? ? ? return out;
? ? }

? ? /**
? ? ?* @brief Get the character at a given index in the ::STRKEY
? ? ?*
? ? ?* @param idx index value
? ? ?* @return character at the index
? ? ?*/
? ? static inline char get_idx_char(const uint8_t idx) { return STRKEY[idx]; }

? ? /**
? ? ?* @brief Get the index of a character in the ::STRKEY
? ? ?*
? ? ?* @param ch character to search
? ? ?* @return index of character
? ? ?*/
? ? static inline uint8_t get_char_idx(const char ch) {
? ? ? ? size_t L = std::strlen(STRKEY);

? ? ? ? for (size_t idx = 0; idx <= L; idx++)
? ? ? ? ? ? if (STRKEY[idx] == ch)
? ? ? ? ? ? ? ? return idx;

? ? ? ? std::cerr << __func__ << ":" << __LINE__ << ": (" << ch
? ? ? ? ? ? ? ? ? << ") Should not reach here!\n";
? ? ? ? return 0;
? ? }

? ? /**
? ? ?* @brief Convenience function to perform block cipher operations. The
? ? ?* operations are identical for both encryption and decryption.
? ? ?*
? ? ?* @param text input text to encrypt or decrypt
? ? ?* @param key key for encryption or decryption
? ? ?* @return encrypted/decrypted output
? ? ?*/
? ? static const std::string codec(const std::string &text,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?const matrix<int> &key) {
? ? ? ? size_t text_len = text.length();
? ? ? ? size_t key_len = key.size();

? ? ? ? // length of output string must be a multiple of key_len
? ? ? ? // create output string and initialize with '\0' character
? ? ? ? size_t L2 = text_len % key_len == 0
? ? ? ? ? ? ? ? ? ? ? ? ? text_len
? ? ? ? ? ? ? ? ? ? ? ? : text_len + key_len - (text_len % key_len);
? ? ? ? std::string coded_text(L2, '\0');

? ? ? ? // temporary array for batch processing
? ? ? ? int i;
#ifdef _OPENMP
#pragma parallel omp for private(i)
#endif
? ? ? ? for (i = 0; i < L2 - key_len + 1; i += key_len) {
? ? ? ? ? ? std::valarray<uint8_t> batch_int(key_len);
? ? ? ? ? ? for (size_t j = 0; j < key_len; j++) {
? ? ? ? ? ? ? ? batch_int[j] = get_char_idx(text[i + j]);
? ? ? ? ? ? }

? ? ? ? ? ? batch_int = mat_mul(batch_int, key);

? ? ? ? ? ? for (size_t j = 0; j < key_len; j++) {
? ? ? ? ? ? ? ? coded_text[i + j] =
? ? ? ? ? ? ? ? ? ? STRKEY[batch_int[j]]; ?// get character at key
? ? ? ? ? ? }
? ? ? ? }

? ? ? ? return coded_text;
? ? }

? ? /**
? ? ?* Get matrix inverse using Row-transformations. Given matrix must
? ? ?* be a square and non-singular.
? ? ?* \returns inverse matrix
? ? ?**/
? ? template <typename T>
? ? static matrix<double> get_inverse(matrix<T> const &A) {
? ? ? ? // Assuming A is square matrix
? ? ? ? size_t N = A.size();

? ? ? ? matrix<double> inverse(N, std::valarray<double>(N));
? ? ? ? for (size_t row = 0; row < N; row++) {
? ? ? ? ? ? for (size_t col = 0; col < N; col++) {
? ? ? ? ? ? ? ? // create identity matrix
? ? ? ? ? ? ? ? inverse[row][col] = (row == col) ? 1.f : 0.f;
? ? ? ? ? ? }
? ? ? ? }

? ? ? ? if (A.size() != A[0].size()) {
? ? ? ? ? ? std::cerr << "A must be a square matrix!" << std::endl;
? ? ? ? ? ? return inverse;
? ? ? ? }

? ? ? ? // preallocate a temporary matrix identical to A
? ? ? ? matrix<double> temp(N, std::valarray<double>(N));
? ? ? ? for (size_t row = 0; row < N; row++) {
? ? ? ? ? ? for (size_t col = 0; col < N; col++)
? ? ? ? ? ? ? ? temp[row][col] = static_cast<double>(A[row][col]);
? ? ? ? }

? ? ? ? // start transformations
? ? ? ? for (size_t row = 0; row < N; row++) {
? ? ? ? ? ? for (size_t row2 = row; row2 < N && temp[row][row] == 0; row2++) {
? ? ? ? ? ? ? ? // this to ensure diagonal elements are not 0
? ? ? ? ? ? ? ? temp[row] = temp[row] + temp[row2];
? ? ? ? ? ? ? ? inverse[row] = inverse[row] + inverse[row2];
? ? ? ? ? ? }

? ? ? ? ? ? for (size_t col2 = row; col2 < N && temp[row][row] == 0; col2++) {
? ? ? ? ? ? ? ? // this to further ensure diagonal elements are not 0
? ? ? ? ? ? ? ? for (size_t row2 = 0; row2 < N; row2++) {
? ? ? ? ? ? ? ? ? ? temp[row2][row] = temp[row2][row] + temp[row2][col2];
? ? ? ? ? ? ? ? ? ? inverse[row2][row] =
? ? ? ? ? ? ? ? ? ? ? ? inverse[row2][row] + inverse[row2][col2];
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }

? ? ? ? ? ? if (temp[row][row] == 0) {
? ? ? ? ? ? ? ? // Probably a low-rank matrix and hence singular
? ? ? ? ? ? ? ? std::cerr << "Low-rank matrix, no inverse!" << std::endl;
? ? ? ? ? ? ? ? return inverse;
? ? ? ? ? ? }

? ? ? ? ? ? // set diagonal to 1
? ? ? ? ? ? double divisor = temp[row][row];
? ? ? ? ? ? temp[row] = temp[row] / divisor;
? ? ? ? ? ? inverse[row] = inverse[row] / divisor;
? ? ? ? ? ? // Row transformations
? ? ? ? ? ? for (size_t row2 = 0; row2 < N; row2++) {
? ? ? ? ? ? ? ? if (row2 == row)
? ? ? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? ? ? double factor = temp[row2][row];
? ? ? ? ? ? ? ? temp[row2] = temp[row2] - factor * temp[row];
? ? ? ? ? ? ? ? inverse[row2] = inverse[row2] - factor * inverse[row];
? ? ? ? ? ? }
? ? ? ? }

? ? ? ? return inverse;
? ? }

? ? static int modulo(int a, int b) {
? ? ? ? int ret = a % b;
? ? ? ? if (ret < 0)
? ? ? ? ? ? ret += b;
? ? ? ? return ret;
? ? }

?public:
? ? /**
? ? ?* @brief Generate encryption matrix of a given size. Larger size matrices
? ? ?* are difficult to generate but provide more security. Important conditions
? ? ?* are:
? ? ?* 1. matrix should be invertible
? ? ?* 2. determinant must not have any common factors with the length of
? ? ?* character key
? ? ?* There is no head-fast way to generate hte matrix under the given
? ? ?* numerical restrictions of the machine but the conditions added achieve
? ? ?* the goals. Bigger the matrix, greater is the probability of the matrix
? ? ?* being ill-defined.
? ? ?*
? ? ?* @param size size of matrix (typically \f$\text{size}\le10\f$)
? ? ?* @param limit1 lower limit of range of random elements (default=0)
? ? ?* @param limit2 upper limit of range of random elements (default=10)
? ? ?* @return Encryption martix
? ? ?*/
? ? static matrix<int> generate_encryption_key(size_t size, int limit1 = 0,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int limit2 = 10) {
? ? ? ? matrix<int> encrypt_key(size, std::valarray<int>(size));
? ? ? ? matrix<int> min_mat = encrypt_key;
? ? ? ? int mat_determinant = -1; ?// because matrix has only ints, the
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// determinant will also be an int
? ? ? ? int L = std::strlen(STRKEY);

? ? ? ? double dd;
? ? ? ? do {
? ? ? ? ? ? // keeping the random number range smaller generates better
? ? ? ? ? ? // defined matrices with more ease of cracking
? ? ? ? ? ? dd = rand_range(&encrypt_key, limit1, limit2);
? ? ? ? ? ? mat_determinant = static_cast<int>(dd);

? ? ? ? ? ? if (mat_determinant < 0)
? ? ? ? ? ? ? ? mat_determinant = (mat_determinant % L);
? ? ? ? } while (std::abs(dd) > 1e3 || ?// while ill-defined
? ? ? ? ? ? ? ? ?dd < 0.1 || ?// while singular or negative determinant
? ? ? ? ? ? ? ? ?!std::isfinite(dd) || ?// while determinant is not finite
? ? ? ? ? ? ? ? ?gcd(mat_determinant, L) != 1); ?// while no common factors
? ? ? ? // std::cout <<

? ? ? ? return encrypt_key;
? ? }

? ? /**
? ? ?* @brief Generate decryption matrix from an encryption matrix key.
? ? ?*
? ? ?* @param encrypt_key encryption key for which to create a decrypt key
? ? ?* @return Decryption martix
? ? ?*/
? ? static matrix<int> generate_decryption_key(matrix<int> const &encrypt_key) {
? ? ? ? size_t size = encrypt_key.size();
? ? ? ? int L = std::strlen(STRKEY);

? ? ? ? matrix<int> decrypt_key(size, std::valarray<int>(size));
? ? ? ? int det_encrypt = static_cast<int>(determinant_lu(encrypt_key));

? ? ? ? int mat_determinant = det_encrypt < 0 ? det_encrypt % L : det_encrypt;

? ? ? ? matrix<double> tmp_inverse = get_inverse(encrypt_key);
? ? ? ? double d2 = determinant_lu(decrypt_key);

? ? ? ? // find co-prime factor for inversion
? ? ? ? int det_inv = -1;
? ? ? ? for (int i = 0; i < L; i++) {
? ? ? ? ? ? if (modulo(mat_determinant * i, L) == 1) {
? ? ? ? ? ? ? ? det_inv = i;
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? }

? ? ? ? if (det_inv == -1) {
? ? ? ? ? ? std::cerr << "Could not find a co-prime for inversion\n";
? ? ? ? ? ? std::exit(EXIT_FAILURE);
? ? ? ? }

? ? ? ? mat_determinant = det_inv * det_encrypt;

? ? ? ? // perform modular inverse of encryption matrix
? ? ? ? int i;
#ifdef _OPENMP
#pragma parallel omp for private(i)
#endif
? ? ? ? for (i = 0; i < size; i++) {
? ? ? ? ? ? for (int j = 0; j < size; j++) {
? ? ? ? ? ? ? ? int temp = std::round(tmp_inverse[i][j] * mat_determinant);
? ? ? ? ? ? ? ? decrypt_key[i][j] = modulo(temp, L);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return decrypt_key;
? ? }

? ? /**
? ? ?* @brief Generate encryption and decryption key pair
? ? ?*
? ? ?* @param size size of matrix key (typically \f$\text{size}\le10\f$)
? ? ?* @param limit1 lower limit of range of random elements (default=0)
? ? ?* @param limit2 upper limit of range of random elements (default=10)
? ? ?* @return std::pair<matrix<int>, matrix<int>> encryption and decryption
? ? ?* keys as a pair
? ? ?*
? ? ?* @see ::generate_encryption_key
? ? ?*/
? ? static std::pair<matrix<int>, matrix<int>> generate_keys(size_t size,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int limit1 = 0,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int limit2 = 10) {
? ? ? ? matrix<int> encrypt_key = generate_encryption_key(size);
? ? ? ? matrix<int> decrypt_key = generate_decryption_key(encrypt_key);
? ? ? ? double det2 = determinant_lu(decrypt_key);
? ? ? ? while (std::abs(det2) < 0.1 || std::abs(det2) > 1e3) {
? ? ? ? ? ? encrypt_key = generate_encryption_key(size, limit1, limit2);
? ? ? ? ? ? decrypt_key = generate_decryption_key(encrypt_key);
? ? ? ? ? ? det2 = determinant_lu(decrypt_key);
? ? ? ? }
? ? ? ? return std::make_pair(encrypt_key, decrypt_key);
? ? }

? ? /**
? ? ?* @brief Encrypt a given text using a given key
? ? ?*
? ? ?* @param text string to encrypt
? ? ?* @param encrypt_key ?key for encryption
? ? ?* @return encrypted text
? ? ?*/
? ? static const std::string encrypt_text(const std::string &text,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const matrix<int> &encrypt_key) {
? ? ? ? return codec(text, encrypt_key);
? ? }

? ? /**
? ? ?* @brief Decrypt a given text using a given key
? ? ?*
? ? ?* @param text string to decrypt
? ? ?* @param decrypt_key ?key for decryption
? ? ?* @return decrypted text
? ? ?*/
? ? static const std::string decrypt_text(const std::string &text,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const matrix<int> &decrypt_key) {
? ? ? ? return codec(text, decrypt_key);
? ? }
};

} ?// namespace ciphers

/**
?* @brief Self test 1 - using 3x3 randomly generated key
?*
?* @param text string to encrypt and decrypt
?*/
void test1(const std::string &text) {
? ? // std::string text = "Hello world!";
? ? std::cout << "======Test 1 (3x3 key) ======\nOriginal text:\n\t" << text
? ? ? ? ? ? ? << std::endl;

? ? std::pair<matrix<int>, matrix<int>> p =
? ? ? ? ciphers::HillCipher::generate_keys(3, 0, 100);
? ? matrix<int> ekey = p.first;
? ? matrix<int> dkey = p.second;

? ? // matrix<int> ekey = {{22, 28, 25}, {5, 26, 15}, {14, 18, 9}};
? ? // std::cout << "Encryption key: \n" << ekey;
? ? std::string gibberish = ciphers::HillCipher::encrypt_text(text, ekey);
? ? std::cout << "Encrypted text:\n\t" << gibberish << std::endl;

? ? // matrix<int> dkey = ciphers::HillCipher::generate_decryption_key(ekey);
? ? // std::cout << "Decryption key: \n" << dkey;
? ? std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey);
? ? std::cout << "Reconstruct text:\n\t" << txt_back << std::endl;

? ? std::ofstream out_file("hill_cipher_test1.txt");
? ? out_file << "Block size: " << ekey.size() << "\n";
? ? out_file << "Encryption Key:\n" << ekey;
? ? out_file << "\nDecryption Key:\n" << dkey;
? ? out_file.close();

? ? assert(txt_back == text);
? ? std::cout << "Passed :)\n";
}

/**
?* @brief Self test 2 - using 8x8 randomly generated key
?*
?* @param text string to encrypt and decrypt
?*/
void test2(const std::string &text) {
? ? // std::string text = "Hello world!";
? ? std::cout << "======Test 2 (8x8 key) ======\nOriginal text:\n\t" << text
? ? ? ? ? ? ? << std::endl;

? ? std::pair<matrix<int>, matrix<int>> p =
? ? ? ? ciphers::HillCipher::generate_keys(8, 0, 3);
? ? matrix<int> ekey = p.first;
? ? matrix<int> dkey = p.second;

? ? std::string gibberish = ciphers::HillCipher::encrypt_text(text, ekey);
? ? std::cout << "Encrypted text:\n\t" << gibberish << std::endl;

? ? std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey);
? ? std::cout << "Reconstruct text:\n\t" << txt_back << std::endl;

? ? std::ofstream out_file("hill_cipher_test2.txt");
? ? out_file << "Block size: " << ekey.size() << "\n";
? ? out_file << "Encryption Key:\n" << ekey;
? ? out_file << "\nDecryption Key:\n" << dkey;
? ? out_file.close();

? ? assert(txt_back.compare(0, text.size(), text) == 0);
? ? std::cout << "Passed :)\n";
}

/** Main function */
int main() {
? ? std::srand(std::time(nullptr));
? ? std::cout << "Key dictionary: (" << std::strlen(ciphers::STRKEY) << ")\n\t"
? ? ? ? ? ? ? << ciphers::STRKEY << "\n";

? ? std::string text = "This is a simple text with numb3r5 and exclamat!0n.";

? ? test1(text);
? ? test2(text);

? ? return 0;
}

示例二:

用C++实现的简单示例:

#include <iostream>
#include <vector>

std::string encrypt(const std::string& plaintext, const std::vector<std::vector<int>>& keyMatrix) {
? ? std::string ciphertext;
? ? int keySize = keyMatrix.size();
? ? int blockSize = keySize;
? ? int paddingSize = keySize - (plaintext.length() % keySize);

? ? // 添加填充字符
? ? for (int i = 0; i < paddingSize; i++) {
? ? ? ? plaintext += 'X';
? ? }

? ? // 对明文进行分块加密
? ? for (int i = 0; i < plaintext.length(); i += blockSize) {
? ? ? ? std::vector<int> block;
? ? ? ? for (int j = i; j < i + blockSize; j++) {
? ? ? ? ? ? block.push_back(plaintext[j] - 'A');
? ? ? ? }

? ? ? ? // 使用密钥矩阵进行乘法运算
? ? ? ? std::vector<int> result(keySize, 0);
? ? ? ? for (int k = 0; k < keySize; k++) {
? ? ? ? ? ? for (int l = 0; l < keySize; l++) {
? ? ? ? ? ? ? ? result[k] += keyMatrix[k][l] * block[l];
? ? ? ? ? ? }
? ? ? ? ? ? result[k] %= 26; // 取模操作,映射到字母表范围内
? ? ? ? ? ? ciphertext += static_cast<char>(result[k] + 'A');
? ? ? ? }
? ? }

? ? return ciphertext;
}

std::string decrypt(const std::string& ciphertext, const std::vector<std::vector<int>>& keyMatrix) {
? ? std::string plaintext;
? ? int keySize = keyMatrix.size();
? ? int blockSize = keySize;

? ? // 对密文进行分块解密
? ? for (int i = 0; i < ciphertext.length(); i += blockSize) {
? ? ? ? std::vector<int> block;
? ? ? ? for (int j = i; j < i + blockSize; j++) {
? ? ? ? ? ? block.push_back(ciphertext[j] - 'A');
? ? ? ? }

? ? ? ? // 使用逆矩阵进行乘法运算
? ? ? ? std::vector<int> result(keySize, 0);
? ? ? ? for (int k = 0; k < keySize; k++) {
? ? ? ? ? ? for (int l = 0; l < keySize; l++) {
? ? ? ? ? ? ? ? result[k] += keyMatrix[l][k] * block[l];
? ? ? ? ? ? }
? ? ? ? ? ? result[k] %= 26; // 取模操作,映射到字母表范围内
? ? ? ? ? ? plaintext += static_cast<char>(result[k] + 'A');
? ? ? ? }
? ? }

? ? return plaintext;
}

int main() {
? ? std::vector<std::vector<int>> keyMatrix = {
? ? ? ? {3, 2},
? ? ? ? {5, 7}
? ? };
? ? std::string plaintext = "HELLO";
? ? std::string ciphertext = encrypt(plaintext, keyMatrix);
? ? std::string decryptedText = decrypt(ciphertext, keyMatrix);

? ? std::cout << "Plaintext: " << plaintext << std::endl;
? ? std::cout << "Ciphertext: " << ciphertext << std::endl;
? ? std::cout << "Decrypted text: " << decryptedText << std::endl;

? ? return 0;
}
????????这个示例使用2x2的矩阵作为密钥,对明文进行加密和解密操作。你可以根据需要修改矩阵的大小和明文的内容来进行扩展和测试。请注意,此示例中仅使用大写字母,并且未处理其他特殊字符。对于更复杂的需求,请根据需要修改实现。

文章来源:https://blog.csdn.net/hefeng_aspnet/article/details/135521478
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。