逆向工程实验——pre8(密码分析、RSA和AES混合加密方案)

实验目录

  • 1.阅读
  • 2.阅读
  • 3.Cryptanalysis Hacking Puzzles
    • (1)Cryptanalysis Hacking Puzzles — Part 1
    • (2)Cryptanalysis Hacking Puzzles — Part 2
  • 4. (选做)Hybrid Encryption I

1.阅读

对某病毒的一次完全逆向分析之旅
https://bbs.pediy.com/thread-174633.htm

2.阅读

CVE-2017-7269:IIS6.0远程代码执行漏洞逆向分析记录
https://bbs.pediy.com/thread-216967.htm

3.Cryptanalysis Hacking Puzzles

Cryptanalysis Hacking Puzzles — Part 1
https://www.mysterytwisterc3.org/en/challenges/level-i/cryptanalysis-hacking-puzzles-part-1

Cryptanalysis Hacking Puzzles — Part 2
https://www.mysterytwisterc3.org/en/challenges/level-i/cryptanalysis-hacking-puzzles-part-2

(1)Cryptanalysis Hacking Puzzles — Part 1

Challenge (1/3)
This is an imaginary, but possible scenario, where a person A needs to secure the transport of a message to another person B.
A decided not to send the message in clear and to increase the security by using two different human messengers.
A prepared a paper with the following “cipher” text and gave it to the rst messenger:
d910e60aa257c600edcbda550c9e39591b32dab5f8710f5f073b5927f4b386a723d61c5b969d644ea04a17e668e305e8609a4ca1875f41d97e404c6cd8eafb5c3a316f10311acb88e7d715fa3f7da7f689357af90107a102666c7d7631204d7e0e74757f692e
Challenge (2/3)
A then prepared another paper with the following “cipher” text and gave it to the second messenger:
dc22ea5eb95ad54cee85cd1c5d89255f5e7cd4e1ab6602581b7a593ce284a43493551984d4e66d45bc0f02b9ec22e313f57dd449a7e5c01d47cb360d436dc1a3fb57743d3b17201c9f93f7d743fc277da5f4cb4d04d06661dc6368616c6c656e676540696e746567
When the rst messenger returned, A asked him to deliver a third message (this time in plain text) to the same destination (B):
either one, but not both nor none
So the receiver B got 3 messages, which all have to be connected with the same operator.
Challenge (3/3)
The solution consists of the last word of the sought-after plaintext before the signature. Please enter the solution in lower-case letters.
Hint
The third message is another operand and in addition its content describes with which operator all three messages have to be connected.

挑战(1/3)
这是一个虚构的但可能的场景,其中一个人a需要确保消息传输到另一个人B。
A决定不发送清晰的信息,并通过使用两个不同的人类信使来增加安全性。
A准备了一份文件,上面有下面的密文文本,并交给了第一信使:
d910e60aa257c600edcbda550c9e39591b32dab5f8710f5f073b5927f4b386a723d61c5b969d644ea04a17e668e305e8609a4ca1875f41d97e404c6cd8eafb5c3a316f10311acb88e7d715fa3f7da7f689357af90107a102666c7d7631204d7e0e74757f692e
挑战(2/3)
然后A又准备了一份纸条,上面写着下面的密文文本,交给了第二个信使:
dc22ea5eb95ad54cee85cd1c5d89255f5e7cd4e1ab6602581b7a593ce284a43493551984d4e66d45bc0f02b9ec22e313f57dd449a7e5c01d47cb360d436dc1a3fb57743d3b17201c9f93f7d743fc277da5f4cb4d04d06661dc6368616c6c656e676540696e746567
当第一个信使返回时,A让他向同一个目的地(B)传递第三条信息(这次是纯文本):
两者中的一个是,但不是两者都是,也不是三者都是
所以接收者B收到了3条消息,它们都必须连接到同一个操作符。
挑战(3/3)
该解决方案由签名前所追求的明文的最后一个字组成。请用小写字母输入解决方案。
提示
第三个消息是另一个操作数,它的内容描述了所有三个消息必须连接到哪个操作符。

  我们查看了前两个消息的密文,发现内容都是16进制数,所以是一种加密后的结果为16进制数的算法。第一次密文长度是204,第二次的密文长度是208,第三次的是明文操作数描述了一个操作符。

  但是我尝试了假设第三次的操作符是与、或、异或,然后用可打印的ASCII字符来暴力破解前两次的密文,但是都没有得到可以人眼识别的明文,0~256的字符也不行。写这个网站的破解密码学算法的题更多的是需要破解的方向和思路吧,没有找到合适的方向真的没办法破解。

(2)Cryptanalysis Hacking Puzzles — Part 2

Your task is to decrypt the ciphertext (substitution cipher) on page 3 and answer the following question:
In one word only, what cryptology concept is the author refering in his quote?
Please enter the solution in lower-case letters.
Note from the author: This puzzle links the author’s passion for amateur astronomy and for cryptology. To get across the nature of keys and their distribution in the universe of possible numbers is in the meaning of this puzzle. The ciphertext expresses his own definition of one relevant cryptology concept.

你的任务是解密第三页上的密文(替代密码),并回答以下问题:
一句话,作者引用的密码学概念是什么?
请用小写字母输入解决方案。
注从作者:这个谜连接作者的激情业余天文学和密码学。解开这个谜题的意义在于理解键的本质及其在宇宙中可能数字的分布。密文表达了他自己对一个相关密码学概念的定义。

从题目易知这是经过替换加密后的密文,对其进行频率分析:
逆向工程实验——pre8(密码分析、RSA和AES混合加密方案)_第1张图片

然后按频率进行初始代换,针对代换后的内容猜测部分替换关系,再一点点尝试其他可能的代换,最终得到结果:
在这里插入图片描述

imagine our galaxy with their estimated three hundred billion stars and all their planets, comets, asteroids and space dust as the keyspace. and the rest of the universe with all the galaxies and particles in it, as the universe of possible numbers were that keyspace exists!
想象一下,我们的星系有大约3000亿颗恒星和所有的行星、彗星、小行星和太空尘埃,它们是关键空间。以及宇宙中所有星系和粒子的其余部分,就像宇宙中可能的数字一样,键空间是存在的!
从其中能看到唯一和密码学相关的内容为keyspace,所以我们要的结果就是keyspace。
(Ps.之前做过类似的题目,用的是相同的代码,这里就不再放了。)

4. (选做)Hybrid Encryption I

https://www.mysterytwisterc3.org/en/challenges/level-ii/hybrid-encryption-i

Hybrid Encryption
A drawback of symmetric encryption schemes is the problem of key exchange.
Prior to the actual encryption the parties have to exchange a secret key in asecure way.
The encryption itself can be performed very efficiently.
  
Asymmetric encryption schemes solve the problem of key exchange
by using a key pair consisting of public and private key.
The data encryption, however, is very costly
To use the advantages of both symmetric and asymmetric, in practise one often uses a hybrid encryption.
This means that a random key K for some symmetric scheme is generated and the plaintext is encrypted using that scheme.
To transfer this session key K to the receiver, a public key scheme is employed to encrypt the session key.
  
You eavesdropped on a hybrid encryption communication.
You know that the asymmetric scheme RSA is used in its plain form, i.e. the session key is encrypted as c = K e mod N.
The session key itself is used in an 128 bit AES Cipher in ECB mode to encrypt the plaintext message.
Find the plaintext message.
In the addidional file you will find the public RSA parameters (N,e) and the ciphertexts.
The encryption of the session key under RSA is given as cp and the encryption of the plaintext under AES using the session key is given as cs.

混合加密
对称加密方案的一个缺点是密钥交换问题。
在进行实际加密之前,双方必须以安全的方式交换密钥。
加密本身可以非常有效地执行。
非对称加密方案解决了密钥交换问题
通过使用由公钥和私钥组成的密钥对。
然而,数据加密是非常昂贵的

利用对称和不对称的优点,在练习一通常使用混合加密。
这意味着生成某个对称方案的随机密钥K,明文使用该方案加密。
为了将这个会话密钥K传输给接收者,我们使用了一个公钥方案对会话密钥进行加密。

你窃听了一个混合加密通讯。
您知道非对称方案RSA在其普通格式中使用形式,即会话密钥加密为c = Ke mod N。
会话密钥本身以128位AES密码在ECB模式下用于加密明文消息。
查找明文消息。
在附加文件中,您将发现公共RSA参数(N,e)和密文。
在RSA下的会话密钥加密后以cp的形式给出,在AES下使用会话密钥对明文进行加密后为cs。

题目的意思是先使用了非对称算法RSA加密了对称算法AES的会话密钥,所以我们第一步首先要解密RSA算法得到会话密钥,题目中给出了已知的条件有:

密文:c_p =
0xc0eacf32dc0492464d9616fefc3d01f56589a137781bf6cf56784dea1c44ef52d61b1025655f370eb78646716f93e0a5
参数N:n =
0x9c5f36caf9adc60b4447897c639f1564ed0709251147276de030db395555c8afed912a198b334bd230198173128298126e958e38cac653e061035e300505eed1
指数e:e = 0x3

加密过程:c = me mod n,e=3
①当m3,也就是说m3=c。那么我们求解明文只需要c开三次根就行了;
②当m3>n,即m3=c+i * n。哪我们就爆破i,对c+i*n开三次根,直到得到的结果是整数。
源代码:

import gmpy2

c_p = 0xc0eacf32dc0492464d9616fefc3d01f56589a137781bf6cf56784dea1c44ef52d61b1025655f370eb78646716f93e0a5
n = 0x9c5f36caf9adc60b4447897c639f1564ed0709251147276de030db395555c8afed912a198b334bd230198173128298126e958e38cac653e061035e300505eed1
e = 0x3

i=0
while 1:
    # c_p+i*n开三次根,直到返回找到一个整数根
    temp =gmpy2.iroot(c_p+i*n, e)
    # 返回结果包括开根的结果和是否为整数,(mpz(309658584779820310739729975902632468029), True)
    if(temp[1]==1):
        print(temp[0])
        break
    i=i+1

运行结果:
在这里插入图片描述

得到的用于AES算法中的会话密钥是309658584779820310739729975902632468029。
AES密钥的16进制形式就是0xe8f612f7fb5b6ac2a3e99a52ba6cde3d,又已知密文c_s=0xfd0b934c23288975648cd1d03ed3c5e2,接下来以128位AES密码在ECB模式下解密。
源代码aes.c:

#include 
#include 
#include 

typedef struct{
    uint32_t eK[44], dK[44];    // encKey, decKey
    int Nr; // 10 rounds
}AesKey;

#define BLOCKSIZE 16  //AES-128分组长度为16字节

// uint8_t y[4] -> uint32_t x
#define LOAD32H(x, y) \
  do { (x) = ((uint32_t)((y)[0] & 0xff)<<24) | ((uint32_t)((y)[1] & 0xff)<<16) | \
             ((uint32_t)((y)[2] & 0xff)<<8)  | ((uint32_t)((y)[3] & 0xff));} while(0)

// uint32_t x -> uint8_t y[4]
#define STORE32H(x, y) \
  do { (y)[0] = (uint8_t)(((x)>>24) & 0xff); (y)[1] = (uint8_t)(((x)>>16) & 0xff);   \
       (y)[2] = (uint8_t)(((x)>>8) & 0xff); (y)[3] = (uint8_t)((x) & 0xff); } while(0)

// 从uint32_t x中提取从低位开始的第n个字节
#define BYTE(x, n) (((x) >> (8 * (n))) & 0xff)

/* used for keyExpansion */
// 字节替换然后循环左移1位
#define MIX(x) (((S[BYTE(x, 2)] << 24) & 0xff000000) ^ ((S[BYTE(x, 1)] << 16) & 0xff0000) ^ \
                ((S[BYTE(x, 0)] << 8) & 0xff00) ^ (S[BYTE(x, 3)] & 0xff))

// uint32_t x循环左移n位
#define ROF32(x, n)  (((x) << (n)) | ((x) >> (32-(n))))
// uint32_t x循环右移n位
#define ROR32(x, n)  (((x) >> (n)) | ((x) << (32-(n))))

/* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
// AES-128轮常量
static const uint32_t rcon[10] = {
        0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, 0x10000000UL,
        0x20000000UL, 0x40000000UL, 0x80000000UL, 0x1B000000UL, 0x36000000UL
};
// S盒
unsigned char S[256] = {
        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盒
unsigned char inv_S[256] = {
        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
};

/* copy in[16] to state[4][4] */
int loadStateArray(uint8_t (*state)[4], const uint8_t *in) {
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            state[j][i] = *in++;
        }
    }
    return 0;
}

/* copy state[4][4] to out[16] */
int storeStateArray(uint8_t (*state)[4], uint8_t *out) {
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            *out++ = state[j][i];
        }
    }
    return 0;
}
//秘钥扩展
int keyExpansion(const uint8_t *key, uint32_t keyLen, AesKey *aesKey) {

    if (NULL == key || NULL == aesKey){
        printf("keyExpansion param is NULL\n");
        return -1;
    }

    if (keyLen != 16){
        printf("keyExpansion keyLen = %d, Not support.\n", keyLen);
        return -1;
    }

    uint32_t *w = aesKey->eK;  //加密秘钥
    uint32_t *v = aesKey->dK;  //解密秘钥

    /* keyLen is 16 Bytes, generate uint32_t W[44]. */

    /* W[0-3] */
    for (int i = 0; i < 4; ++i) {
        LOAD32H(w[i], key + 4*i);
    }

    /* W[4-43] */
    for (int i = 0; i < 10; ++i) {
        w[4] = w[0] ^ MIX(w[3]) ^ rcon[i];
        w[5] = w[1] ^ w[4];
        w[6] = w[2] ^ w[5];
        w[7] = w[3] ^ w[6];
        w += 4;
    }

    w = aesKey->eK+44 - 4;
    //解密秘钥矩阵为加密秘钥矩阵的倒序,方便使用,把ek的11个矩阵倒序排列分配给dk作为解密秘钥
    //即dk[0-3]=ek[41-44], dk[4-7]=ek[37-40]... dk[41-44]=ek[0-3]
    for (int j = 0; j < 11; ++j) {

        for (int i = 0; i < 4; ++i) {
            v[i] = w[i];
        }
        w -= 4;
        v += 4;
    }

    return 0;
}

// 轮秘钥加
int addRoundKey(uint8_t (*state)[4], const uint32_t *key) {
    uint8_t k[4][4];

    /* i: row, j: col */
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            k[i][j] = (uint8_t) BYTE(key[j], 3 - i);  /* 把 uint32 key[4] 先转换为矩阵 uint8 k[4][4] */
            state[i][j] ^= k[i][j];
        }
    }

    return 0;
}

//字节替换
int subBytes(uint8_t (*state)[4]) {
    /* i: row, j: col */
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            state[i][j] = S[state[i][j]]; //直接使用原始字节作为S盒数据下标
        }
    }

    return 0;
}

//逆字节替换
int invSubBytes(uint8_t (*state)[4]) {
    /* i: row, j: col */
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            state[i][j] = inv_S[state[i][j]];
        }
    }
    return 0;
}

//行移位
int shiftRows(uint8_t (*state)[4]) {
    uint32_t block[4] = {0};

    /* i: row */
    for (int i = 0; i < 4; ++i) {
    //便于行循环移位,先把一行4字节拼成uint_32结构,移位后再转成独立的4个字节uint8_t
        LOAD32H(block[i], state[i]);
        block[i] = ROF32(block[i], 8*i);
        STORE32H(block[i], state[i]);
    }

    return 0;
}

//逆行移位
int invShiftRows(uint8_t (*state)[4]) {
    uint32_t block[4] = {0};

    /* i: row */
    for (int i = 0; i < 4; ++i) {
        LOAD32H(block[i], state[i]);
        block[i] = ROR32(block[i], 8*i);
        STORE32H(block[i], state[i]);
    }

    return 0;
}

/* Galois Field (256) Multiplication of two Bytes */
// 两字节的伽罗华域乘法运算
uint8_t GMul(uint8_t u, uint8_t v) {
    uint8_t p = 0;

    for (int i = 0; i < 8; ++i) {
        if (u & 0x01) {    //
            p ^= v;
        }

        int flag = (v & 0x80);
        v <<= 1;
        if (flag) {
            v ^= 0x1B; /* x^8 + x^4 + x^3 + x + 1 */
        }

        u >>= 1;
    }

    return p;
}

// 列混合
int mixColumns(uint8_t (*state)[4]) {
    uint8_t tmp[4][4];
    uint8_t M[4][4] = {{0x02, 0x03, 0x01, 0x01},
                       {0x01, 0x02, 0x03, 0x01},
                       {0x01, 0x01, 0x02, 0x03},
                       {0x03, 0x01, 0x01, 0x02}};

    /* copy state[4][4] to tmp[4][4] */
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j){
            tmp[i][j] = state[i][j];
        }
    }

    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {  //伽罗华域加法和乘法
            state[i][j] = GMul(M[i][0], tmp[0][j]) ^ GMul(M[i][1], tmp[1][j])
                        ^ GMul(M[i][2], tmp[2][j]) ^ GMul(M[i][3], tmp[3][j]);
        }
    }

    return 0;
}

// 逆列混合
int invMixColumns(uint8_t (*state)[4]) {
    uint8_t tmp[4][4];
    uint8_t M[4][4] = {{0x0E, 0x0B, 0x0D, 0x09},
                       {0x09, 0x0E, 0x0B, 0x0D},
                       {0x0D, 0x09, 0x0E, 0x0B},
                       {0x0B, 0x0D, 0x09, 0x0E}};  //使用列混合矩阵的逆矩阵

    /* copy state[4][4] to tmp[4][4] */
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j){
            tmp[i][j] = state[i][j];
        }
    }

    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            state[i][j] = GMul(M[i][0], tmp[0][j]) ^ GMul(M[i][1], tmp[1][j])
                          ^ GMul(M[i][2], tmp[2][j]) ^ GMul(M[i][3], tmp[3][j]);
        }
    }

    return 0;
}

// AES128解密, 参数要求同加密
int aesDecrypt(const uint8_t *key, uint32_t keyLen, const uint8_t *ct, uint8_t *pt, uint32_t len) {
    AesKey aesKey;
    uint8_t *pos = pt;
    const uint32_t *rk = aesKey.dK;  //解密秘钥指针
    uint8_t out[BLOCKSIZE] = {0};
    uint8_t actualKey[16] = {0};
    uint8_t state[4][4] = {0};

    if (NULL == key || NULL == ct || NULL == pt){
        printf("param err.\n");
        return -1;
    }

    if (keyLen > 16){
        printf("keyLen must be 16.\n");
        return -1;
    }

    if (len % BLOCKSIZE){
        printf("inLen is invalid.\n");
        return -1;
    }

    memcpy(actualKey, key, keyLen);
    //秘钥扩展,同加密
    keyExpansion(actualKey, 16, &aesKey);

    for (int i = 0; i < len; i += BLOCKSIZE) {
        // 把16字节的密文转换为4x4状态矩阵来进行处理
        loadStateArray(state, ct);
        // 轮秘钥加,同加密
        addRoundKey(state, rk);

        for (int j = 1; j < 10; ++j) {
            rk += 4;
            invShiftRows(state);    // 逆行移位
            invSubBytes(state);     // 逆字节替换,这两步顺序可以颠倒
            addRoundKey(state, rk); // 轮秘钥加,同加密
            invMixColumns(state);   // 逆列混合
        }

        // 逆字节替换
        invSubBytes(state);
        // 逆行移位
        invShiftRows(state);
        // 此处没有逆列混合
        addRoundKey(state, rk+4);  // 轮秘钥加,同加密

        // 保存明文数据
        storeStateArray(state, pos);
        // 输出数据内存指针移位分组长度
        pos += BLOCKSIZE;
        // 输入数据内存指针移位分组长度
        ct += BLOCKSIZE;
        // 恢复rk指针到秘钥初始位置
        rk = aesKey.dK;
    }
    return 0;
}

int main() {
    //密钥
    const uint8_t key[16] = {0xe8,0xf6,0x12,0xf7,0xfb,0x5b,0x6a,0xc2,0xa3,0xe9,0x9a,0x52,0xba,0x6c,0xde,0x3d};
    //密文
    uint8_t pt[16]={0xfd,0x0b,0x93 ,0x4c ,0x23 ,0x28 ,0x89 ,0x75 ,0x64 ,0x8c ,0xd1 ,0xd0 ,0x3e ,0xd3 ,0xc5,0xe2};
    //解密后的明文
    uint8_t plain[16] = {0};  // 外部申请输出数据内存,用于解密后的数据

    ///解密
    aesDecrypt(key, 16, pt, plain, 16);       // 解密
    printf("解密后的明文:");
    for(int i = 0 ; i <16 ;i++){
        printf("%c",plain[i]);
    }
    return 0;
}

运行结果:
在这里插入图片描述

AES解密得到的明文是Diffie Rocks !!!
在网址输入验证正确:
在这里插入图片描述

你可能感兴趣的:(#,逆向工程实验,密码学,python,算法,c语言,RSA,AES)