LEA Cipher 암호화/복호화 과정 이해하기

 

LEA Cipher 암호화/복호화 과정 이해하기

블록암호 LEA(Lightweight Encryption Algorithm)는 128비트 데이터 블록을 암호화하는 알고리즘으로 128, 192, 256비트 비밀키를 사용할 수 있으며 요구되는 안전성 기준에 따라 용도가 구분될 수 있다 1. LEA ��

cryptosecurity.tistory.com

LEA Cipher 암호화와 복호화 규격과 구조, 과정을 이해하고 보시길 바랍니다.

 

 

 

LEA.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef _LEA_H_
#define _LEA_H_
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
typedef unsigned char BYTE; //1byte
typedef unsigned long int WORD; //4byte 
 
int ROL(int i, WORD value);
int ROR(int i, WORD value);
void KeySchedule_128(BYTE *K, WORD *RK);
void KeySchedule_192(BYTE *K, WORD *RK);
void KeySchedule_256(BYTE *K, WORD *RK);
void Encrypt(int Nr, WORD *RK, BYTE *P, BYTE *C);
void Decrypt(int Nr, WORD *RK, BYTE *D, BYTE *C);
 
#else
#endif
cs

 

 

LEA.cpp

delta 상수 정하기

1
2
3
4
5
6
7
8
9
10
11
12
#include "LEA.h"
 
WORD delta[8= {
    0xc3efe9db,
    0x44626b02,
    0x79e27c8a,
    0x78df30ec,
    0x715ea49e,
    0xc785da0a,
    0xe04ef22a,
    0xe5c40957
};
cs

 

Rotate Left & Rotate Right 함수 구현

1
2
3
4
5
6
7
8
9
10
11
//32비트 비트열 x의 i비트 좌측 순환이동
int ROL(int i, WORD value)
{
    return (value << i) | (value >> (32 - i));
}
 
//32비트 비트열 x의 i비트 우측 순환이동
int ROR(int i, WORD value)
{
    return (value >> i) | (value << (32 - i));
}
cs

 

LEA-128 키 스케줄링 함수 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void KeySchedule_128(BYTE *K, WORD *RK)
{
    WORD T[4];
 
    memcpy(T, K, 16); //8*16 = 128
 
    int i;
    for (i = 0; i < 24; i++)
    {
        T[0= ROL(1, T[0+ ROL(i, delta[i % 4]));
        T[1= ROL(3, T[1+ ROL(i + 1, delta[i % 4]));
        T[2= ROL(6, T[2+ ROL(i + 2, delta[i % 4]));
        T[3= ROL(11, T[3+ ROL(i + 3, delta[i % 4]));
        RK[i * 6 + 0= T[0];
        RK[i * 6 + 1= T[1];
        RK[i * 6 + 2= T[2];
        RK[i * 6 + 3= T[1];
        RK[i * 6 + 4= T[3];
        RK[i * 6 + 5= T[1];
    }
}
cs

 

 

LEA-192 키 스케줄링 함수 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void KeySchedule_192(BYTE *K, WORD *RK)
{
    WORD T[6];
 
    memcpy(T, K, 24); //8*24 = 192
 
    int i;
    for (i = 0; i < 28; i++)
    {
        T[0= ROL(1, T[0+ ROL(i, delta[i % 6]));
        T[1= ROL(3, T[1+ ROL(i + 1, delta[i % 6]));
        T[2= ROL(6, T[2+ ROL(i + 2, delta[i % 6]));
        T[3= ROL(11, T[3+ ROL(i + 3, delta[i % 6]));
        T[4= ROL(13, T[4+ ROL(i + 4, delta[i % 6]));
        T[5= ROL(17, T[5+ ROL(i + 5, delta[i % 6]));
        RK[i * 6 + 0= T[0];
        RK[i * 6 + 1= T[1];
        RK[i * 6 + 2= T[2];
        RK[i * 6 + 3= T[3];
        RK[i * 6 + 4= T[4];
        RK[i * 6 + 5= T[5];
    }
}
cs

 

LEA-256 키 스케줄링 함수 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void KeySchedule_256(BYTE *K, WORD *RK)
{
    WORD T[8];
 
    memcpy(T, K, 32); //8*32 = 256
 
    int i;
    for (i = 0; i < 32; i++)
    {
        T[(6 * i + 0) % 8= ROL(1, T[(6 * i + 0) % 8+ ROL(i, delta[i % 8]));
        T[(6 * i + 1) % 8= ROL(3, T[(6 * i + 1) % 8+ ROL(i + 1, delta[i % 8]));
        T[(6 * i + 2) % 8= ROL(6, T[(6 * i + 2) % 8+ ROL(i + 2, delta[i % 8]));
        T[(6 * i + 3) % 8= ROL(11, T[(6 * i + 3) % 8+ ROL(i + 3, delta[i % 8]));
        T[(6 * i + 4) % 8= ROL(13, T[(6 * i + 4) % 8+ ROL(i + 4, delta[i % 8]));
        T[(6 * i + 5) % 8= ROL(17, T[(6 * i + 5) % 8+ ROL(i + 5, delta[i % 8]));
        RK[i * 6 + 0= T[(i * 6 + 0) % 8];
        RK[i * 6 + 1= T[(i * 6 + 1) % 8];
        RK[i * 6 + 2= T[(i * 6 + 2) % 8];
        RK[i * 6 + 3= T[(i * 6 + 3) % 8];
        RK[i * 6 + 4= T[(i * 6 + 4) % 8];
        RK[i * 6 + 5= T[(i * 6 + 5) % 8];
    }
}
cs

 

LEA 암호화 함수 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void Encrypt(int Nr, WORD *RK, BYTE *P, BYTE *C)
{
    WORD X_Round[4]; //32 * 4 =128BIT  
    WORD X_NextRound[4];
 
    memcpy(X_Round, P, 16);
 
    int i, j, k;
    for (i = 0; i < Nr; i++)
    {
        X_NextRound[0= ROL(9, (X_Round[0] ^ RK[i * 6 + 0]) + (X_Round[1] ^ RK[i * 6 + 1]));
        X_NextRound[1= ROR(5, (X_Round[1] ^ RK[i * 6 + 2]) + (X_Round[2] ^ RK[i * 6 + 3]));
        X_NextRound[2= ROR(3, (X_Round[2] ^ RK[i * 6 + 4]) + (X_Round[3] ^ RK[i * 6 + 5]));
        X_NextRound[3= X_Round[0];
 
        memcpy(X_Round, X_NextRound, 16);
    }
 
    memcpy(C, X_NextRound, 16);
}
cs

 

LEA 복호화 함수 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void Decrypt(int Nr, WORD *RK, BYTE *D, BYTE *C)
{
    WORD X_Round[4];
    WORD X_NextRound[4];
    
    memcpy(X_Round, C, 16);
    
    int i;
    for (i = 0; i < Nr; i++)
    {
        X_NextRound[0= X_Round[3];
        X_NextRound[1= (ROR(9, X_Round[0]) - (X_NextRound[0] ^ RK[((Nr - i - 1* 6+ 0])) ^ RK[((Nr - i - 1* 6+ 1];
        X_NextRound[2= (ROL(5, X_Round[1]) - (X_NextRound[1] ^ RK[((Nr - i - 1* 6+ 2])) ^ RK[((Nr - i - 1* 6+ 3];
        X_NextRound[3= (ROL(3, X_Round[2]) - (X_NextRound[2] ^ RK[((Nr - i - 1* 6+ 4])) ^ RK[((Nr - i - 1* 6+ 5];
        
        memcpy(X_Round, X_NextRound, 16);
    }
    
    memcpy(D, X_Round, 16);
}
cs

 

 

main.cpp

LEA 암호화 복호화 테스트 해보기

1. LEA-128 암호화, 복호화 테스트하기

 

Nb : 16, Nk : 16, Nr : 24

Key : 0f 1e 2d 3c 4b 5a 69 78 87 96 a5 b4 c3 d2 e1 f0

Plaintext : 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f

 

다음의 Key로 Plaintext를 암호화 해서 Ciphertext를 구하고, 다시 Ciphertext를 복호화해서 Plaintext를 구해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include "LEA.h"
 
int main()
{
    int i;
 
    BYTE K[16=
    {
        0x0f0x1e0x2d0x3c0x4b0x5a0x690x780x870x960xa50xb40xc30xd20xe10xf0
    };
 
    BYTE P[16=
    {
        0x100x110x120x130x140x150x160x170x180x190x1a0x1b0x1c0x1d0x1e0x1f
    };
 
    WORD RoundKey[144= { 0, };
    BYTE C[16= { 0 };
    BYTE D[16= { 0 };
 
    KeySchedule_128(K, RoundKey);
 
    printf("Key : ");
    for (i = 0; i < 16; i++)
    {
        printf("0x%02x ", K[i]);
    }
    printf("\n\n");
 
    printf("Plaintext :  ");
    for (i = 0; i < 16; i++)
    {
        printf("0x%02x ", P[i]);
    }
    printf("\n\n");
 
    Encrypt(24, RoundKey, P, C);
    printf("Ciphertext : ");
    for (i = 0; i < 16; i++)
    {
        printf("0x%02x ", C[i]);
    }
    printf("\n\n");
 
    Decrypt(24, RoundKey, D, C);
    printf("Plaintext :  ");
    for (i = 0; i < 16; i++)
    {
        printf("0x%02x ", D[i]);
    }
    printf("\n");
 
    return 0;
}
cs

 

==실행결과==

 

 

2. LEA-192 암호화 복호화 테스트하기

 

Nb : 16, Nk : 24, Nr : 28

Key : 0f 1e 2d 3c 4b 5a 69 78 87 96 a5 b4 c3 d2 e1 f0 f0 e1 d2 c3 b4 a5 96 87

Plaintext : 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f

 

다음의 Key로 Plaintext를 암호화 해서 Ciphertext를 구하고, 다시 Ciphertext를 복호화해서 Plaintext를 구해보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include "lea.h"
 
int main()
{
    int i;
 
    BYTE K[24=
    {
        0x0f0x1e0x2d0x3c0x4b0x5a0x690x780x870x960xa50xb40xc30xd20xe10xf00xf00xe10xd20xc30xb40xa50x960x87
    };
 
    
    BYTE P[16=
    {
        0x200x210x220x230x240x250x260x270x280x290x2a0x2b0x2c0x2d0x2e0x2f
    };
 
    WORD RoundKey[168= { 0, };
    BYTE C[16= { 0 };
    BYTE D[16= { 0 };
 
    KeySchedule_192(K, RoundKey);
 
    printf("Key : ");
    for (i = 0; i < 24; i++)
    {
        printf("0x%02x ", K[i]);
    }
    printf("\n\n");
 
    printf("Plaintext :  ");
    for (i = 0; i < 16; i++)
    {
        printf("0x%02x ", P[i]);
    }
    printf("\n\n");
 
    Encrypt(28, RoundKey, P, C);
    printf("Ciphertext : ");
    for (i = 0; i < 16; i++)
    {
        printf("0x%02x ", C[i]);
    }
    printf("\n\n");
 
    Decrypt(28, RoundKey, D, C);
    printf("Plaintext :  ");
    for (i = 0; i < 16; i++)
    {
        printf("0x%02x ", D[i]);
    }
    printf("\n");
 
    return 0;
}
cs

 

==실행결과==

 

 

 

3. LEA-256 암호화, 복호화 테스트하기

 

Nb : 16, Nk : 32, Nr : 32

Key : 0f 1e 2d 3c 4b 5a 69 78 87 96 a5 b4 c3 d2 e1 f0 f0 e1 d2 c3 b4 a5 96 87

Plaintext : 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f

 

다음의 Key로 Plaintext를 암호화 해서 Ciphertext를 구하고, 다시 Ciphertext를 복호화해서 Plaintext를 구해보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include "lea.h"
 
int main()
{
    int i;
    BYTE K[32=
    {
        0x0f0x1e0x2d0x3c0x4b0x5a0x690x780x870x960xa50xb40xc30xd20xe10xf00xf00xe10xd20xc30xb40xa50x960x870x780x690x5a0x4b0x3c0x2d0x1e0x0f
    };
 
    BYTE P[16=
    {
        0x300x310x320x330x340x350x360x370x380x390x3a0x3b0x3c0x3d0x3e0x3f
    };
 
    WORD RoundKey[192= { 0, };
    BYTE C[16= { 0 };
    BYTE D[16= { 0 };
    
    KeySchedule_256(K, RoundKey);
    
    printf("Key : ");
    for (i = 0; i < 32; i++)
    {
        printf("0x%02x ", K[i]);
    }
    printf("\n\n");
 
    printf("Plaintext :  ");
    for (i = 0; i < 16; i++)
    {
        printf("0x%02x ", P[i]);
    }
    printf("\n\n");
 
    Encrypt(32, RoundKey, P, C);
    printf("Ciphertext : ");
    for (i = 0; i < 16; i++)
    {
        printf("0x%02x ", C[i]);
    }
    printf("\n\n");
 
    Decrypt(32, RoundKey, D, C);
    printf("Plaintext :  ");
    for (i = 0; i < 16; i++)
    {
        printf("0x%02x ", D[i]);
    }
    printf("\n");
    return 0;
}
cs

 

==실행결과==

 

 

LEA 암호화, 복호화 전체 c언어 코드 보기

github.com/K-subin/LEA

'Cipher analysis > LEA' 카테고리의 다른 글

LEA Cipher 암호화/복호화 과정 이해하기  (0) 2020.10.14

블록암호 LEA(Lightweight Encryption Algorithm)는 128비트 데이터 블록을 암호화하는 알고리즘으로 128, 192, 256비트 비밀키를 사용할 수 있으며 요구되는 안전성 기준에 따라 용도가 구분될 수 있다

 

1. LEA 규격

LEA를 각 키 길이에 따라 LEA-128, LEA-192, LEA-256으로 구분한다.

  • 블록 길이 : Nb 바이트
  • 비밀키 길이 : Nk 바이트
  • 라운드 수 : Nr

 

LEA 암호화 및 복호화 과정

LEA의 전체적인 동작 과정은 다음과 같다.

 

 

2. LEA 암호화

LEA의 암호화 과정은 k비트 키 K로부터 Nr개의 192비트 암호화용 라운드키 RK_i (0 ≤ i ≤ (Nr - 1))를 생성하는 키 스케줄 함수 KeySchedule_k와, 라운드키 RK_i 및 라운드 함수 Round를 이용하여 128비트 평문 P를 128비트 암호문 C로 변환하는 암호화 함수 Encrypt로 구성된다.

 

2.1. 암호화 키 스케줄

키 K로부터 암호화 과정에 필요한 Nr개의 192비트 암호화 라운드키 RK_i (0 ≤ i ≤ (Nr - 1))들을 생성하는 키 스케줄 과정을 설명한다

 

- 상수

키 스케줄 함수에서 사용되는 32비트 상수들 δ[i] (0 ≤ i ≤ 7)는 다음과 같다

 

- LEA-128 암호화 키 스케줄링

128비트 키 K = (K[0], K[1], … , K[15])에 대해 LEA-128의 암호화를 위해 사용되는 키 스케줄 함수 KeySchedule-128은 24개의 192비트 암호화 라운드키 RK_i = (RK_i[0], RK_i[1], … , RK_i[5]) (0 ≤ i ≤ 23)를 다음 알고리즘3과 같이 생성한다.

이 과정에서 128비트 내부상태 변수 T = (T[0], T[1], T [2], T[3])가 사용된다

 

- LEA-192 암호화 키 스케줄링

192비트 키 K = (K[0], K[1], … , K[23])에 대해 LEA-192의 암호화를 위해 사용되는 키 스케줄 함수 KeySchedule-192는 28개의 192비트 암호화 라운드키 RK_i = (RK_i[0], RK_i[1] , … , RK_i[5]) (0 ≤ i ≤ 27)를 알고리즘4와 같이 생성한다.

이 과정에서 192비트 내부상태 변수 T = (T[0], T[1], … , T[5])가 사용된다.

 

- LEA-256 암호화 키 스케줄링

256비트 키 K = (K[0], K[1], … , K[31])에 대해 LEA-256의 암호화를 위해 사용되는 키 스케줄 함수 KeySchedule2 e5n 6 c는 32개의 192비트 암호화 라운드키 RK_i = (RK_i[0], RK_i[1], … , RK_i[5]) (0 ≤ i ≤ 31)를 알고리즘5와 같이 생성한다.

이 과정에서 256비트 내부상태 변수 T = (T[0], T[1], … , T[7])가 사용된다.

 

 

 

2.2. 암호화 함수

- 암호화 라운드 함수

알고리즘 1에서 i (0 ≤ i ≤ (Nr - 1))번째 라운드의 라운드 함수 Round는 128비트 내부상태 변수 X_i = (X_i[0], X_i[1], X_i[2], X_i[3])와 198비트 라운드키 RK_i = (RK_i[0], RK_i[1], … , RK_i[5])로부터 알고리즘 2를 수행하여 새로운 128비트 내부상태 변수 X_i+1 = (X_(i+1)[0], X_(i+1)[1], X_(i+1)[2], X_(i+1)[3])을 생성한다.

 

- 암호화 함수

LEA의 암호화 함수 Encrypt는 k비트 키 K에 대해 키 스케줄 함수 KeySchedulekenc을 수행하여 생성된 Nr개의 192비트 라운드키 RK_i = (RK_i[0], RK_i[1], … , RK_i[5]) (0 ≤ i ≤ (Nr - 1))와 128비트 평문 P = (P[0], P[1], … , P[15])를 입력받아 알고리즘 1을 수행하여 128비트 암호문 C = (C[0], C[1], … , C[15])를 출력한다.

 

다음은 암호화 과정의 i번째 라운드 함수를 도식화한 것이다.

 

 

 

 

3. LEA 복호화

LEA의 복호화 과정은 k비트 키 K로부터 Nr개의 192비트 복호화용 라운드키 RK_i (0 ≤ i ≤ (Nr - 1))를 생성하는 키 스케줄 함수 KeySchedule_k와, 라운드키 RK_i및 라운드 함수 Round를 이용하여 128비트 암호문 C를 128비트 평문 P로 변환하는 복호화 함수 Decrypt로 구성된다.

 

3.1. 복호화 키 스케줄링

키 K로부터 복호화 과정에 필요한 Nr개의 복호화 라운드키 RK_i (0 ≤ i ≤ (Nr - 1))들을 생성하는 키 스케줄 과정을 설명한다. 암호화 라운드키와 복호화 라운드키는

인 관계를 제외하면 동일한 방법으로 생성되며, 동일한 상수가 사용된다.

 

 

3.2. 복호화 함수

- 복호화 라운드 함수

알고리즘 6에서 i (0 ≤ i ≤ (Nr - 1))번째 라운드의 라운드 함수 Round는 128비트 내부상태 변수 Xi = (Xi[0], Xi[1], Xi[2], Xi[3]) 와 192비트 라운드키 RK_i = (RK_i[0], RK_i[1], … , RK_i[5]) 로 부터 알고리즘 7을 수행하여 새로운 128비트 내부상태 변수 X_(i+1) = (X_(i+1)[0], X_(i+1)[1], X_(i+1)[2], X_(i+1)[3]) 을 생성한다.

 

- 복호화 함수

LEA의 복호화 함수 Decrypt는 k비트 키 K에 대해 키 스케줄 함수 KeySchedule_k을 수행하여 생성된 Nr개의 192비트 라운드키 RK_i = (RK_i[0], RK_i[1], … , RK_i[5]) (0 ≤ i ≤ (Nr - 1)) 와 128비트 암호문 C = (C[0], C[1], … , C[15])를 입력받아 알고리즘 6을 수행하여 128 비트 평문 P = (P[0], P[1], … , P[15])를 출력한다.

 

다음은 복호화 과정의 i번째 라운드 함수를 도식화 한 것이다.

 

 

 

 

출처 : 128비트 블록암호 LEA 규격서, NSR 국가보안기술연구소

'Cipher analysis > LEA' 카테고리의 다른 글

LEA Cipher 암호화, 복호화 C언어로 구현하기  (0) 2020.10.14

[ AES 암호의 특징과 구조 ]

cryptosecurity.tistory.com/29

 

AES 암호의 특징과 구조

AES의 특징 1. 128비트 블록단위로 암호화하는 대칭 암호 알고리즘 2. 키의 비트 길이는 128, 192, 256비트 3. 10/12/14 라운드 4. SPN 구조 5. 바이트 단위의 연산 위주 AES의 구조 1. SubBytes 2. ShiftRows 3...

cryptosecurity.tistory.com

 

 

AES Cipher 암호화, 복호화 파이썬으로 구현하기

1. Sbox, ISBox, RC 설정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# Rijndael S-box
Sbox =  [ 0x630x7c0x770x7b0xf20x6b0x6f0xc50x300x010x67,
        0x2b0xfe0xd70xab0x760xca0x820xc90x7d0xfa0x59,
        0x470xf00xad0xd40xa20xaf0x9c0xa40x720xc00xb7,
        0xfd0x930x260x360x3f0xf70xcc0x340xa50xe50xf1,
        0x710xd80x310x150x040xc70x230xc30x180x960x05,
        0x9a0x070x120x800xe20xeb0x270xb20x750x090x83,
        0x2c0x1a0x1b0x6e0x5a0xa00x520x3b0xd60xb30x29,
        0xe30x2f0x840x530xd10x000xed0x200xfc0xb10x5b,
        0x6a0xcb0xbe0x390x4a0x4c0x580xcf0xd00xef0xaa,
        0xfb0x430x4d0x330x850x450xf90x020x7f0x500x3c,
        0x9f0xa80x510xa30x400x8f0x920x9d0x380xf50xbc,
        0xb60xda0x210x100xff0xf30xd20xcd0x0c0x130xec,
        0x5f0x970x440x170xc40xa70x7e0x3d0x640x5d0x19,
        0x730x600x810x4f0xdc0x220x2a0x900x880x460xee,
        0xb80x140xde0x5e0x0b0xdb0xe00x320x3a0x0a0x49,
        0x060x240x5c0xc20xd30xac0x620x910x950xe40x79,
        0xe70xc80x370x6d0x8d0xd50x4e0xa90x6c0x560xf4,
        0xea0x650x7a0xae0x080xba0x780x250x2e0x1c0xa6,
        0xb40xc60xe80xdd0x740x1f0x4b0xbd0x8b0x8a0x70,
        0x3e0xb50x660x480x030xf60x0e0x610x350x570xb9,
        0x860xc10x1d0x9e0xe10xf80x980x110x690xd90x8e,
        0x940x9b0x1e0x870xe90xce0x550x280xdf0x8c0xa1,
        0x890x0d0xbf0xe60x420x680x410x990x2d0x0f0xb0,
        0x540xbb0x16]
 
# Rijndael Inverted S-box
ISbox = [ 0x520x090x6a0xd50x300x360xa50x380xbf0x400xa3,
        0x9e0x810xf30xd70xfb , 0x7c0xe30x390x820x9b0x2f,
        0xff0x870x340x8e0x430x440xc40xde0xe90xcb , 0x54,
        0x7b0x940x320xa60xc20x230x3d0xee0x4c0x950x0b,
        0x420xfa0xc30x4e , 0x080x2e0xa10x660x280xd90x24,
        0xb20x760x5b0xa20x490x6d0x8b0xd10x25 , 0x720xf8,
        0xf60x640x860x680x980x160xd40xa40x5c0xcc0x5d,
        0x650xb60x92 , 0x6c0x700x480x500xfd0xed0xb90xda,
        0x5e0x150x460x570xa70x8d0x9d0x84 , 0x900xd80xab,
        0x000x8c0xbc0xd30x0a0xf70xe40x580x050xb80xb3,
        0x450x06 , 0xd00x2c0x1e0x8f0xca0x3f0x0f0x020xc1,
        0xaf0xbd0x030x010x130x8a0x6b , 0x3a0x910x110x41,
        0x4f0x670xdc0xea0x970xf20xcf0xce0xf00xb40xe6,
        0x73 , 0x960xac0x740x220xe70xad0x350x850xe20xf9,
        0x370xe80x1c0x750xdf0x6e , 0x470xf10x1a0x710x1d,
        0x290xc50x890x6f0xb70x620x0e0xaa0x180xbe0x1b ,
        0xfc0x560x3e0x4b0xc60xd20x790x200x9a0xdb0xc0,
        0xfe0x780xcd0x5a0xf4 , 0x1f0xdd0xa80x330x880x07,
        0xc70x310xb10x120x100x590x270x800xec0x5f , 0x60,
        0x510x7f0xa90x190xb50x4a0x0d0x2d0xe50x7a0x9f,
        0x930xc90x9c0xef , 0xa00xe00x3b0x4d0xae0x2a0xf5,
        0xb00xc80xeb0xbb0x3c0x830x530x990x61 , 0x170x2b,
        0x040x7e0xba0x770xd60x260xe10x690x140x630x55,
        0x210x0c0x7d]
 
# Round constant for Key schedule
RC = [ 0x010x020x040x080x100x200x400x800x1B0x36]
cs

 

 

2. 16byte를 4x4 행렬(state)로 변환하고 출력해주는 함수 구현하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#-- 16바이트를 4x4 행렬(state)로 변환 
def block2state(in_block):
    new_state = []
    for col in range(4):
        new_col = [ in_block[col*4+i] for i in range(4) ]
        new_state.append(new_col)
    return new_state
 
#-- (4x4 state) 출력
def hex_print(state):
    print('[', end='')
    for i in range(4):
        print('[%02x, %02x, %02x, %02x]' \
              %(state[i][0], state[i][1], state[i][2], state[i][3]), end='')
        if i<3:
            print(', ', end='')
    print(']')
cs

 

 

 

3. 유한체 GF(2^8) 상에서의 곱셈 함수 구현하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#-- xtime 유한체 GF(2^8)에서의 곱셈 (다항식에 x를 곱하기)
def xtime(x):
    y = (x << 1& 0xff
    if x >= 128:
        y ^= 0x1b
    return y
 
#-- MixColumn 용 '0x02' 곱하기
def m02(x):
    return xtime(x)
 
#-- MixColumn 용 '0x03' 곱하기
def m03(x):
    return m02(x)^x
cs

 

 

 

4. 한 Column에 대한 MixColumns 연산, SBox 연산, Xor연산 함수 구현하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#-- 한 Column에 대한 MixColumns 연산
    # [ [2, 3, 1, 1], [1, 2, 3, 1], [1, 1, 2, 3], [3, 1, 1, 2] ]
def MC_Col(col):
    new_col = [0]*4
    new_col[0= m02(col[0]) ^ m03(col[1]) ^ col[2] ^ col[3]
    new_col[1= col[0] ^ m02(col[1]) ^ m03(col[2]) ^ col[3]
    new_col[2= col[0] ^ col[1] ^ m02(col[2]) ^ m03(col[3])
    new_col[3= m03(col[0]) ^ col[1] ^ col[2] ^ m02(col[3])
    return new_col
 
#-- 한 column에 대한 Sbox
def SubByte_Col(col):
    new_col = [ Sbox[col[i]] for i in range(4) ]
    return new_col
 
#-- 한 Column의 XOR
def Xor_Col(c1, c2):
    new_col = [ c1[i]^c2[i] for i in range(4) ]
    return new_col
cs

 

 

 

5. SubBytes, ShiftRows, MixColums, AddRoundKey 함수 구현하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#-- SubBytes
def SubBytes(state):
    new_state = []
    for col in range(4):
        new_col = [ Sbox[ state[col][i] ] for i in range(4) ]
        new_state.append(new_col)
    return new_state
 
#-- ShiftRows
def ShiftRows(state):
    new_state = []
    for col in range(4):
        new_col = [ state[(col+i)%4][i] for i in range(4) ]
        new_state.append(new_col)
    return new_state
 
#-- MixColumns
def MixColumns(state):
    new_state = []
    for col in range(4):
        new_col = MC_Col(state[col])
        new_state.append(new_col)
    return new_state
 
#-- AddRoundkey
def AddRoundKey(state, rkey):
    new_state = []
    for col in range(4):
        new_col = [ state[col][i] ^ rkey[col][i] for i in range(4) ]
        new_state.append(new_col)
    return new_state
cs

 

 

 

6. 라운드 함수 구현하기

1
2
3
4
5
6
7
8
#-- 라운드 함수
def AES_Round(state, rkey):
    new_state = copy.deepcopy(state)
    new_state2 = SubBytes(new_state)
    new_state3 = ShiftRows(new_state2)
    new_state4 = MixColumns(new_state3)
    new_state5 = AddRoundKey(new_state4, rkey)
    return new_state5
cs

 

 

 

7. key schedule 함수 구현하기

[ AES key schedule에서만 사용되는 4바이트 변환함수 ]

    -  바이트 rotation -> Sbox 적용 -> RoundConstant 적용

1
2
3
4
5
6
def KeySR(col, round):
    new_col = Rotl(col)
    round_constant = [ RC[round-1], 000]
    new_col2 = SubByte_Col(new_col)
    new_col3 = Xor_Col(new_col2, round_constant)
    return new_col3
cs

 

[ AES Encrytion용 Key schedule ]

   - 입력: 암호키 (4x4 state)

   - 출력: 11개의 라운드키(4x4 state)

   - 출력 rkey = [ rkey[0], rkey[1], ... , rkey[10] ]

   - rkey[r] = [ [rk00, rk10, rk20, rk30], ... , [rk03, rk13, rk23, rk33] ]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def key_schedule_Enc(key_state):
    rkey = [ copy.deepcopy(key_state) ]
    for round in range(1,11):
        new_state = []
        new_w0 = Xor_Col(rkey[round-1][0], KeySR(rkey[round-1][3], round))
        new_state.append(new_w0)
        new_w1 = Xor_Col(rkey[round-1][1], new_w0)
        new_state.append(new_w1)
        new_w2 = Xor_Col(rkey[round-1][2], new_w1)
        new_state.append(new_w2)
        new_w3 = Xor_Col(rkey[round-1][3], new_w2)
        new_state.append(new_w3)
        rkey.append(new_state)
    return rkey
cs

 

 

 

8. AES 128 암호화 구현하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#-- AES-128 암호화
def AES_Enc(pt, key):
    rkey = key_schedule_Enc(key)
    state = copy.deepcopy(pt)
    new_state = AddRoundKey(state, rkey[0])
    for i in range(1,10):  # 1,2,...,9
        out_state = AES_Round(new_state, rkey[i])
        new_state = copy.deepcopy(out_state)
        print(i, ': ', end ='')
        hex_print(new_state)
    #-- final round
    new_state2 = SubBytes(new_state)
    new_state3 = ShiftRows(new_state2)
    new_state4 = AddRoundKey(new_state3, rkey[10])
    return new_state4
cs

final round (10라운드) 부분은 MixColums이 없기 때문에 따로 써준다.

 

 

9. 암호화 테스트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def main():
    # 테스트 벡터: FIPS 197 - AES (page 33)
    block = [ 0x320x430xf60xa80x880x5a0x300x8d, \
            0x310x310x980xa20xe00x370x070x34 ]
    key = [ 0x2b0x7e0x150x160x280xae0xd20xa6, \
            0xab0xf70x150x880x090xcf0x4f0x3c ]
    
    in_state = block2state(block)
    key_state = block2state(key)
    
    print('plaintext =')
    hex_print(in_state)
    print('key=')
    hex_print(key_state)
    
    new_state = AES_Enc(in_state, key_state)
    print('ciphertext=')
    hex_print(new_state)
    
if __name__ == '__main__':
    main()        
cs

 

== 실행결과 ==

 

'Cipher analysis > AES' 카테고리의 다른 글

AES 암호의 특징과 구조  (0) 2020.10.12
[Python] AES, Hash 구현 - Crypto 모듈 이용  (0) 2020.09.12

AES의 특징

1. 128비트 블록단위로 암호화하는 대칭 암호 알고리즘

2. 키의 비트 길이는 128, 192, 256비트

3. 10/12/14 라운드

4. SPN 구조

5. 바이트 단위의 연산 위주

 

 

AES의 구조

 

 

 

 

 

 

1. SubBytes

2. ShiftRows

3. MixColumns

4. AddRoundKey

 

 

 

 

 

 

 

 

- 마지막 라운드에는 MixColumns 수행하지 않음

- 구현 효율성과 암호화 / 복호화 대칭성에 유리하기 때문

 

SubBytes

Rijndaek field : GF(2^8) = GF(2)[X] / <m(x)>

M(x) = x^8+x^4+x^3+x+1

SubBytes 함수 : y = S(x) = Ax^(-1) + b

-> GF(2^8)에서 mod m(x) 상에서의 inverse계산

- >Affine 변환 적용(GF(2) 상)

 

AES의 S-Box

 

ShiftRows

각 행을 위로부터 0,1,2,3 만큼 왼쪽으로 회전

MixColumns 과 함께 확산효과를 위하여 사용

 

MixColumns

- 열 단위 확산함수

- 각 열을 GF(2^8) 상의 벡터로 간주한 선형 변환

- 각 열을 c(x) = 03x^3 + 01x^2 + 01x + 02와 mod x^4 + 1 상에서 곱한다.

- b(x) = c(x) * a(x) mod x^4 + 1

 

 

AES 라운드 함수의 테이블 구조 구현 1

- SubBytes, ShiftRows, MixColums

 

AES 라운드 함수의 테이블 구조 구현 2

- AddRoundKey

 

[ AES, Hash 구현 - Crypto 모듈 이용 ]

 

1.cmd에서 pycryptodomex 패키지 설치

 

 

2.x버전 -> pycrypto

3.x버전 -> pycryptodome

윈도우 -> pycryptodomex

 

 

 

 

 

2. 모듈 설정

1
2
3
import hashlib
from Crypto.Cipher import AES
from Crypto import Random
cs

 

3. AES길이 설정

1
BS = AES.block_size
cs

AES에서 BLOCK_SIZE = 16byte

BS=16

 

 

4. Encrypt 함수

1
2
3
4
def encrypt(key, plain):
        iv = Random.new().read(BS)
        cipher = AES.new(key, AES.MODE_CBC, iv)
        return iv + cipher.encrypt(plain)
cs
  • iv는 random함수를 이용해 BS길이만큼 설정
  • AES함수를 이용해 암호화 준비 설정
  • iv + encrypt 값 반환

 

4. decrypt 함수

1
2
3
4
def decrypt(key, enc):
        iv = enc[:BS]
        cipher = AES.new(key, AES.MODE_CBC, iv)
        return cipher.decrypt(enc[BS:])
cs
  • iv는 암호화할 때와 같아야 한다.
  • AES함수를 이용해 암호화 준비 설정
  • Iv 제외한 decrypt 값 반환

 

5. Hash함수로 키 생성

1
2
# hash algoritm 이용해 키 생성
key = hashlib.sha256(Random.new().read(32)).digest()
cs
  • Hashlib 모듈 이용해 hash algoritm사용
  • Sha256으로 key 생성

 

6. AES로 암호화 복호화 실행하기

1
2
3
4
5
6
7
8
9
10
message="nice to meet you"
print(message)
 
#encrypt
enc=encrypt(key, message)
print(enc)
 
#decrypt
dec=decrypt(key, enc)
print(dec)
cs

 

 

 

=== 실행 결과 ===

 

'Cipher analysis > AES' 카테고리의 다른 글

[Python] AES Cipher 암호화, 복호화 구현하기  (0) 2020.10.12
AES 암호의 특징과 구조  (0) 2020.10.12

+ Recent posts