AES 算法的 CTR 模式演示

基于 AES 算法的 CTR 工作模式演示程序实现
基本要求:
1、如图 4 可视化实现 CBC 工作模式。图 4 的分组加密和分组解密可以直接
调用编程语言 DES 算法实现提供的接口函数实现,不需要自行编写密码算法。
但不能直接选择调用编程语言 DES-CBC 模式的接口直接实现。
2、图形化界面设计要求:
(1)采用图形化界面演示 CBC 模式的加密和解密运行演示过程(参考图 5
所示。还可以更加详细,比如输出界面中初始向量和明文分组对应字符的 16 进
制数值,以及异或之后的结果),至少加密和解密 4 组明文,若最后 1 组不够分
组长度,尾部需要自行进行填充,填充方法可参考密码学教材选择相关填充方法。
(2)加密算法密钥和初始变量 IV 的输入界面.
说明:选择其他分组密码算法和密码工作模式要求类似,比如 3DES、AES
算法;密码工作模式除了 CBC 模式外,还可以选择 OFB,CFB,CRT 其他 3 种
工作模式,其他工作模式的加密和解密流程可以参考相关教材。具体功能实现要
求类似基于 DES 算法的 CBC 演示程序实现要求和界面设计。

img

img

高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。本文将介绍AES的具体流程,以及c++实现,并且实现了CBC和CTR模式的解密函数。

1.关于AES(高级加密标准):在这里一个分组为128bit(16byte),密钥也是128bit(16byte),密钥要先通过密钥扩展,具体过程如图:

img


然后加轮密钥(第一轮之前),之后再经过每一轮的比特代换,行移位,列混合和加轮密钥,每个分组一共10轮,如下图所示的加密过程:

img


解密则是相逆的过程,如上图所示,首先是密钥扩展,先加轮密钥,然后在经过每一轮的行移位反演,位代换反演,加轮密钥和列混合反演,每个分组一共进行10轮。还要注意的一点是在每一轮里的结构是状态(state),是4*4的矩阵。


#include <stdio.h>
#include <stdlib.h>
#include "AES.h"
 
Byte *keyExpansion(Byte *cipherKey) {
    Byte *expandedKey = (Byte *)malloc(sizeof(Byte) * BYTES_IN_EXPANDED_KEY);
    
    // get the key of the first round
    for(int i = 0; i < BYTES_IN_ROUND; i++)
        expandedKey[i] = cipherKey[i];
    
    // get the key of other rounds
    Byte *temporary_word = (Byte *)malloc(sizeof(Byte) * BYTES_IN_WORD);
    for(int i = 1; i <= NUM_OF_ROUNDS; i++) {
        // calculate the temporary word
        for(int j = 0; j < BYTES_IN_WORD; j++)
            temporary_word[j] = expandedKey[i * BYTES_IN_ROUND - BYTES_IN_WORD + j];
        rotateWord(temporary_word, 1);
        substitutionWord(temporary_word);
        temporary_word[0] = (temporary_word[0] ^ roundConstant[i - 1]);
               
        // get the key of this round
        for(int j = 0; j < BYTES_IN_WORD; j++)
            expandedKey[i * BYTES_IN_ROUND + j] = temporary_word[j]
                ^ expandedKey[(i - 1) * BYTES_IN_ROUND + j];
        for(int j = 1; j < WORD_IN_ROUND; j++) {
            for(int k = 0; k < BYTES_IN_WORD; k++) {
                expandedKey[i * BYTES_IN_ROUND + j * BYTES_IN_WORD + k] =
                    expandedKey[i * BYTES_IN_ROUND + (j - 1) * BYTES_IN_WORD + k] ^
                    expandedKey[(i - 1) * BYTES_IN_ROUND + j * BYTES_IN_WORD + k];
            }
        }
    }
    free(temporary_word);
    
    return expandedKey;
}
 
void AES_Encryption(Byte state[][BYTES_IN_WORD], Byte* key) {
    // Round 0: addRoundKey
    addRoundKey(state, key, 0);
    
    // Round 1~9: substitutionWord + shiftRow + mixColumn + addRoundKey
    for(int i = 1; i < 10; i++) {
        substitutionWord(state);
        shiftRow(state);
        mixColumn(state);
        addRoundKey(state, key, i);
    }
    
    // Round 10: substitutionWord + shiftRow + addRoundKey
    substitutionWord(state);
    shiftRow(state);
    addRoundKey(state, key, 10);
}
 
void AES_Decryption(Byte state[][BYTES_IN_WORD], Byte* key) {
    // Inv round 10: addRoundKey + shiftRowInv + substitutionWordInv
    addRoundKey(state, key, 10);
    shiftRowInv(state);
    substitutionWordInv(state);
    
    // Inv round 9~1: addRoundKey + mixColumnInv + shiftRowInv + substitutionWordInv
    for(int i = 9; i > 0; i--) {
        addRoundKey(state, key, i);
        mixColumnInv(state);
        shiftRowInv(state);
        substitutionWordInv(state);
    }
    
    // Inv round 0: addRoundKey
    addRoundKey(state, key, 0);
}
 
void rotateWord(Byte *word, int offset) {
    Byte *temp = (Byte *)malloc(sizeof(Byte) * BYTES_IN_WORD);
    for(int i = 0; i < BYTES_IN_WORD; i++)
        temp[(i + BYTES_IN_WORD - offset) % 4] = word[i];
    for(int i = 0; i < BYTES_IN_WORD; i++)
        word[i] = temp[i];
    free(temp);
}
 
void substitutionWord(Byte *word) {
    for(int i = 0; i < BYTES_IN_WORD; i++)
        word[i] = sBox[word[i] / 16][word[i] % 16];
}
 
void substitutionWord(Byte state[][BYTES_IN_WORD]) {
    for(int i = 0; i < BYTES_IN_WORD; i++)
        for(int j = 0; j < BYTES_IN_WORD; j++)
            state[i][j] = sBox[state[i][j] / 16][state[i][j] % 16];
}
 
void substitutionWordInv(Byte state[][BYTES_IN_WORD]) {
    for(int i = 0; i < BYTES_IN_WORD; i++)
        for(int j = 0; j < BYTES_IN_WORD; j++)
            state[i][j] = sBoxInv[state[i][j] / 16][state[i][j] % 16];
}
 
void shiftRow(Byte state[][BYTES_IN_WORD]) {
    for(int i = 0; i < BYTES_IN_WORD; i++)
        rotateWord(state[i], i);
}
 
void shiftRowInv(Byte state[][BYTES_IN_WORD]) {
    for(int i = 1; i < BYTES_IN_WORD; i++)
        rotateWord(state[i], 4 - i);
}
 
void mixColumn(Byte state[][BYTES_IN_WORD]) {
    Byte *temp = (Byte *)malloc(sizeof(Byte) * BYTES_IN_WORD);
    for(int i = 0; i < BYTES_IN_WORD; i++) {
        for(int j = 0; j < BYTES_IN_WORD; j++)
            temp[j] = state[j][i];
        for(int j = 0; j < BYTES_IN_WORD; j++) {
            state[j][i] = 0;
            for(int k = 0; k < BYTES_IN_WORD; k++)
                state[j][i] = (state[j][i] ^ GF_Multiplication(constantMatrix[j][k], temp[k]));
        }
    }
    free(temp);
}
 
void mixColumnInv(Byte state[][BYTES_IN_WORD]) {
    Byte *temp = (Byte *)malloc(sizeof(Byte) * BYTES_IN_WORD);
    for(int i = 0; i < BYTES_IN_WORD; i++) {
        for(int j = 0; j < BYTES_IN_WORD; j++)
            temp[j] = state[j][i];
        for(int j = 0; j < BYTES_IN_WORD; j++) {
            state[j][i] = 0;
            for(int k = 0; k < BYTES_IN_WORD; k++)
                state[j][i] = (state[j][i] ^ GF_Multiplication(constantMatrixInv[j][k], temp[k]));
        }
    }
    free(temp);
}
 
Byte GF_Multiplication(Byte a, Byte b) {
    bool *temp = (bool *)malloc(sizeof(bool) * BIT_IN_BYTE * 2);
    for(int i = 0; i < BIT_IN_BYTE; i++) {
        temp[i] = b % 2;
        b /= 2;
    }
    
    short result = 0;
    for(int i = 0; i < BIT_IN_BYTE; i++) {
        result = result ^ ((temp[i] * a) << i);
    }
    
    int count = 0;
    int temp_result = result;
    for(int i = 0; i < BIT_IN_BYTE * 2; i++) {
        temp[count++] = temp_result % 2;
        temp_result /= 2;
    }
    for(int i = BIT_IN_BYTE; i < BIT_IN_BYTE * 2; i++)
        if(temp[i] == 1)
            result = result ^ GF_constant[i - BIT_IN_BYTE];
 
    free(temp);
    return (Byte)result;
}
 
void addRoundKey(Byte state[][BYTES_IN_WORD], Byte* key, int round) {
    for(int i = 0; i < BYTES_IN_WORD; i++)
        for(int j = 0; j < BYTES_IN_WORD; j++)
            state[j][i] = (state[j][i] ^ key[round * BYTES_IN_ROUND + i * 4 + j]);
}
 
void printState(Byte state[][BYTES_IN_WORD]) {
    for(int i = 0; i < BYTES_IN_WORD; i++) {
        for(int j = 0; j < BYTES_IN_WORD; j++)
            printf("%02X ", state[i][j]);
        printf("\n");
    }
    printf("\n");
}

来源:
Fancy_ruanruan