현대 암호학

[현대 암호학] 03. 실습(2)

Uggjjini 2021. 6. 22. 12:33

[실습] 전치 암호(Transposition Cipher)

 

단순 전치 암호

= 주상 전치 암호

= 열 방향 전치 암호

 

 

 

주상 전치 암호(열 방향 전치 암호, 단순 전치 암호) 만들기

 

전치 암호의 종류들

  • 단순 전치 암호
  • 레일 펜스(Rail Fence)
  • 경로(Route) 암호
  • 가로장 암호
  • 미즈코우스키(Myszkowski) 전치 암호
  • 분할된 전치 암호
  • 기타

 

간단한 전치 암호 중 하나인 "열 방향(columnar) 전치 암호"에 대한 프로그램을 만들어 보자.

 

() 주상 전치 암호 - 암호화

평문 : "Common sense is not so common." : 30글자

 : 8

암호문 : "Cenoonommstmme oo snnio. s s c" : 30글자

 

transpositionEncrypt.py

# 주상 전치 암호화 - 1st version
#
# (1) 입력 : 평문 메세지 (Input: Common sense is not so common.)
# (2) 출력 : 주상 전치 암호화/복호화 후 메세지 (Ouput: |Cenoonommstmme oo snnio. s s c|)
# (3) 기능 :
# * 평문 메세지를 입력으로 받아서
# * 주상 전치 암호화 알고리즘을 이용하여 암호화/복호화 한다.
# (4) [참고] 전치 암호화 과정
# 1) messages key의 문자 수를 센다.
# 2) 키와 같은 개수의 상자를 한줄에 그린다.(: 키가 8개면 상자 8)
# 3) 왼쪽에서 오른쪽으로 상자를 채우고 상자 한개에 글자 한개를 넣는다.
# 4) 문자가 상자 끝에 이르면 상자의 줄을 한 줄 더 그린다.
# 5) 마지막 문자까지 오면 마지막 행에 있는 사용하지 않은 상자는 칠해 둔다.
# 6) 왼쪽 상단부터 시작해 각 열을 내려가면서 문자를 쓴다.
# 열의 가장 아래에 이르면 오른쪽의 다음 열로 이동한다.
# 지운 상자는 건너뛴다. 이것이 암호문이 된다.
암호시스템 : 주상 전치 암호
 : 8
입력 평문 : Common sense is not so common.
출력 암호문: ?
def main():
    mymsg = "Common sense is not so common."
    mykey = 8
    print("Plaintext : |%s|" %mymsg)

    myencrypted = transposition_cipher(mymsg, mykey)
    print("Encrypted : |%s| " %myencrypted)

def transposition_cipher(msg, key):
    # input: str(msg), int(key)
    # output: str(encrypted)
    # function:
    #   * transposition cipher with key = 8
    encrypted = [''] * key
    for n, c in enumerate(msg):
        str_index = n % key
        encrypted[str_index] += c

    return ''.join(encrypted)

if __name__ == '__main__':
    main()

 

() 주상 전치 암호 - 복호화

암호문 : "Cenoonommstmme oo snnio. s s c" : 30글자

 : 8

평문 : "Common sense is not so common." : 30글자

 

(조건) msg = "....", key = 8

메세지 전체 크기: 30

전체 박스의 크기: 4 * key = 32

math.ceil(30 / 8) = 4

 

블랙 박스의 크기: 32 - 30 = 2

블랙 박스의 index ?

(32 - 1) - (i * 4)

 

문자열의 특정 index안에 ^ 문자 넣기

* str = str[:num] + ^ + str[num:]

 

transpositionDecrypt.py

# 주상 전치 복호화 - 1st version
#
# (1) 입력 : 평문 메세지 (Input: Common sense is not so common.)
# (2) 출력 : 주상 전치 암호화/복호화 후 메세지 (Ouput: )
# (3) 기능 :
# * 평문 메세지를 입력으로 받아서
# * 주상 전치 암호화 알고리즘을 이용하여 암호화/복호화 한다.
# (4) [참고] 전치 암호화 과정
# 1) messages key의 문자 수를 센다.
# 2) 키와 같은 개수의 상자를 한줄에 그린다.(: 키가 8개면 상자 8)
# 3) 왼쪽에서 오른쪽으로 상자를 채우고 상자 한개에 글자 한개를 넣는다.
# 4) 문자가 상자 끝에 이르면 상자의 줄을 한 줄 더 그린다.
# 5) 마지막 문자까지 오면 마지막 행에 있는 사용하지 않은 상자는 칠해 둔다.
# 6) 왼쪽 상단부터 시작해 각 열을 내려가면서 문자를 쓴다. 열의 가장 아래에 이르면 오른쪽의 다음 열로 이동한다.
# 지운 상자는 건너뛴다. 이것이 암호문이 된다.
암호 시스템: 주상 전치 암호
입력 암호문: Cenoonommstmme oo snnio. s s c
 : 8
출력 평문 : ?
 
 올림
import math
math.ceil(len(messages)/key)

 올림, 내림, 반올림
math.ceil() : 올림,
math.floor(), 내림,
math.round() : 반올림
import math

def main():
    mymsg = "Common sense is not so common."
    mykey = 8
    print("Plaintext : |%s|" %mymsg)

    myencrypted = transposition_cipher_encrypt(mymsg, mykey)
    print("Encrypted : |%s| " %myencrypted)

    mydecrypted = transposition_cipher_decrypt(myencrypted, mykey)
    print("Decrypted : |%s| " %mydecrypted)

def transposition_cipher_decrypt(msg, key):
    # 메시지 전체 크기 : 30
    msg_total_size = len(msg)
    
    # 리스트 인덱스 값 : 4
    list_index = math.ceil(msg_total_size / key)
    
    # 블랙 박스의 크기 : 2
    array_total_size = list_index * key
    black_box_size = array_total_size - msg_total_size
    
    # 블랙 박스 리스트 : [27, 31]
    black_box_list = []
    for i in range(black_box_size):
        black_box_index = (array_total_size - 1) - (i * list_index)
        black_box_list.append(black_box_index)
    black_box_list.reverse()
    
    # 메세지 안에 특수문자(^) 집어 넣기 : .....^...^
    for j in black_box_list:
        msg = msg[:j] + '^' + msg[j:]
  
    # 복호화 목록을 담은 리스트 
    decrypted_list = [''] * list_index
    # 메세지를 받아서 복호화 리스트안에 나누어 담기 
    for n, k in enumerate(msg):
        decrypted_list_index = n % list_index
        decrypted_list[decrypted_list_index] += k
        
    # 리스트 안의 스트링을 붙이고 msg_total_size 만큼만 자르기
    decrypted = ''.join(decrypted_list)
    decrypted = decrypted[:msg_total_size]

    return decrypted


def transposition_cipher_encrypt(msg, key):
    # input: str(msg), int(key)
    # output: str(encrypted)
    # function:
    #   * transposition cipher with key = 8
    encrypted = [''] * key
    for n, c in enumerate(msg):
        str_index = n % key
        encrypted[str_index] += c

    return ''.join(encrypted)

if __name__ == '__main__':
    main()

 


[실습] 전치 암호 테스트 프로그램 - Transposition Cipher Test

주상 전치 암호의 암호화/복호화가 같은지 테스트 하는 프로그램 만들기

 

프로그램을 테스트 하는 프로그램밍 기법을 소개한다.

 

  • 입력 평문의 랜덤화
  • 암호화/복호화 확인
  • 암호화/복호화 성능 측정

 

transpositionTest.py

# 전치 암호 테스트 프로그램 - lst version
#
# (0) 준비 : transposition.py
# (1) 입력 : 임의의 길이의 임의의 문자열
# (2) 출력 : 암호화, 복호화된 메세지가 같은지 출력
# (3) 기능 : 입력 메세지를 압호화, 복호화하고 입력메세지와 복호화된 메세지가 같은지 확인

 

[참고 사항]


random 모듈 import 방법과 .seed(), .randint(), .suffile() method 설명
import random
random.seed(42)
random.randint(4, 40)
random.shuffle(list)


for i in range(int(random.randint(message/2))) ; print(i)
random.seed(42) 의미


import random
numbers = []
for i in range(20):
numbers.append(random.randint(1, 10))
print(numbers)
여러번 실행 시켜 본다.
[5, 9, 8, 3, 6, 2, 3, 9, 9, 1, 7, 4, 1, 8, 10, 2, 7, 10, 1, 7]
[8, 4, 8, 1, 2, 5, 2, 2, 6, 5, 3, 1, 2, 5, 9, 9, 9, 10, 7, 3]
[10, 9, 1, 5, 2, 10, 1, 2, 9, 4, 9, 3, 9, 4, 1, 10, 5, 10, 4, 7]


import random
random.seed(42)
numbers = []
for i in range(20):
numbers.append(random.randint(1, 10))
print(numbers)
여러번 실행 시켜 본다.
[2, 1, 5, 4, 4, 3, 2, 9, 2, 10, 7, 1, 1, 2, 4, 4, 9, 10, 1, 9]
[2, 1, 5, 4, 4, 3, 2, 9, 2, 10, 7, 1, 1, 2, 4, 4, 9, 10, 1, 9]
[2, 1, 5, 4, 4, 3, 2, 9, 2, 10, 7, 1, 1, 2, 4, 4, 9, 10, 1, 9]

 

import random
import sys

import transposition


def main():
    random.seed(42)  # 무작위 랜덤 함수의 초기화를 위한 시드값을 상수로 설정 한다.

    for i in range(20):     # 20회 테스트 한다.
        # 테스트용 무작위 메세지를 생성한다.
        # 생성된 메세지는 길이가 임의의 값이 될것이다.
        message = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' * random.randint(4, 40)

        # plaintext 문자열을 뒤섞기 위해 리스트를 만든다.
        message = list(message)
        # 리스트의 요소 뒤섞기
        random.shuffle(message)
        # 리스트를 다시 문자열로 전환
        message = ''.join(message)

        print("Test #%s: |%s|" % (i+1, message[:50]))

        # 각 message에 대해 가능한 모든 키 값을 확인한다.
        for key in range(1, int(len(message)/2)):
            encrypted = transposition.transposition_cipher_encrypt(message, key)
            decrypted = transposition.transposition_cipher_decrypt(encrypted, key)

            # 원래 message의 복호화된 message가 틀리면 에러 메세지를 출력하고 종료
            if message != decrypted:
                print('Mismatch with key %s and plaintext %s' % (key, message))
                print('Decrypted as: ' + decrypted)
                sys.exit(1)

    print('Transposition cipher test passed.')


if __name__ == '__main__':
    main()

 


[실습] 파일을 입력 받아 전치 암호화 또는 복호화 수행후 파일에 저장하기

 

파일을 입력 받아 주상 전치 암호화 또는 복호화 후 그 내용을 다시 파일에 저장하기

디스크에서 파일을 읽거나 쓰는 프로그램을 작성하는 방법을 다룬다.

 

(준비) frankenstein.txt, transposition.py

# 전치 파일 암호 암호화/복호화 - 1st version
#
# (0) 준비: frankenstein.txt, transpositionEncrypt.py, transpositionDecrypt.py
# (1) 입력: 파일이름(EX: frankenstein.txt)
# (2) 출력: 암호화된 파일(EX: frankenstein.encrypted.txt)
# (3) 기능:
# * 파일을 입력 받아 암호화 또는 복호화 수행한 후 그 내용을 다시 파일로 생성한다.

 

transpostionFileCipher.py

import random
import sys

import transposition


def main():
    random.seed(42)  # 무작위 랜덤 함수의 초기화를 위한 시드값을 상수로 설정 한다.

    for i in range(20):     # 20회 테스트 한다.
        # 테스트용 무작위 메세지를 생성한다.
        # 생성된 메세지는 길이가 임의의 값이 될것이다.
        message = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' * random.randint(4, 40)

        # plaintext 문자열을 뒤섞기 위해 리스트를 만든다.
        message = list(message)
        # 리스트의 요소 뒤섞기
        random.shuffle(message)
        # 리스트를 다시 문자열로 전환
        message = ''.join(message)

        print("Test #%s: |%s|" % (i+1, message[:50]))

        # 각 message에 대해 가능한 모든 키 값을 확인한다.
        for key in range(1, int(len(message)/2)):
            encrypted = transposition.transposition_cipher_encrypt(message, key)
            decrypted = transposition.transposition_cipher_decrypt(encrypted, key)

            # 원래 message의 복호화된 message가 틀리면 에러 메세지를 출력하고 종료
            if message != decrypted:
                print('Mismatch with key %s and plaintext %s' % (key, message))
                print('Decrypted as: ' + decrypted)
                sys.exit(1)

    print('Transposition cipher test passed.')


if __name__ == '__main__':
    main()