[암호학] 1. DES를 C언어로 구현하다가 엔디안(Endian)의 존재에 대해 알게 되었다.
[암호학] 1. DES를 C언어로 구현하다가 엔디안(Endian)의 존재에 대해 알게 되었다.
DES Code
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
#include <stdio.h>
...
unsigned int IP[] = {
...
};
unsigned int inv_IP[] = {
...
};
uint8_t get_bit(uint64_t *data, int n) { //문제의 코드
//64비트 짜리 data에서 n번째 비트를 가져온다.
return (*data >> (64 - n)) & 1;
}
char plaintext[] = "QWERASDF"; //이 'QWERASDF'를 64비트 정수로 한 번에 읽어서 비트를 뽑으려 함
int main() {
unsigned int bitpt[64];
for (int i = 1; i < 65; i++)
{
bitpt[i-1] = get_bit(plaintext, i);
printf("%d", bitpt[i-1]);
}
return 0;
}
C언어로 DES를 구현해보자. 우선 plaintext를 문자열로 받는다. 이때 문자열은 바이트 단위로 나뉘기 때문에 DES를 적용하려면 결국 비트로 쪼개야 한다. 따라서 저렇게 코드를 짰고, 논리적으로는 완벽해 보였다. 하지만 순서가 거꾸로 된 상태로 출력이 되었다.
원인은 리틀 엔디안(Little-endian) 때문이었다.
바이트 오더링(Byte Ordering)
컴퓨터 공학의 기초 중 바이트 오더링(Byte Ordering)이라는 개념이 있다. 2 바이트 이상의 데이터가 메모리에 저장될 때 각 바이트가 메모리에 정렬되는 방식을 바이트 오더링 이라고 한다. 바이트 오더링은 빅 엔디안(Bing Endian)과 리틀 엔디안(Little Endian) 으로 나뉘어 진다.
빅 엔디안(Bing-endian)
가장 왼쪽에 있는 바이트부터 메모리의 낮은 주소에 저장되는 방식이다.
따라서 바이트 오더링에 대해 모른 사람일 경우 항상 데이터는 빅 엔디안의 방식처럼 메모리에 저장될거라고 착각하기 쉽다.
리틀 엔디안(Little-endian)
가장 오른쪽에 있는 바이트부터 메모리의 낮은 주소에 저장되는 방식이다.
내가 DES를 구현하다가 포인터를 이용하여 데이터에서 비트를 하나씩 가져왔다. 데이터는 리틀 엔디안 방식으로 저장되어 있기 때문에 우리는 순서대로 QWERASDF 라고 저장되어 있을 것이라고 생각하지만, 실제로 컴퓨터 메모리에는 FDSAREWQ 순서로 데이터를 저장되어 있어서 순서가 바뀐 채로 출력이 되는 것이었다.
DES Code
1
2
3
4
5
6
7
8
inline uint8_t get_bit(unsigned char *data, int n) {
// n은 1 ~ 64
int byte_index = (n - 1) / 8; // 몇 번째 바이트에 있는지 계산 (0 ~ 7)
int bit_index = (n - 1) % 8; // 그 바이트 내에서 몇 번째 비트인지 계산 (0 ~ 7)
// 바이트 내에서는 왼쪽(MSB)부터 0번 인덱스 취급하므로 7에서 빼줍니다.
return (data[byte_index] >> (7 - bit_index)) & 1;
}
이런식으로 코드를 작성하면 엔디안을 고려해서 배열에 접근하기 때문에 문제가 발생하지 않는다.
This post is licensed under CC BY 4.0 by the author.