密码学学习记录(二)

密码学学习记录(二)

在之前的记录中,主要说明了常见的几种密码的原理

本次记录主要是对前面加密的核心代码实现(使用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加密算法通过多轮迭代的变换过程实现数据的安全加密:首先生成扩展密钥,随后进行初始轮密钥加;接着循环执行字节替换、行移位、列混淆和轮密钥加操作(最后一轮省略列混淆);最终输出密文。整个过程巧妙结合了非线性变换、线性混合和密钥加操作,在保证加密强度的同时维持了算法效率,成为当今最广泛使用的对称加密标准之一。

posted @ 2025-09-19 22:45  loreflux  阅读(75)  评论(0)    收藏  举报