吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1197|回复: 1
收起左侧

[讨论] 加密算法从0到-1--1SM4加密算法

[复制链接]
TongShuai 发表于 2020-11-12 12:08

SM4

  • 密钥长度为128bits

  • 加密算法和密钥扩展算法都是32位非线性迭代结构

  • 加解密算法结构相同,轮密钥的使用顺序相反

定义运算

32位数$x$向左循环移动$i$$:x<<<i,\oplus$为异或

#define ROL32(x,i) ((x)<<(i)|(((unsigned int)x>>(32-(i)))))

定义参量

密钥长度位128bits $MK=(MK_0,MK_1,MK_2,MK_3)$

轮密钥为32*32bits $rk=(rk_0,rk_1,...,rk_{31})$

$FK=(FK_0,FK_1,...,FK_3)$为系统参数,$CK=(CK_0,CK_1,...,CK_{31})$为固定参数

$CK_{i,j}=(4i+j)*7\ mod\ 256$,其中$i$为双字编号,$j$为字节编号,$j$采用大端序

#define RK_SIZE 32
static uint32_t mk[4];    // 加密使用的密钥
static uint32_t rk[31];    // 轮密钥
static uint32_t fk[4]={0xA3B1BAC6,0x56AA3350,0x677D9197,0xB27022DC};
// ck会在密钥生成算法中体现

轮函数F

$F(X_0,X_1,X_2,X_3,rk)=X_0\oplus T(X_1\oplus X_2\oplus X_3\oplus rk)$

合成置换$T(.)=L(\tau(.))$

若输入为$A=(a_0,a_1,a_2,a_3)$,其中$a_i$为8字节无符号整数,则非线性置换$\tau(A)=(sbox[a_0],sbox[a_1],sbox[a_2],sbox[a_3])$

$sbox$为替换用s盒

若输入为$B$,其中$B$为32字节无符号整数,则线性变换$L(B)=B\oplus (B&lt;&lt;&lt;2)\oplus(B&lt;&lt;&lt;10)\oplus(B&lt;&lt;&lt;18)\oplus(B&lt;&lt;&lt;24)$

#define L(x) (x)^ROL32(x,2)^ROL32(x,10)^ROL32(x,18)^ROL32(x,24)

#define tau(x) (sbox[(x)>>24]<<24|sbox[((x)>>16)&0xFF]<<16|sbox[((x)>>8)&0xFF]<<8|sbox[x&0xFF])
#define T(x) (L(tau(x)))

uint8_t sbox[256]; // s盒,在最终代码中体现

// 轮函数F直接在加密过程中体现

加密算法

反序变换$R(a_0,a_1,a_2,a_3)=(a_3,a_2,a_1,a_0),a_i$为8位

设输入为$(X_0,X_1,X_2,X_3),X_i$为32位

输出为$(Y_0,Y_1,Y_2,Y_3)$

$X_{i+4}=F(X_i,X_{i+1},X_{i+2},X_{i+3},rk_i)$

$(Y_0,Y_1,Y_2,Y_3)=R(X_{32},X_{33},X_{34},X_{35})$

解密过程和加密过程变换结构相同,不同的是轮密钥顺序

加密时$(rk_0,rk_1,...,rk_{31})$

解密时$rk_{31},rk_{30},...,rk_0$

void crypt(uint32_t p[4],uint32_t crk[31]){
    uint32_t c[36];
    c[0]=p[0];
    c[1]=p[1];
    c[2]=p[2];
    c[3]=p[3];
    for(size_t i=0;i<RK_SIZE;i++){
        c[i+4]=c[i]^T(c[i+1]^c[i+2]^c[i+3]^crk[i]);
    }
    p[0]=c[35];
    p[1]=c[34];
    p[2]=c[33];
    p[3]=c[32];
}
void encrypt(uint32_t p[4]){
    crypt(p,rk);
}
void decrypt(uint32_t c[4]){
    crypt(p,rrk); // rrk是rk的逆序
}

密钥扩展算法

密钥$MK=(MK_0,MK_1,MK_2,MK_3)$

$K=(K_0,K_1,...,K_{31})$

$(K_0,K_1,K_2,K_3)=(MK_0\oplus FK_0,MK_1\oplus FK_1,MK_2\oplus FK_2,MK_3\oplus FK_3)$

轮密钥为$rk,rk_i=K_{i+4}=K_i\oplus T'(K_{i+1}\oplus K_{i+2}\oplus K_{i+3}\oplus CK_i)$

$T'$$T$基本相同,其中的$L'=B\oplus(B&lt;&lt;&lt;13)\oplus(B&lt;&lt;&lt;23)$

#define Lp(x) ((x)^ROL32(x,13)^ROL32(x,23))
#define Tp(x) Lp(tau(x))
#define ck(i) (((4*(i)*7)&0xFF)<<24|(((4*(i)+1)*7)&0xFF)<<16|(((4*(i)+2)*7)&0xFF)<<8|(4*(i)+3)&0xFF)
void initKey(uin32_t mk[4]){
    uint32_t k[36];
    k[0]=mk[0]^fk[0];

    for(size_t i=0;i<RK_SIZE;i++){
        k[i+4]=k[i]^Tp(k[i+1]^k[i+2]^k[i+3]^ck(i));
        rk[i]=k[i+4];
        rrk[RK_SIZE-i]=rk[i]
    }
}

完整代码

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <inttypes.h>

#define cha(x) ((((x)&0x3F)+24)%64)
#define ROL32(x,i) ((x)<<(i)|(((unsigned int)(x)>>(32-(i)))))
#define L(x) (x)^ROL32(x,2)^ROL32(x,10)^ROL32(x,18)^ROL32(x,24)
#define tau(x) (sbox[((x)>>24)&0xFF]<<24|sbox[((x)>>16)&0xFF]<<16|sbox[((x)>>8)&0xFF]<<8|sbox[x&0xFF])
#define T(x) (L(tau(x)))
#define Lp(x) ((x)^ROL32(x,13)^ROL32(x,23)) // L'
#define Tp(x) (Lp(tau(x))) // T'
#define ck(i) (((4*(i)*7)&0xFF)<<24|(((4*(i)+1)*7)&0xFF)<<16|(((4*(i)+2)*7)&0xFF)<<8|(4*(i)+3)*7&0xFF)
#define R(x) (((x)>>24)&0xFF|((x)>>8)&0xFF00|((x)<<8)&0xFF0000|((x)<<24))
#define RK_SIZE 32      // 密钥轮数
static uint32_t rk[32];    // 轮密钥
static uint32_t rrk[32];    // 逆序轮密钥
static uint32_t fk[4] = { 0xA3B1BAC6,0x56AA3350,0x677D9197,0xB27022DC };

static uint8_t sbox[256] = {
0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05,
0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99,
0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62,
0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6,
0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8,
0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35,
0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87,
0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e,
0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1,
0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3,
0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f,
0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51,
0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8,
0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0,
0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84,
0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48
};
void crypt(uint32_t p[4], uint32_t crk[31]) {
    uint32_t c[36];
    c[0] = p[0];
    c[1] = p[1];
    c[2] = p[2];
    c[3] = p[3];
    uint32_t t;
    for (size_t i = 0; i < RK_SIZE; i++) {
        t = (c[i + 1] ^ c[i + 2] ^ c[i + 3] ^ crk[i]);
        c[i + 4] = c[i] ^ T(t);
        printf("%08x\n", c[i + 4]);
    }
    p[0] = c[35];
    p[1] = c[34];
    p[2] = c[33];
    p[3] = c[32];
}
void encrypt(uint32_t p[4]) {
    crypt(p, rk);
}
void decrypt(uint32_t c[4]) {
    crypt(c, rrk); // rrk是rk的逆序
}
void initKey(uint32_t mk[4]) {
    uint32_t k[36];
    k[0] = mk[0] ^ fk[0];
    k[1] = mk[1] ^ fk[1];
    k[2] = mk[2] ^ fk[2];
    k[3] = mk[3] ^ fk[3];

    uint32_t t;
    for (size_t i = 0; i < RK_SIZE; i++) {
        t = k[i + 1] ^ k[i + 2] ^ k[i + 3]^ck(i);
        k[i + 4] = k[i] ^ Tp(t);
        rk[i] = k[i + 4];
        rrk[RK_SIZE - i-1] = rk[i];
    }
}

void printArray(const char* name, uint32_t* d, size_t len) {
    printf("==============%s============\n", name);
    for (size_t i = 0; i < len; i++) {
        printf("0x%08X,", d[i]);
    }
    printf("\n============================\n");
}
int main() {
    uint8_t data[] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };
    uint8_t key[] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };
    uint32_t mk[4];
    uint32_t p[4];

    memcpy(p, data, 16);
    memcpy(mk, key, 16);
    for (size_t i = 0; i < 4; i++) {
        mk[i] = R(mk[i]);
        p[i] = R(p[i]);
    }
    initKey(mk);
    printArray("plain text", p, 4);
    encrypt(p);
    printArray("cipher", p, 4);
    decrypt(p);
    printArray("plain text(after decrypt)", p, 4);
    for (size_t i = 0; i < 4; i++) {
        p[i] = R(p[i]);
    }

    memcpy(data, p, 16);
    return 0;
}

参考资料

[1] SM4算法标准

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| TongShuai 发表于 2020-12-4 17:07
下周更新AES= =
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止回复与主题无关非技术内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-17 06:09

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表