2016년 12월 12일 월요일

파이썬 암호학 공부

파이썬 공부

모듈을 단축 이름으로 사용하는 방법.

import nump as np
# 위와 같이 선언하면 numpy 모듈을 np로 호출하여 사용
파일 읽기 전용
file = open(file path, 'rt')    #텍스트 읽기 모드로 파일을 오픈
file = open(file path, 'rb')    #바이너리 읽기 모드로 파일을 오픈
파일 쓰기 전용
file = open(file path, 'wt')    #텍스트 쓰기 모드
file = open(file path, 'wb')    #바이너리 쓰기 모드
파일 생성 후 읽고 쓰기 전용
file = open(file path, 'wt+')    #텍스트 쓰기 모드로 파일 생성 후 오픈
file = open(file path, 'wb+')    #바이너리 쓰기 모드로 파일 생성 후 오픈
기존 파일의 맨 뒤에 내용을 추가하기(읽기 가능)
file = open(file path, 'at')    #텍스트 추가 모드로 파일 생성 후 오픈
file = open(file path, 'ab')    #바이너리 추가 모드로 파일 생성 후 오픈
일반적으로 파일 읽는 코드
file = open('read.txt','rt')
content = ''
content = file.read()
print(content)
file.close()

카이사르 암호

ENC = 0
DEC = 1

def makeDisk(key):
    keytable = map(lambda x: (chr(x+65), x), range(26))
    # key는 알파벳 1자

    #keytable의 형식이 key2index에 들어감, {알파벳 문자: 문자 인덱스} 형식
    key2index = {}    
    for t in keytable:
        alphabet, index = t[0], t[1]
        key2index[alphabet] = index
    #키가 존재하면, key에 해당하는 문자 인덱스 할당
    if key in key2index:
        k = key2index[key]
    #그렇지 않으면 None 반환
    else:
        return None, None

    enc_disk = {}    #{평문 문자: 암호문 문자}
    dec_disk = {}    #{암호문 문자: 평문 문자}

    for i in range(26):
        enc_i = (i+k)%26    #카이사르 암호문, (i+k)mod 26 구현
        enc_ascii = enc_i + 65
        enc_disk[chr(i+65)] = chr(enc_ascii)
        dec_disk[chr(enc_ascii)] = chr(i+65)

    return enc_disk, dec_disk
# 암호문을 만들거나 암호문을 평문으로 만드는 함수
def caesar(msg, key, mode):
    ret = ''    #반환 값 저장하는 변수

    msg = msg.upper()    #대문자 변환
    enc_disk, dec_disk = makeDisk(key)

    if enc_disk is None:    #결과가 None이면 None 반환
        return ret

    if mode is ENC:        #ENC면 enc_disk, DEC면 dec_disk
        disk = enc_disk
    if mode is DEC:
        disk = dec_disk

    #문자 숫자 구분 처리
    for c in msg:
        if c in disk:
            ret += disk[c]
        else:
            ret += c
    return ret

def main():
    plaintext = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    key = 'F'

    print('Original:\t%s' %plaintext.upper())
    ciphertext = caesar(plaintext, key, ENC)
    print('Caesar Cipher:\t%s' %ciphertext)
    deciphertext =  caesar(ciphertext, key, DEC)
    print('Deciphered:\t%s' %deciphertext)

if __name__ == '__main__':
    main()

코드 세부 설명

keytable = map(lambda x: (chr(x+65), x), range(26))

keytable을 출력하면 다음과 같은 값이 저장된다.

keytable[('A', 0), ('B', 1), ('C', 2), ('D', 3), ('E', 4), ('F', 5), ('G', 6), ('H', 7), ('I', 8), ('J', 9), ('K', 10), ('L', 11), ('M', 12), ('N', 13), ('O', 14), ('P', 15), ('Q', 16), ('R', 17), ('S', 18), ('T', 19), ('U', 20), ('V', 21), ('W', 22), ('X', 23), ('Y', 24), ('Z', 25)]

lambda함수

lambda 인자, 인자, ...

제곱수를 반환해주는 함수
ex)

>>> f = lambda x: x*x
>>> f(2)
4

원하는 문자열을 추가하여 반환하는 함수
ex)

>>> f = lambda x: x + '.txt'
>>> f('abc')
'abc.txt'

원하는 문자열 반복 반환해주는 함수
ex)

>>> f = lambda x, count: x*count
>>> f('abc', 2)
'abcabc'

숫자 인자를 받아 +65를 더한 값을 ASCII 문자와 입력 받은 숫자를 튜플로 리턴 하는 함수
ex)

>>> f = lambda x: (chr(x+64), x)
>>> f(0)
('A',0)

map함수

반복 가능한 자료형을 순처적으로 뽑을 때 사용하는 함수
map(함수, 반복 가능한 자료)

chr()

ASCII에 해당하는 문자 반환

>>> chr(65)
A

ord()

ASCII 코드를 반환

>>> ord('A')
65

아핀 암호

카이사르의 변형으로 암호키의 개수를 늘린 암호화 방법

Enc(i) = (k1*i+k2) mod 26

k1: 26과 서로소인 25이하 양수, k1 = {1,3, 5, 7, 8, 11, 15, 17, 19, 21, 23, 25}    
k2: 25이하 양수 또는 0, k2 = {1...25}

곧 키는 2개 k1, k2가 된다.

ENC = 0
DEC = 1

def makeDisk(k1, k2):
    enc_disk = {}
    dec_disk = {}

    for i in range(26):
        enc_i = (k1*i+k2)%26
        enc_ascii = enc_i + 65
        enc_disk[chr(i+65)] = chr(enc_ascii)
        dec_disk[chr(enc_ascii)] = chr(i+65)
    return enc_disk, dec_disk

def affine(msg, key1, key2, mode):
    ret = ''
    msg = msg.upper()
    enc_disk, dec_disk = makeDisk(key1, key2)

    if mode is ENC:
        disk = enc_disk
    if mode is DEC:
        disk = dec_disk

    for c in msg:
        if c in disk:
            ret += disk[c]
        else:
            ret += c
    return ret

def main():
    plaintext = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    key1 = 3
    key2 = 5

    print('Original:\t%s' %plaintext.upper())
    plaintext = affine(plaintext, key1, key2, ENC)
    print('Affine Cipher:\t%s' %plaintext)

    plaintext = affine(plaintext, key1, key2, DEC)
    print('Deciphered:\t%s' %plaintext)

if __name__ == '__main__':
    main()

댓글 없음:

댓글 쓰기