[5주차] 암호 문서화 과제

  1. AES
    공개키, 대칭 알고리즘
    128,192,256 비트 세 가지 종류가 AES 표준

알고리즘

  1. 평문을 128비트 또는 16바이트 블록화
  2. 열 우선 행렬 생성(state matrix)
  3. KeyExpansion: 암호화 키 가져와서 추가키 생성, 각 라운드마다 key 하나 생성 -> round key
  4. AddRoundKey: 라운트 키의 각 바이트 XOR 상태 행렬의 바이트,
    ( x_{i,j} = p_{i,j} \oplus k_{i,j} )
  5. 일련의 라운드 수행: SubBytes -> ShiftRows -> MixColumns(마지막 라운드 제외) -> AddRoundKey
#예제에서 쓰인 블록 암호 모드는 ECB, 해당 부분 설명으로 아래서... 
import string
import random
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad

#암호화 
def aes_encrypt(key, plaintext):
    cipher = AES.new(key, AES.MODE_ECB)
    ciphertext = cipher.encrypt(pad(plaintext.encode('utf-8'), AES.block_size)) #AES 사이즈 지정 
    return ciphertext

#복호화 
def aes_decrypt(key, ciphertext):
    cipher = AES.new(key, AES.MODE_ECB) #이때 key는 대칭키 
    decrypted_data = unpad(cipher.decrypt(ciphertext), AES.block_size)
    return decrypted_data.decode('utf-8')
  1. DES
    비밀키, 대칭 암호 알고리즘

알고리즘

  1. Initial permutation: 각 비트 치환
  2. 라운드 함수로 서로 다른 서브키로 각 비트 치환
  3. 블록화
  4. Final permutation: 한 번 더 치환
from Crypto.Cipher import DES
from Crypto.Hash import SHA256 as SHA

class myDES():

    # DES 초기화
    def __init__(self, keytext, ivtext):
        hash = SHA.new()
        hash.update(keytext.encode('utf-8'))
        # keytext를 해시화했을 때 첫 8byte를 key로 함
        key = hash.digest()
        self.key = key[:8]

        hash.update(ivtext.encode('utf-8'))
        iv = hash.digest()
        # ivtext를 해시화했을때 첫 8byte를 iv로 함
        # iv는 CBC 모드 운영을 위한 초기화벡터를 말함 
        self.iv = iv[:8]

    # ECB 모드로 암호화
    def encrypt_ECB(self, plaintext):
        # 항상 8byte 단위로 끊어서 암호화하기 때문에 평문이 8byte로 끊기지 않는다면 
        # padding값을 추가해 8byte로 만들어줌
        while(len(plaintext) % 8 != 0):
            plaintext += ' '
        des = DES.new(self.key, DES.MODE_ECB)
        encryptMsg = des.encrypt(plaintext.encode())
        return encryptMsg

    # ECB 모드로 암호화된 암호문을 복호화
    def decrypt_ECB(self, ciphertext):
        des = DES.new(self.key, DES.MODE_ECB)
        descryptMsg = des.decrypt(ciphertext)
        return descryptMsg

    # CBC 모드로 암호화
    def encrypt_CBC(self, plaintext):
        while(len(plaintext) % 8 != 0):
            plaintext += ' '

        # CBC 모드에서는 iv(초기화 벡터) 값이 필요
        des = DES.new(self.key, DES.MODE_CBC, self.iv)
        encryptMsg = des.encrypt(plaintext.encode())
        return encryptMsg

    # CBC 모드로 암호화된 암호문을 복호화
    def decrypt_CBC(self, ciphertext):
        des = DES.new(self.key, DES.MODE_CBC, self.iv)
        descryptMsg = des.decrypt(ciphertext)
        return descryptMsg
  1. RSA
    비대칭 암호 알고리즘
    공개키, 비밀키 모두 사용하는데, 공개키는 암호화할 때, 비밀키는 복호화할 때 사용

알고리즘

  1. 두 큰 소수를 곱해서 공개키 생성
  2. 이때 개인키는 (공개키X개인키)mod 오일러(p*q)=1인 숫자 -> ( (e * d) \mod \Phi(n) = 1 )
    ( n = p * q ) (p, q는 소수)
    ( \Phi(n) = (p — 1) * (q — 1) )
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP

def generate_keys():
    key = RSA.generate(2048)
    # 개인키 생성 
    private_key = key.export_key()
    # 공개키 생성, 이때 서로 소수 
    public_key = key.publickey().export_key()
    return private_key, public_key

# 암호화 
def encrypt_message(public_key, message):
    rsa_key = RSA.import_key(public_key)
    # OAEP는 RSA와 함께 사용되는 Padding 
    cipher = PKCS1_OAEP.new(rsa_key)
    encrypted_message = cipher.encrypt(message.encode())
    return encrypted_message

# 복호화 
def decrypt_message(private_key, encrypted_message):
    # key import(개인키) 
    rsa_key = RSA.import_key(private_key)
    cipher = PKCS1_OAEP.new(rsa_key)
    decrypted_message = cipher.decrypt(encrypted_message).decode()
    return decrypted_message
  1. 해시 함수
    해시 함수들은 복호화되지 않는다. 한 번 압축함수를 거치면 되돌릴 수 없다(예측 불가능성)
    해시 암/복호화 툴 사이트 (CTF에서 필요할 때 들어가기..)

4-1. SHA256
SHA 해시 함수는 1, 256, 384 등.. 다양함
어떤 입력값이든 고정된 길이 n(SHA256에서는 256)으로 변환 처리한다.

알고리즘
1) 패딩 -> 512bit의 배수가 되도록
2) 파싱 -> 32bit씩 나눈다.
3) 해싱

import hashlib #이전 암호 라이브러리와 다르다 

# SHA-256 해시 객체 생성
hash_object = hashlib.sha256()

# 데이터 업데이트
hash_object.update(data.encode())

# 해시 값 추출
hash_value = hash_object.hexdigest()

4-2. MD5
128비트 길이를 만들어주는 해시 함수
SHA1보다는 안전하나 지금은 원본을 찾을 수 있는 빠른 알고리즘이 나와 잘 사용하진 않는다.

알고리즘

  1. 데이터 비트 오른쪽에 1
  2. 비트 길이 448(mod 512)되도록 0 패딩(오른쪽에)
  3. 마지막 64비트에 padding되기 전 데이터 길이 저장(리틀 엔디언)
  4. 512비트 블록으로 쪼개기
  5. 각 블록에 대해 연산
import hashlib

result = hashlib.md5(data.encode()).hexdigest()
  1. 블록 암호
    평문을 분할하여 m길이*n개 블록을 만드는 알고리즘이다.
    운영모드는 5가지가 있는데 ECB, CBC, CFB, OFB, CTR
5-1. ECB
블록 단위로 나누고 각 블록마다 key로 암호화
반복 공격에 취약하다.

ECB

5-2. CBC
iv로 첫 블록을 암호화하고 다음 블록은 이전 암호와 평문을 xor 후 key로 암호화
초기 iv가 동일하며 출력 결과가 동일한 취약점이 있다.

CBC

5-3. CFB
iv로 첫 블록 암호화하고 이후 블록은 key와 암호화 후 평문과 xor
재전송 공격에 취약하다.

CFB

5-4. OFB
CFB와 이전 블록의 결과를 가져다 쓰는 위치가 다르다(그림으로 확인하기)
OFB는 xor 전 암호화 결과를 다음 블록에서 사용한다.

OFB

5-5. CTR
암호화 할 때마다 증가하는 Counter 변수를 두고, 이것을 key와 암호화

CTR