密码学学习记录(二)
密码学学习记录(二)
在之前的记录中,主要说明了常见的几种密码的原理
本次记录主要是对前面加密的核心代码实现(使用C++)
经典密码算法
恺撒密码
很简单的加密算法,对每个字母进行偏移就行了
void CaesarEncrypt(char* str,int offset) {
int len = strlen(str);
for (size_t i = 0; i < len; i++)
{
if (str[i] >= 'A' && str[i] <= 'Z') {
str[i] = ((int)(str[i]) + offset - (int)'A' + 26) % 26 + (int)'A';
}
else if (str[i] >= 'a' && str[i] <= 'z') {
str[i] = ((int)(str[i]) + offset - (int)'a' + 26) % 26 + (int)'a';
}
}
}
当然,汉字也是一种编码,也可以使用恺撒密码的算法进行加密
// #include <codecvt>
// GBK -> UTF-16(Windows 下 wchar_t 是 UTF-16)
wstring_convert<codecvt_byname<wchar_t, char, mbstate_t>> conv(new codecvt_byname<wchar_t, char, mbstate_t>("chs"));
wstring wstr = conv.from_bytes(str);
for (size_t i = 0; i < wstr.size(); i++) {
if (wstr[i] >= L'一' && wstr[i] <= L'龥') {
wstr[i] = (wstr[i] - L'一' + offset) % (L'龥' - L'一' + 1) + L'一';
}
}
// UTF-16 -> GBK
string output = conv.to_bytes(wstr);
解密只需要反向即可
简单替换密码
给出一个替换表,在查找到相同字符后进行替换即可
// #include <unordered_map>
const string alphabet = "abcdefghijklmnopqrstuvwxyz";
const string encrypted_alphabet = "bcdefghijklmnopqrstuvwxyza";
unordered_map<char, char> encryptionMap;
// 初始化映射
for (int i = 0; i < alphabet.length(); i++) {
encryptionMap[alphabet[i]] = encrypted_alphabet[i];
}
// 加密算法
string encrypt(string plaintext) {
string ciphertext = "";
for (char c : plaintext) {
if (encryptionMap.find(tolower(c)) != encryptionMap.end()) {
ciphertext += encryptionMap[tolower(c)];
}
else {
ciphertext += c;
}
}
return ciphertext;
}
解密只需要把对应的替换表交换即可
流密码
比特序列XOR
对每个字的二进制和密钥进行异或运算得到密文,再次进行异或得到明文
#include <iostream>
#include <string>
#include <bitset>
#include <vector>
#include <algorithm>
using namespace std;
// 函数声明
string textToBinary(const string& text);
string binaryToText(const string& binaryStr);
string generateKey(size_t length);
string xorEncryptDecrypt(const string& data, const string& key);
void displayBinary(const string& binaryStr, const string& title = "二进制表示");
int main() {
string input, key;
int choice;
cout << "文本转二进制及XOR加密工具" << endl;
cout << "========================" << endl;
cout << "请输入文本(可以包含字母、汉字或其他字符): ";
getline(cin, input);
if (input.empty()) {
cout << "输入不能为空!" << endl;
return 1;
}
// 转换为二进制并显示
string binaryData = textToBinary(input);
displayBinary(binaryData, "原始二进制数据");
cout << "\n请选择操作:" << endl;
cout << "1. 仅显示二进制" << endl;
cout << "2. XOR加密" << endl;
cout << "3. XOR解密" << endl;
cout << "请选择 (1-3): ";
cin >> choice;
cin.ignore(); // 清除输入缓冲区
if (choice == 1) {
// 仅显示二进制,不需要进一步操作
return 0;
}
if (choice == 2 || choice == 3) {
cout << "请输入加密密钥(或留空随机生成): ";
getline(cin, key);
if (key.empty()) {
// 生成与数据长度相同的随机密钥
key = generateKey(binaryData.length());
cout << "生成的随机密钥: " << key << endl;
}
// 确保密钥长度与数据长度相同
while (key.length() < binaryData.length()) {
key += key; // 重复密钥直到足够长
}
key = key.substr(0, binaryData.length()); // 截取到相同长度
// 执行XOR操作
string result = xorEncryptDecrypt(binaryData, key);
if (choice == 2) {
displayBinary(result, "加密后的二进制数据");
// 将加密后的二进制转换回文本(可能包含不可打印字符)
string encryptedText = binaryToText(result);
cout << "加密后的文本(可能不可读): " << encryptedText << endl;
}
else {
displayBinary(result, "解密后的二进制数据");
// 将解密后的二进制转换回文本
string decryptedText = binaryToText(result);
cout << "解密后的文本: " << decryptedText << endl;
}
}
else {
cout << "无效的选择!" << endl;
return 1;
}
return 0;
}
// 将文本转换为二进制表示
string textToBinary(const string& text) {
string binaryStr;
for (char c : text) {
// 将每个字符转换为其二进制表示(8位)
bitset<8> bits(static_cast<unsigned char>(c));
binaryStr += bits.to_string();
}
return binaryStr;
}
// 将二进制字符串转换回文本
string binaryToText(const string& binaryStr) {
string text;
// 确保二进制字符串长度是8的倍数
size_t len = binaryStr.length();
if (len % 8 != 0) {
throw invalid_argument("二进制字符串长度必须是8的倍数");
}
// 每8位转换为一个字符
for (size_t i = 0; i < len; i += 8) {
string byte = binaryStr.substr(i, 8);
bitset<8> bits(byte);
text += static_cast<char>(bits.to_ulong());
}
return text;
}
// 生成随机密钥
string generateKey(size_t length) {
string key;
srand(static_cast<unsigned int>(time(nullptr)));
for (size_t i = 0; i < length; i++) {
key += (rand() % 2) ? '1' : '0';
}
return key;
}
// XOR加密/解密函数
string xorEncryptDecrypt(const string& data, const string& key) {
if (data.length() != key.length()) {
throw invalid_argument("数据和密钥长度必须相同");
}
string result;
for (size_t i = 0; i < data.length(); i++) {
result += (data[i] == key[i]) ? '0' : '1';
}
return result;
}
// 格式化显示二进制结果
void displayBinary(const string& binaryStr, const string& title) {
cout << "\n" << title << ": " << endl;
cout << "==========================================" << endl;
// 每8位一组显示(一个字节)
for (size_t i = 0; i < binaryStr.length(); i++) {
cout << binaryStr[i];
if ((i + 1) % 8 == 0) {
cout << " ";
}
if ((i + 1) % 32 == 0) {
cout << endl;
}
}
cout << "\n==========================================" << endl;
}
可以看到,加密和解密是同一个函数
一次性密码本
密钥要和明文长度相同
// 加密
string encryptMessage(string plaintext, string key) {
string ciphertext = "";
for (int i = 0; i < plaintext.length(); i++) {
char encryptedChar = (plaintext[i] + key[i]) % 128;
ciphertext += encryptedChar;
}
return ciphertext;
}
// 解密
string decryptMessage(string ciphertext, string key) {
string plaintext = "";
for (int i = 0; i < ciphertext.length(); i++) {
char decryptedChar = (ciphertext[i] - key[i] + 128) % 128;
plaintext += decryptedChar;
}
return plaintext;
}
加密原理很简单:
- 对明文的每个字符,将其ASCII码值与密钥对应位置的字符ASCII码值相加
- 使用模128运算(
% 128)确保结果在0-127范围内(标准ASCII字符集范围) - 将结果转换回字符并添加到密文中
对称密码
DES
参考DES对称加密算法详解和c++代码实现(带样例和详细的中间数据) - 西*风 - 博客园
string encrypt(string str1)
{
//第一步:明文初始置换 64->64
str1 = plaintext_initial_permutation(str1);
cout << "明文初始置换结果(64->64):" << str1 << endl << endl;
//第二步:数据分组
string left = str1.substr(0, 32);
string right = str1.substr(32, 32);
cout << "L0:" << left << endl;
cout << "R0:" << right << endl << endl;
string newleft;
//第三步:16轮迭代
for (int i = 1; i <= 16; i++)
{
cout << "第" << i << "次迭代" << endl;
newleft = right;
right = XOR(left, f(right, Keys[i]));
left = newleft;
cout << "L[" << i << "]:" << left << endl;
cout << "R[" << i << "]:" << right << endl << endl;
}
//第四步:合并数据 注意位R16L16
string rs = right + left;
cout << "R16L16:" << rs << endl << endl;
//结尾置换
rs = final_permutation(rs);
cout << "最终置换结果:" << rs << endl << endl;
return rs;
}
三重DES
本质上是对原有DES加密过程的三次重复应用
由于3DES是基于DES算法实现的,OpenSSL库提供了DES算法的实现,因此我们可以利用OpenSSL库来简化3DES的实现过程
// #include <openssl/des.h>
// 3DES加密函数
// 使用第一个密钥对输入数据进行DES加密,然后使用第二个密钥对结果进行DES解密,最后使用第三个密钥再次对解密结果进行DES加密
void tripleDesEncrypt(const unsigned char *input, unsigned char *output, const DES_key_schedule &key1,
const DES_key_schedule &key2, const DES_key_schedule &key3) {
unsigned char temp[8];
DES_ecb_encrypt((DES_cblock*)input, (DES_cblock*)temp, &key1, DES_ENCRYPT);
DES_ecb_encrypt((DES_cblock*)temp, (DES_cblock*)temp, &key2, DES_DECRYPT);
DES_ecb_encrypt((DES_cblock*)temp, (DES_cblock*)output, &key3, DES_ENCRYPT);
}
// 3DES解密函数
// 使用第三个密钥对密文进行DES解密,然后使用第二个密钥对解密结果进行DES加密,最后使用第一个密钥对加密结果进行DES解密,恢复原始的明文
void tripleDesDecrypt(const unsigned char *input, unsigned char *output, const DES_key_schedule &key1,
const DES_key_schedule &key2, const DES_key_schedule &key3) {
unsigned char temp[8];
DES_ecb_encrypt((DES_cblock*)input, (DES_cblock*)temp, &key3, DES_DECRYPT);
DES_ecb_encrypt((DES_cblock*)temp, (DES_cblock*)temp, &key2, DES_ENCRYPT);
DES_ecb_encrypt((DES_cblock*)temp, (DES_cblock*)output, &key1, DES_DECRYPT);
AES
// s 盒, 用于密钥生成和加密时的字节代换
static const int S[16][16] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
// 逆s 盒, 用于在解密时的 逆字节变换
static const int S1[16][16] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
// 常量轮值表
static const long long Rcon[10] = {
0x01000000, 0x02000000,
0x04000000, 0x08000000,
0x10000000, 0x20000000,
0x40000000, 0x80000000,
0x1b000000, 0x36000000
};
密钥拓展
vector<string> expand_encryption_key(string& encryption_key)
{
vector<string> segmented_key = segment_key(encryption_key);
int total_rounds = 40;
for (int round_num = 0; round_num < total_rounds; ++round_num)
{
int current_index = 4 + round_num;
string previous_key = segmented_key[current_index - 1];
if (current_index % 4 == 0)
{
int t_round = current_index / 4 - 1;
previous_key = transformation(previous_key, t_round);
}
string new_key = xor_strings(previous_key, segmented_key[current_index - 4]);
segmented_key.push_back(new_key);
}
return segmented_key;
}
轮密钥加
// 初始轮密钥加操作
vector<string> process_initial_round(vector<string>& input_blocks, vector<string>& round_keys)
{
for (int block_idx = 0; block_idx < 4; ++block_idx)
{
input_blocks[block_idx] = xor_hex_strings(input_blocks[block_idx], round_keys[block_idx]);
}
return input_blocks;
}
// 十六进制字符串异或运算函数
string xor_hex_strings(string hex_str1, string hex_str2)
{
long long value1 = hex_string_to_long(hex_str1);
long long value2 = hex_string_to_long(hex_str2);
long long result = value1 ^ value2;
// 将结果转换回字符串
string result_str = long_to_hex_string(result);
// 确保结果长度为8个字符,不足则前补0
while (result_str.length() < 8)
{
result_str = "0" + result_str;
}
return result_str;
}
字节代换
// 字节替换操作实现
string perform_byte_substitution(string& input_word)
{
int word_length = input_word.length();
string substituted_result = "";
for (int char_index = 0; char_index < word_length; char_index += 2)
{
// 获取当前字节的高4位和低4位
int high_nibble = char_to_hex_value(input_word[char_index]);
int low_nibble = char_to_hex_value(input_word[char_index + 1]);
// 从S盒中查找替换值
int substituted_value = SUBSTITUTION_BOX[high_nibble][low_nibble];
// 将数值转换为十六进制字符串
string hex_string = value_to_hex_string(substituted_value);
// 确保始终为2位十六进制表示
while (hex_string.length() < 2)
{
hex_string = "0" + hex_string;
}
// 添加到结果字符串
substituted_result += hex_string;
}
return substituted_result;
}
行移位
// 执行行移位变换
vector<string> shift_rows(vector<string>& state_matrix)
{
vector<string> shifted_matrix = state_matrix;
// 注意:字符串数组中的每个元素对应一列,因此需要对列进行操作来实现行移位
// 每个字节由两个十六进制字符表示,因此需要同时移动两个字符
for (int row = 0; row < 4; ++row)
{
int char_position = row * 2;
// 对每一列应用循环移位
for (int col = 0; col < 4; ++col)
{
int target_col = (col + row) % 4;
shifted_matrix[col][char_position] = state_matrix[target_col][char_position];
shifted_matrix[col][char_position + 1] = state_matrix[target_col][char_position + 1];
}
}
return shifted_matrix;
}
列混淆
// 执行列混淆变换
vector<string> mix_columns(vector<string>& state_matrix)
{
vector<string> mixed_matrix = state_matrix;
// 对状态矩阵的每一列进行处理
for (int column = 0; column < 4; ++column)
{
// 将列数据拆分为4个字节
auto byte_blocks = split_into_bytes(state_matrix[column]);
// 将字节转换为数值
int byte0 = hex_to_int(byte_blocks[0]);
int byte1 = hex_to_int(byte_blocks[1]);
int byte2 = hex_to_int(byte_blocks[2]);
int byte3 = hex_to_int(byte_blocks[3]);
// 应用列混淆变换公式
int transformed_byte0 = galois_multiply(byte0, 2) ^ galois_multiply(byte1, 3) ^ byte2 ^ byte3;
int transformed_byte1 = byte0 ^ galois_multiply(byte1, 2) ^ galois_multiply(byte2, 3) ^ byte3;
int transformed_byte2 = byte0 ^ byte1 ^ galois_multiply(byte2, 2) ^ galois_multiply(byte3, 3);
int transformed_byte3 = galois_multiply(byte0, 3) ^ byte1 ^ byte2 ^ galois_multiply(byte3, 2);
// 将结果转换回十六进制并组合
mixed_matrix[column] =
int_to_hex_byte(transformed_byte0) +
int_to_hex_byte(transformed_byte1) +
int_to_hex_byte(transformed_byte2) +
int_to_hex_byte(transformed_byte3);
}
return mixed_matrix;
}
AES加密算法通过多轮迭代的变换过程实现数据的安全加密:首先生成扩展密钥,随后进行初始轮密钥加;接着循环执行字节替换、行移位、列混淆和轮密钥加操作(最后一轮省略列混淆);最终输出密文。整个过程巧妙结合了非线性变换、线性混合和密钥加操作,在保证加密强度的同时维持了算法效率,成为当今最广泛使用的对称加密标准之一。

浙公网安备 33010602011771号