[목차]

 

 

1. Affine 암호 프로그래밍

* 아핀 암호(Affine Cipher)를 구현하기 위한 모듈러 연산 모듈

* 아핀 암호 암복호화 프로그램

* 아핀 암호 크랙 프로그램

 

 

2. Cryptodom

* AES 데이터 암복호화

* RSA 키 생성(Generate an RSA key) 및 PEM 파일 생성

 

 

 

3. 블럭 암호 (이론)

* DES

* 트리플DES

* AES

* Rijndael

* 정리

 

 

 

 

 


 

 

 

 

 

[Affine 암호 프로그래밍]

 

 

 

1. 아핀 암호(Affine Cipher)를 구현하기 위한 모듈러 연산 모듈

 

 

 

■ 시저 암호(Caesar Cipher) : C = (P + K) mod 26

■ 곱셈 암호(Multiplication Cipher) : C = (P * K) mod 26

■ 아핀 암호(Affine Cipher) : C = (P * K1 + K2) mod 26

 

 

여러 실습에서 사용할 cryptomath.py 파일을 작성해 보자.

 

아핀(Affine) 암호 = 곱셈암호 + 시저 암호(카이사르 암호)

 

아핀 암호 구현을 위한 필요 지식

나머지 연산(modular)

최대 공약수(GCD, Greatest Common Divisor)

 

1) 나머지 연산

(수 학) 10 mod 3 : 10을 3으로 나눈 나머지

(파이썬) 10 % 3

 

2) 최대 공약수를 찾는 유클리드 알고리즘

용어: 약수, 공약수, 최대공약수

2000년 전의 수학자 유클리드(Euclid)는 나머지 연산을 통해 두 수의 GCD를 찾는 간단한 알고리즘을 고안했다.

 

■ 파이썬으로 유클리드 알고리즘 구현 => 복수 할당문 사용

-------------------------------------

def gcd(a, b):

while a != 0:

a, b = b % a, a

return b

-------------------------------------

 

(예) 유클리드 알고리즘 확인(손으로 풀어 보기)

만약 a = 24, b =32 라면,

a의 약수 : 1, 2, 3, 4, 6, 8, 12, 24

b의 약수 : 1, 2, 4, 8, 16, 32

a, b의 공약수 : 1, 2, 8

a, b의 최대 공약수 : 8

 

(예) 유클리드 알고리즘 확인(프로그램으로 확인)

만약 a = 24, b =32 라면,

첫번째 loop 돌 때(a != 0)

a , b = b % a , a

a , b = 32 % 24 , 24

a , b = 8 , 24

두번째 loop 돌 때(a != 0)

a , b = b % a , a

a , b = 24 % 8 , 8

a , b = 0 , 8

따라서, return 8

 

 

■ 아핀 암호(Affine Cipher)의 암호화

 

C = (P * K1 + K2) mod len(symbols)

 

(조건) K1, len(symbols)는 서로소 관계이어야 한다.

암호화 과정:

(ㄱ) 평문을 K1으로 곱셈

(ㄴ) K2를 더함

(ㄷ) 심볼 집합 크기로 나머지 연산

 

 

 

■ 아핀 암호(Affine Cipher)의 복호화

 

P = {(C - K2) * K1-1} mod len(symbols)

 

(조건) K1, len(symbols)는 서로소 관계이어야 한다.

복호화 과정:

(ㄱ) 암호문에서 K2를 뺀다.

(ㄴ) K1의 모듈러 역수 연산

(ㄷ) 심볼 집합 크기로 나머지 연산

 

 

 

cryptoMath.py

 

def gcd(a, b):
    # 유클리드 알고리즘으로 a와 b의 GCD(최대 공약수)를 return 한다.
    while a != 0:
        a, b = b % a, a

    return b


def find_mod_inverse(a, m):
    # "a * x % m = 1"을 만족하는 a와 m의 모듈러 역수를 return 한다.

    if gcd(a, m) != 1:
        return None     # a와 m이 서로소 관계가 아니면 모듈러 역수가 없다.

    # 확장 유클리디안 알고리즘으로 계산한다.
    u1, u2, u3 = 1, 0, a
    v1, v2, v3 = 0, 1, m
    while v3 != 0:
        q = u3 // v3    # "//"은 정수 나눗셈 연산자이다.
        v1, v2, v3, u1, u2, u3 = (u1 - q * v1), (u2 - q * v2), (u3 - q * v3), v1, v2, v3

    return u1 % m

 

 

 

 

2. 아핀 암호 암복호화 프로그램

 

affineChiper.py

#!/usr/bin/python3

#

# 아핀 암호

#

# (0) 준비 : cryptomath.py

# (1) 입력 : 평문 메시지, 암호화 키, 모드(encrypt|decrypt)

# (2) 출력 : 암호화문 또는 복호화문

# (3) 기능 : 아핀 암호를 사용하여 암호화하고 복호화 할 수 있는 프로그램을 제작한다.

 

 

import os
import sys
import random

try:
    import cryptomath

except Exception as e:
    sys.exit('Error:', e)


SYMBOLS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 !?.'


def main():
    my_message = """A computer would deserve to be called intelligent if it could deceive a human into believing that it was human. -Alan Turing"""
    my_key = 2894

    enc_msg = encrypt_message(my_message, my_key)
    print("Plaintext :", my_message)
    print("Ciphertext: ", enc_msg)

    dec_msg = decrypt_message(enc_msg, my_key)
    print("Decrypted :", dec_msg)

def decrypt_message(msg, key):
    key_a, key_b = get_key_parts(key)
    check_keys(key_a, key_b, 'decrypt')

    # P = ((C - K2) * K1(-1)) mod len(SYMBOLS)
    plaintext = ''
    for symbol in msg:
        #print(symbol)
        if symbol in SYMBOLS:
            symbol_index = SYMBOLS.find(symbol)
            mod_inverse_of_key_a = cryptomath.find_mod_inverse(key_a, key_b)
            if mod_inverse_of_key_a is not None:
                affine_index = (symbol_index - key_b) * mod_inverse_of_key_a % len(SYMBOLS)
                #print(affine_index)
                plaintext += SYMBOLS[affine_index]
        else:
            plaintext += symbol

    return plaintext


def encrypt_message(msg, key):
    # input : str(msg), int(key)
    # output : str(enc_msg)
    # function: affine cipher

    key_a, key_b = get_key_parts(key)
    #print(key_a, key_b)
    check_keys(key_a, key_b, 'encrypt')

    #   * affine cipher : C = (P * K1 + K2) mod len(SYMBOLS)
    ciphertext = ''
    for symbol in msg:
        if symbol in SYMBOLS:
            symbol_index = SYMBOLS.find(symbol)
            affine_index = (symbol_index * key_a + key_b) % len(SYMBOLS)
            #print(symbol, symbol_index)
            ciphertext += SYMBOLS[affine_index]
        else:
            ciphertext += symbol
    return ciphertext


def check_keys(key1, key2, mode):

    if key1 == 1 and mode == 'encrypt':
        sys.exit('Cipher is weak if key A is 1. Choose a different key.')
    if key2 == 0 and mode == 'encrypt':
        sys.exit('Cipher is weak if key B is 0. Choose a different key.')
    if key1 < 0 or key2 > len(SYMBOLS) -1:
        sys.exit('Key A must be greater than 0 and key B must be between 0 and %d' % (len(SYMBOLS) - 1))
    if cryptomath.gcd(key1, len(SYMBOLS)) != 1:
        sys.exit('key A (%s) and the symbol set size (%s) are not relatively prime. Choose a different key.' % (key_a, len(SYMBOLS)))


def get_key_parts(key):
    # input : int(key)
    # output : int(key1), int(key2)
    # funcrion :
    key1 = key // len(SYMBOLS)
    key2 = key % len(SYMBOLS)

    return key1, key2


if __name__ == '__main__':
    main()

 

 

 

 

 

3. 아핀 암호 크랙 프로그램

 

affineHack.py

#!/usr/bin/python3

#

# 2. 아핀 암호 해킹

#

# (0) 준비 : dictionary.txt, affineCiper.py, detectEnglish.py, cryptomath.py

# (1) 입력 : 아핀 암호을 이용한 암호화된 메시지(my_message)

# (2) 출력 : 아핀 암호 해킹을 통해 얻은 평문

# (3) 기능 : 암호문을 입력으로 받아서 아핀 암호 해킹을 통해 평문을 얻는다.

import sys
import os

try:
    import cryptomath
    import detectEnglish
    import affineCipher
except Exception as e :
    sys.exit('Error :', e)

def main():
    my_message = """5QG9ol3La6QI93!xQxaia6faQL9QdaQG1!!axQARLa!!AuaRLQADQALQG93!xQxaGaAfaQ1QX3o1RQARL9Qda!AafARuQLX1LQALQI1iQX3o1RNQ-5!1RQP36ARu"""

    hack_affine(my_message)


def hack_affine(msg):
    # input : str(msg)
    # output : affine crack action
    print('Hacking started.')
    print('Press <CTRL + C> or <CTRL + D> to quit at any time.')

    start_key = len(affineCipher.SYMBOLS)+1
    end_key = len(affineCipher.SYMBOLS) ** 2
    for key in range(start_key, end_key):
        key_a = affineCipher.get_key_parts(key)[0]
        if cryptomath.gcd(key_a, len(affineCipher.SYMBOLS)) != 1 :
            continue

        decrypted = affineCipher.decrypt_message(msg, key)
        print('Tried key %s |%s|' % (key, decrypted[:40]))

        if detectEnglish.is_english(decrypted):
            print()
            print('Possible encryption hack:')
            print('Key: %s' % key)

            print('Decrypted plaintext: ' + decrypted[:200])
            print()
            print('Enter D for done, or just press Enter to continue hacking.')
            response = input('> ')

            if response.strip().upper().startswith('D'):
                return decrypted
    return None



if __name__ == '__main__' :
    main()

 

 

 


 

 

 

 

 

[Cryptodome]

https://www.pycryptodome.org/en/latest/

 

 

1. AES 데이터 암복호화

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import os

data = 'hello world'.encode()
#print(get_random_bytes(16))
key = get_random_bytes(16)
cipher = AES.new(key, AES.MODE_EAX)
#print(cipher.encrypt_and_digest(data))
ciphertext, tag = cipher.encrypt_and_digest(data)

fd = open('encrypted.bin', 'wb')
[fd.write(x) for x in (cipher.nonce, tag, ciphertext)]
fd.close()

print(open('encrypted.bin', 'rb').read())

print('----------------------------------------------------------')

fd2 = open('encrypted.bin', 'rb')
nonce, tag, ciphertext = [fd2.read(x) for x in (16, 16, -1)]

cipher2 = AES.new(key, AES.MODE_EAX, nonce)
data = cipher2.decrypt_and_verify(ciphertext, tag)
print(data.decode())

 

 

 

 

2. RSA 키 생성(Generate an RSA key) 및 PEM 파일 생성

 

RSA 키 쌍을 생성하여 비밀 번호로 보호되는 파일로 저장한다.

사전 공격을 막기 위해 암호화 키 파생 기능을 사용한다.

또한, RSA 공개키를 ASCII/PEM 형식으로 파일에 저장한다.

 

from Crypto.PublicKey import RSA

secret_code = "Unquessable"
key = RSA.generate(2048)
print('==================private key===================')
print(key) 
encrypted_key = key.export_key(passphrase=secret_code, pkcs=8,
                              protection="scryptAndAES128-CBC")
print(encrypted_key) ; print()

fd = open('rsa_key.bin', 'wb')
fd.write(encrypted_key)
fd.close()

print('=================Public Key=====================')
print(key.publickey())
print(key.publickey().export_key())

 

 


 

 

 

[블럭 암호]

 

 

 

 

[DES]

1. DES(Data Encryption Standard)란?

DES/3DES(TDES) => AES

 

1) 대칭/비대칭, 대칭키/비밀키

 

대칭(Symmetric) 암호 알고리즘 <--> 비대칭(Asymmetric) 암호 알고리즘

비공개키 암호 알고리즘 <--> 공개키 암호 알고리즘

 

대칭키(Symmetric Key) <--> 비대칭키(Asymmetric Key)

= 비밀키(Secret Key)/공유키 <--> 공개키(Public Key)/개인키(Private Key)

 

DES 알고리즘은 암호문을 작성할 때 사용하는 암호키와 암호문을 해독할 때 사용하는 해독키가 같다. 따라서, 이 키는 절대로 외부에 유출되지 않도록 관리해야 하여 비밀키(Secret Key)라고 부른다.

또한, 양쪽 시스템이 동일 키를 사용한다고 해서 대칭키(Symmetric Key)라고도 한다. 이처럼 외부 사용자에게 노출되지 않아야 하는 암호키로 암호화하는 알고리즘을 비공개키 알고리즘이라고 한다.

 

 

 

2) DES(Data Encryption Standard)

https://en.wikipedia.org/wiki/Data_Encryption_Standard

 

DES(Data Encryption Standard)는 1977년에 미국의 연방 정보 처리 표준 규격(FIPS)으로 채택된 대칭

암호이다. DES는 64비트(8비트 parity, 56비트 + 8비트)의 키를 적용하여 64비트의 평문을 64비트의 암호문으로 암호화 시키는 대칭형 블록 암호이다. 이때, 암호문은 16번(16라운드)의 반복을 통해 만들어지는데, 이때 16번의 반복 동안 라운드 함수를 적용하고, 이때 라운드 함수에 적용되는 키는 라운트 키이다. 라운트 키는 키 스케줄에 의해 라운드 키를 발생시킨다. DES의 블록 암호 구조는 파이스텔(Feistel Cipher) 방식이다.

(AES의 블록 암호 구조는 SPN(Substitution Permutation Network) 구조이다.)

DES 알고리즘에서 사용하는 함수

- 대체(Substitution)

- 치환(Permutation)

대체와 치환은 1949년도에 클라우드 샤논(Claude Shanon)이 제시한 혼돈(Confusion)과 확산(Diffusion)이라는 두 가지 개념에 기반을 두고 있다.

전사 공격으로 해독 할 수 있는 수준

 

 

■ DES 콘테스트(DES Challenge)

1997년 DES Challenge I => 96일

1998년 DES Challenge II-1 => 41일

1998년 DES Challenge II-2 => 56시간

1999년 DES Challenge III => 22시간 15분

 

 

2. DES 암호화/복호화

64비트 평문을 64비트 암호문으로 암호화하는 대칭 암호 알고리즘

키의 비트 길이는 56비트(64비트 = 56비트 + 8비트 parity)

64비트 평문(비트열)을 하나의 단위로 모아서 암호화

 

 

 

DES 취약성 예제(출처: http://www.secmem.org/blog/2019/02/06/block-cipher/)

DES 알고리즘에서 활용되는 키는 56비트이고 암호를 만들 당시에는 충분한 길이였으나 컴퓨터의 성능이 점차 개선됨에 따라 DES는 자체적인 취약점이 발견되지 않았음에도 불구하고 키가 짧아 2016년에 들어서는 GeForce GTX 1080 Ti GPU로 모든 키를 30일 이내에 확인할 수 있는 상황이 되어 더 이상 제 기능을 할 수 없는 암호 알고리즘이 되었습니다.


[참고] "3. 취약점"

https://namu.wiki/w/DES

 

[참고] NIST, TDES 암호알고리즘의 사용제한 권고 동향 - 금융보안원

http://www.fsec.or.kr/common/proc/fsec/bbs/42/fileDownLoad/1605.do

 

[참고] 차분공격

https://ko.wikipedia.org/wiki/차분_공격

 

 

 

 

 

 

[트리플 DES의 현황]

 

현재도 은행등에서 아직 사용

처리 속도는 빠르지 않고

안정성면에서도 풀려버린 사례가 있음

우리나라에서는 3-DES를 표준으로 정하지 않음

우리나라 국가표준은 SEED(Feistel 구조), ARIA(SPN 구조)

 

 

 

[참고] 국산 암호기술 - SEED(Feistel 구조)

https://seed.kisa.or.kr/kisa/algorithm/EgovSeedInfo.do

 

[참고] 국산 암호기술 - ARIA(SPN 구조)

https://seed.kisa.or.kr/kisa/algorithm/EgovAriaInfo.do

 

 

 

 

 

 

[AES]

1. AES 란?

 

AES(Advanced Encryption Standard)

DES를 대신한 새로운 표준 대칭 암호 알고리즘

AES의 후보로서 다수의 대칭 암호 알고리즘을 제안했지만, 그중에서 Rijndael 이라는 대칭 암호 알고리즘이 2000년에 AES로서 선정

 

 

 

2. AES 선정 과정

 

NIST(National Institute of Standard and Technology)에서

공모 경쟁방식에 의한 표준화(Standardization by competition)

조건

제한 없이 무료로 이용

ANSI C와 Java에 의한 구현

암호해독에 대한 강도의 평가

암호 알고리즘 설계 규격과 프로그램 공개

 

 

 

3. AES 최종 후보 및 선정

 

1차 심사 통과: 15개

CAST256, Crypton, DEAL, DFC, E2, Frog, HPC, LOKI97, Magenta, MARS, RC6, Rijndael, SAFER+, Serpent, Twofish

 

2차 심사 통과: 5개

MARS : IBM

RC6 : RSA

Rijndael : Daemen, Rijmen

Serpent : Anderson, Biham, Knudsen

Twofish : Counterpane

 

 

 

 

 

[Rijndael]

1. Rijndael 이란?

 

벨기에 연구자 Joan Daemen과 Vincent Rijmen이 설계한 블록 암호알고리즘

블록 길이 : 128비트

키의 비트 길이: 128비트(16 bytes), 192비트(24 bytes), 256비트(32 bytes)

 

 

 

2. Rijndael 암호화/복호화

 

SPN 구조 = (혼돈)Confusion + (확산)Diffusion

SPN 구조는 Substitution Layer와 Permutation Layer 이용하여 Confustion과 Diffusion을 만족시켜는 암호다.(http://reinliebe.tistory.com/76)

 

SPN(Substitution-Permutation Network) 구조 - 복수의 라운드(round)로 구성(10~14)

SubBytes - 바이트 대체

ShiftRows - 행 이동

MixColumns - 열 섞기

AddRoundKey - 라운트 키와 XOR 연산

 

 

3. Rijndael 해독

 

Rijndael 알고리즘의 수학적 구조

Rijndael 수식을 수학적인 조작에 의해 풀수 있다면, Rijndael을 수학적으로 해독할 수 있을 것이다.

Rijndael에 대한 유효한 공격은 현재로서는 발견되지 않았다.

 

 

 

[정리]

 

어떤 암호를 사용하면 좋은가?

 

(X) DES/3DES => (0) AES

 

DES는 사용하지 말 것!

단, 과거 소프트웨어와의 호환성 유지를 위해 필요.

 

트리플 DES는 호환성 때문에 앞으로도 당분간 사용,

점차 AES로 대체

 

AES(Rijndael)

고속

다양한 플랫폼

현재까지 안전

사용 권장

AES 최종 후보 5개도 사용가능

 

 

[참고] AES 관련 정보

http://index-of.co.uk/Cryptology/06-AES.pdf

http://huammmm1.tistory.com/381

 

 

 

 

대칭 암호

* 블록 암호 : DES/3DES(시험에 많이 나옴), AES

* 스트림 암호

비대칭 암호

* 공개키 암호

* 공개키 서명

해시 암호

 

 

 

1. 대칭키 암호

스트림 암호(ex: ARC4, chacha20, XchaCha20, Salsa20)

블록 암호(ex: DES/3DES, AES, SEED, ARIA)

 

 

2. DES(Data Encryption Standard) - Feistel 구조

키 : 56비트

* 키(56비트) => 키 스케줄 => 서브키(48비트 x 16)

암호시스템 : Feistel 구조, F함수, S-BOX

입력 : 64비트 평문블록

출력 : 64비트 암호문

 

 

3. 3DES(Triple DES) - Feistel 구조

DES-EDE2

DES-EDE3

 

 

4. AES(Advanced Encryption Standard) - SPN 구조

키 : 128비트, 192비트(128+64), 256비트(128+128)

암호시스템 : SPN 구조

입력 : 128비트 평문블록

출력 : 128비트 암호문

 

728x90

+ Recent posts