프롤로그
고전 암호라서 딱히 어렵지는 않음. 근데 귀찮음. 그래도 기초는 이번을 마지막으로 끝날 듯
전치암호
전치 암호란 평문의 문자 위치를 서로 바꾸어 암호문을 만드는 기술. "대국민한 사만들람 이수할해 있다니습" 이렇게 작성한 걸 전치암호 이다.
암호 원리
각 기둥에 종이로 만든 띠를 감고, 기둥 면 방향으로 메시지를 적은 후 띠를 풀게 되면 종이에 적힌 문장은 알아보기 힘든 암호 문장이 됨.
전치 암호 종류
(1) 레일 펜스 암호(RAIL FENCE CIPHER)
평문의 문자를 비스듬하게 작성하고, 맨 위의 첫 번째 행부터 순서대로 취하여 암호문을 작성하는 방법
(2) 라우트 암호(ROUTE CIPHER)
m x n 격자에 평문 글자를 기록하고 읽는 방법에 따라 글자를 취하여 암호문을 작성하는 방법
(3) 주상전치 암호
특정 개수 열로 평문 문장을 배열한 후, 열 방향으로 문장을 읽어 암호문을 구성하는 암호화 방법
주상 전치 암호 구현
평문 문장 "ABCDEFGHIJKLMNOPQRS" 를 순서를 바꾸는 전치 암호를 구현해보자.
저 평문은 20글자이다.
우선 암호키를 입력받는다. 단 암호키는 중복되지 않는 문자로 이루어진 단어이다.
BRAIN 라는 5글자짜리 단어를 키로 입력받았다면 n X 5 가 주어지고, A B C D E / F G H I J... 차례대로 적는다.
A | B | C | D | E |
F | G | H | I | J |
K | L | M | N | O |
P | Q | R | S | T |
4번째 행까지이므로 4 X 5 행렬이 완성이 되었다. 이때 저기서 4는 암호 블록 크기라고 한다.
이제 키 값의 각 글자들의 상대적 순서를 확인해보면
B | R | A | I | N |
2 | 5 | 1 | 3 | 4 |
이다. 대충 먼저 나온 게 숫자가 작고, 나중에 나오는 알파벳일수록 숫자가 크다고 생각하면 된다.
3번째 열에 있는 A가 1번이므로, 아까 만든 4X5 행렬에서 3번째 열에있는 "CHMR"을 첫번째로, 두번째는 "AFKP"...이런식으로 배열들을 적으면
"CHMR AFKP DINS EJOT BGLQ" 이다. 이걸 띄어쓰기를 없애버리면
"CHMRAFKPDINSEJOTBGLQ" 이렇게 된다.
암호키의 크기가 m이라고 가정하고, 평문의 길이가 위와 같이 m의 배수면 좋겠지만 아니라면 평문의 끝에 문자 '0'으로 채워서 맞춰준다. 이 평문의 길이를 m으로 나눈 n이 바로 암호 블록의 크기이다.
평문문자를 배열할 때, u번째 문자가 포함되는 열은 i mod m 을 만족한다.이걸 각 순서 버퍼에다가 차례대로 집어넣으면 된다.
최종적으로 암호문은 버퍼1 + 버퍼2 + 버퍼3 + 버퍼4 + 버퍼5를 만족한다.
코드
ENC = 0;
DEC = 1;
def parseKey(key):
tmp = [];
key = key.upper()
for i, k in enumerate(key):
tmp.append((i, k))
tmp = sorted(tmp, key=lambda x : x[1])
enc_table = {}
dec_table = {}
for i, r in enumerate(tmp):
# print(i, r)
enc_table[r[0]] = i
dec_table[i] = r[0]
return enc_table, dec_table
def transposition(msg, key, mode):
msgsize = len(msg)
keysize = len(key)
ret = ''
filter = ''
if msgsize % keysize != 0:
filter = '0' * (keysize - msgsize % keysize)
msg = msg.upper()
msg +=filter
enc_table, dec_table = parseKey(key)
if mode == ENC:
table = enc_table
else:
table = dec_table
if mode == ENC:
buf = ['']*keysize;
for i, c in enumerate(msg):
col = i%keysize
index = table[col]
buf[index] +=c;
for text in buf:
ret +=text;
else:
blocksize = int(msgsize/keysize)
buf = ['']*keysize;
pos = 0
for i in range(keysize):
text = msg[pos:pos+blocksize];
index = table[i];
buf[index] +=text;
pos+=blocksize;
for i in range(blocksize):
for j in range(keysize):
if buf[j][i] !='0':
ret +=buf[j][i];
return ret;
def main():
key = "BRAIN"
msg = "TREASUREBOXISBURRIEDATTWOGUNDREDFEETTONORTHEASTAWAYFROMYOURHOME"
print("Original : \t%s" %msg.upper())
ciphertext = transposition(msg, key, ENC)
print("Ciphered : \t%s" %ciphertext)
deciphertext = transposition(ciphertext, key, DEC)
print("Deciphered: \t%s" %deciphertext)
if __name__ == "__main__":
main()
실행결과
PS D:\github\cryp> & C:/Users/User/AppData/Local/Programs/Python/Python311/python.exe d:/github/cryp/chap01/transcipher.py
Original : TREASUREBOXISBURRIEDATTWOGUNDREDFEETTONORTHEASTAWAYFROMYOURHOME
Ciphered : EESITNFOHARUETUXRAGETRSYYOABBEWDENEWOR0SOUDOREOAAMH0RRIRTUDTTTFOM
Deciphered: TREASUREBOXISBURRIEDATTWOGUNDREDFEETTONORTHEASTAWAYFROMYOURHOME
PS D:\github\cryp>
코드 분석
def parseKey(key):
tmp = [];
key = key.upper()
for i, k in enumerate(key):
tmp.append((i, k))
tmp = sorted(tmp, key=lambda x : x[1])
enc_table = {}
dec_table = {}
for i, r in enumerate(tmp):
# print(i, r)
enc_table[r[0]] = i
dec_table[i] = r[0]
return enc_table, dec_table
키 테이블을 만드는 것이다.
B | R | A | I | N |
1 | 4 | 0 | 2 | 3 |
으로 인덱스가 바뀌고, 저걸 알파벳 순으로 정렬하여
0 | 1 | 2 | 3 | 4 |
A | B | I | N | R |
2 | 0 | 3 | 4 | 1 |
첫 번째줄은 정렬했을 때, 세 번째 줄은 기존 BRAIN 일때 알파벳의 위치이다.
2 -> 0, 0->1, 3->2, 4->3. 1->4 로 ENC 테이블이 만들어진다.
DEC는 반대로 된다.
msgsize = len(msg)
keysize = len(key)
ret = ''
filter = ''
if msgsize % keysize != 0:
filter = '0' * (keysize - msgsize % keysize)
msg = msg.upper()
msg +=filter
키 값의 배수가 되도록 평문 맨 뒤에 0을 추가하는 과정이다.
enc_table, dec_table = parseKey(key)
if mode == ENC:
table = enc_table
else:
table = dec_table
MODE 에 따라서 암호화인지 복호화인지 결정하는 작업이다.
if mode == ENC:
buf = ['']*keysize;
for i, c in enumerate(msg):
col = i%keysize
index = table[col]
buf[index] +=c;
for text in buf:
ret +=text;
인코딩 모드일시
키 길이에 따른 buf 배열을 생성해주고, 평문을 돌면서 순서에 따라서 키 길이로 나누고, 해당 순서가 존재하는 위치에 buf에 넣어준다.
else:
blocksize = int(msgsize/keysize)
buf = ['']*keysize;
pos = 0
for i in range(keysize):
text = msg[pos:pos+blocksize];
index = table[i];
buf[index] +=text;
pos+=blocksize;
for i in range(blocksize):
for j in range(keysize):
if buf[j][i] !='0':
ret +=buf[j][i];
return ret;
복호화 할 때는 구역 만큼을 데리고 오고 똑같은 과정을 반복해준다.
에필로그
코드로만 보면 조금이해는 안 된다;
'보안 스터디 > 암호학' 카테고리의 다른 글
[암호학] 암호화 해킹 #6 (AES 및 구현) (0) | 2024.01.18 |
---|---|
[암호학] 암호화 해킹 #5 (3DES 및 구현) (1) | 2024.01.18 |
[암호학] 암호화 해킹 #4 (대칭키 암호, Symmetric-key Cryptography) (0) | 2024.01.17 |
[암호학] 암호화 해킹 #2 (카이사르 암호 도구 만들기) (2) | 2024.01.13 |
[암호학] 암호화 해킹 #1 (간단한 암호 도구 만들기 -1) (3) | 2024.01.09 |