미국 남북전쟁 암호해독(1)

mnsng88·2023년 2월 23일
0
post-thumbnail

✨프로젝트 설명

암호학을 맛보는 프로젝트이다.
암호학의 목표 중 하나는 키를 사용하여 평문을 읽을 수 없는 비문으로 암호화하고 이를 다시 평문으로 복호화하는 것이다.
우리는 미국 남북 전쟁에서 사용된 2개의 암호, 루트 전치 암호(북부)와 레일 펜스 암호(북부, 남부)를 탐구한다.


🙋질문

  1. 루트 전치 암호가 뭔가요?

전치 암호(위키피디아)
위키피디아와 이 책에서 말하는 바에 따르면 전치 암호는 간단히 말해서 단어 속 글자들의 순서를 바꾸는 것이라 보면 된다.

루트 전치 암호를 더 잘 이해하기 위해서 우리만의 루트 전치 암호를 작성해볼 것인데, 이를 제어 메시지라고 부른다.

  • 열의 개수 = 4
  • 행의 개수 = 5
  • 시작위치 = 좌측하단
  • 루트 = 열 상하 반복
  • 평문 = 0 1 2 3 ~ 19
  • 비문 = 16 12 8 4 0 1 5 9 13 17 18 14 10 6 2 3 7 11 15 19
  • 키 = -1 2 -3 4
onetwothreefour
0123
4567
891011
12131415
16171819

키는 루트의 순서와 방향을 알려준다.
음수는 하단에서 위로 올라간다는 뜻이고, 양수는 그 반대의 의미를 가진다.


🧑‍💻의사코드

Load the ciphertext string.
Convert ciphertext into a cipherlist to split out individual words.
Get input for the number of columns and rows.
Convert key into a list to split out individual numbers.
Create a new list for the translation matrix.

For every number in the key:
	Create a new list and append every n items (n = # of rows) from the cipherlist.
    Use the sign of key number to decide whether to read the row forward or backward.
    Using the chosen direction, add the new list to the matrix. The index of each new list is based on the column number used in the key.
    
Create a new string to hold translation results.

For range of rows:
	Remove the last word in nested list
    Add the word to the translation string.
    
Print the translation string.
    

💻코드

route_cipher_decrypt_prototype.py

ciphertext = "16 12 8 4 0 1 5 9 13 17 18 14 10 6 2 3 7 11 15 19"

# 각각의 요소를 단어로 나눈다(글자로 나누는 것이 아님!!!)

cipherlist = list(ciphertext.split()) # 1번

# 초기 변수 값 설정하기
COLS = 4 # 가로
ROWS = 5 # 세로
key = '-1 2 -3 4'
translation_matrix = [None] * COLS
plaintext = ''
start = 0
stop = ROWS

# key_int를 정수형 리스트로 변환
key_int = [int(i) for i in key.split()] # 2번

# turn columns into items in list of lists
for k in key_int:
    if k < 0: # reading bottom-to-top of column
        col_items = cipherlist[start:stop] 
    elif k > 0: # reading top-to-bottom of column
        col_items = list((reversed(cipherlist[start:stop]))) # reversed method

    print(col_items) # type: ignore
    translation_matrix[abs(k) - 1] = col_items # type: ignore # 3번
    start += ROWS
    stop += ROWS

print("\nciphertext = {}".format(ciphertext))
print("\ntranslation matrix =", *translation_matrix, sep="\n")
print("\nkey length = {}".format(len(key_int)))    

# loop through nested lists popping off last item to new list:
for i in range(ROWS):
    for col_items in translation_matrix:
        word = str(col_items.pop()) # type: ignore # 4번
        plaintext += word + ''

print("\nplaintext = {}".format(plaintext))

🕵🏼분석

1번

cipherlist = list(ciphertext.split())
  • split 매서드
    split 매서드
    문자열.split(sep, maxsplit) 함수는 문자열을 maxsplit 횟수만큼 sep의 구분자를 기준으로 문자열을 구분하여 잘라서 리스트로 만들어 준다.
    sep 파라미터의 기본값은 NONE이고, 띄어쓰기, 엔터를 구분자고 해서 문자열을 자른다.
    maxsplit 파라미터의 기본값은 -1이고 제한없이 자를 수 있을 때 까지 문자열 전체를 자른다.
  • list()
    아래의 코드는 range(4)에 해당하는 0, 1, 2, 3의 값을 list의 형태로 list1에 저장한다.
list1 = list(range(4))

굳이 split매서드로도 리스트로 나타낼 수 있는데 list()를 사용한 이유는 새로운 list를 만들고 싶어서이다.(나중에 ciphertext를 출력하기때문)


2번

key_int = [int(i) for i in key.split()]
number = []
for i in range(1, 10):
	number.append(i)

위와 같은 리스트를 생성하는 코드를 다음과 같이 리스트 컴프리헨션으로 표기할 수 있다.

[i for i in range(10)]

이미지로 보면 다음과 같다.
이미지 출처: https://wikidocs.net/22805


3번

translation_matrix[abs(k) - 1] = col_items
  • abs()
    절대값 함수라고 불리며 괄호안에 절대값을 구하고 싶은 수를 매개변수로 집어넣는다.
    매개변수로 넣은 수의 절대값을 반환한다.

4번

for i in range(ROWS):
    for col_items in translation_matrix:
        word = str(col_items.pop()) # type: ignore
  • pop() 매서드
list = [1, 2, 3, 4]
element1 = list.pop() # 위치 지정 안함
element2 = list.pop(0) # 위치 지정 함
print(element1) # >>> 4
print(element2) # >>> 1
print(list) # >>> [2, 3]

위치를 지정한다면 지정 위치의 요소를 제거하고 제거된 요소를 반환한다.
위치를 지정하지 않으면 바로 아래에서 살펴볼 stack자료구조로 가장 마지막 요소가 제거되고 그 요소를 반환한다.
자료 참고

  • stack 자료구조
    스택(stack)은 데이터의 삽입과 삭제가 데이터의 가장 한쪽 끝에서만 일어나는 자료구조이다. 가장 마지막에 삽입된 데이터가 가장 먼저 사용되거나 삭제된다.
    데이터를 삽입하는 과정을 push, 가장 마지막에 삽입한 데이터를 삭제하는 과정을 pop라고 한다. 데이터를 삭제하는 pop은 현재 스택에 데이터가 비어있는지 여부를 먼저 확인하고 실행한다.
    top와 isEmpty라는 메소드도 있는데 top은 가장 마지막에 삽입한 데이터를 삭제하지 않고 return 해주는 메소드이고, isEmpty는 현재 스택이 비어있는지 여부를 확인하는 메소드이다.
  • str()
    문자열 형태로 객체를 반환해서 return 하는 함수이다. 위의 코드에서는 plaintext를 완성하는 과정에서 행의 숫자들을 모아 연결해야 하기에 str()를 사용했다.

  • #type: ignore
    #type: ignore에 대한 설명

    You can use the form # type: ignore[code] to only ignore specific errors on the line. This way you are less likely to slience unexpected errors that are not safe to ignore, and this will also document what the purpose of the comment is.

    추가 자료(mypy 1.0.1 documentation)
    It's possible to silence specific error codes on a line using # type: ignore[code]. This way you won't accidentally ignore other, potentially more serious errors.

profile
능동적으로 행동함으로써 세상을 더 좋게 가꾸어가는 사람

0개의 댓글