티스토리 뷰

# AES 암호화 하는 방법에 대한 간단한 설명을 하고자 한다.


# 아래 설명하는 코드는 파이썬이지만, 언어의 종류는 별로 중요하지 않다.

# AES-128bit, 192bit, 256bit.. 가 있으며 이것은 key 즉 패스워드의 길이에 따라 정해진다.

# AES 에 대한 간략한 소개를 하면 DES 라는 1977년도에 미국에서 국가표준으로 정한 암호알고리즘이 하드웨어 발전에 의해 취약해짐에 따라 보완된 대체수단이다.

# 2001년도에 새로운 수단을 준비를 위해 AES(Advanced Encryption Standard) 만들기라는 공모전을 열었고 응모작중 가장 좋은것을 선정해 새로운 표준으로 삼게되었다.

http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf 참조.


# 실제 사용을 간단히 설명하자면 다음과 같다


key = gen_sha256_hashed_key_salt('password')

# 키, 32(256bit)바이트 짜리 값을 넣어라. 짧게 넣어야할 이유가 별로 없다.

# 이 키는 암호화, 복호화 할때 공통적으로 사용되게 된다.


mode = AES.MODE_CBC

# CBC 방식이 권장되는 분위기이므로 나는 CBC를 사용한다.

# CBC 암호화의 방식을 간단히 설명하면

# 먼저 암호화할 대상인 평문을 16바이트씩 끊는다. 만약 암호화할 대상이 총 160바이트라고 한다면 10개로 나눠진다. 이것을 10개의 블락이라고 부른다.

# 1번블락, 2번블락, 3번블락.. 10번블락까지 순서대로 암호화를 해 나간다.

# 블락을 암호화할때는 이미 암호화된 블락을 참조해서 암호화하게 된다.

# 예를 들어 평문인 3번블락을 암호화한다고 할때 이미 암호화된 2번블락의 암호화된 값을 가지고 진행한다는 말이다.

# 이때 아직 암호화가 안된 평문은 Plain 이라고 부르고, 암호화 된 암호문을 Cipher 라고 부른다.

# 자 이러면 의문이 생긴다. 가장 첫번째 블락인 1번블락을 암호화 할땐.. 무엇을 가지고 암호화를 진행해야하나?

# 그것을 위해서 우리는 IV (initialization vector, 초기화 벡터) 라는 값을 준비하고 이것을 첫번째 블락을 암호화하기 위한 값으로써 사용한다.

# 그리고 이 IV값에 의해 첫번째 블락이 암호화되고 두번째블락은 첫번째 블락에 의해 암호화 되므로 IV 의 값에 의해서 전체 결과물이 결정되게 되는 셈이다. 쉽게 말해서 첫 단추인 셈이다.

# 키, 암호화할 데이터가 고정되있을때 IV값도 고정되면 암호화된 결과도 고정된다. IV값을 랜덤하게 만들어내면 암호화된 결과는 랜덤하게 된다. 어떤게 더 강력할지는 상식적으로 생각이 가능하다.


IV = gen_random_iv()

# IV는 0번째 블락이라는 차원에서 이후 블락들과 마찬가지의 길이인 16바이트짜리 값을 넣으면 된다.


text = 'Let me tell you the huge secret! The king has a donkey ear'

# 이것은 암호화 할 평문이다.

# 첫번째 블락은 "Let me tell you "

# 두번째 블락은 "the huge secret!"

# 세번째 블락은 " The king has a "

# 네번째 블락은 "donkey ear"


# 자.. 보면 1~3번째 블락은 16바이트다. 그런데 네번째 블락은 10바이트다..

# 이렇게하고 암호화를 진행하면 에러를 낸다

# Input strings must be a multiple of 16 in length

# 암호화할 대상의 길이는 16의 배수여야한다. 즉 모든 블락은 16바이트여야한다는 소리이다.

# 네번째 블락은 10바이트이므로 이러면 안된다는 소리이다.

# 그럼 어떻게하나

# 첫번째로 암호화를 포기하는 방법이 있다.

# 두번째로 포기하지 않고 네번째 블락을 16바이트로 만들어주는 방법이 있다.


length = 16 - (len(text) % 16)

text += chr(length)*length

# 이 방법이다.

# 뭔소리냐면

# text 의 길이에서 16을 나눠서 나오는 나머지를 16으로 뺀다.

# 즉 그 나머지는 10이며 16에서 10을 빼면 6이다.

# ascii 코드에서 6번에 해당하는 값을 6개를 text에 추가한다.


# 즉 'Let me tell you the huge secret! The king has a donkey ear'+chr(6)+chr(6)+chr(6)+chr(6)+chr(6)+chr(6) 가 되는것이다.

# 결국 이것이 당신이 암호화 하게될 평문의 최종 모습인 셈이다.


encryptor = AES.new(key, mode, IV=IV)

ciphertext = encryptor.encrypt(text)

# chipertext 가 암호화 된 최종 결과물이다.

# IV 값이 랜덤하다면 최종결과물 또한 랜덤하다.

# 복호화할때 IV는 필요없고 key만 있으면 되며, 복호화 후에 결과물은 chr(6)이 6개가 추가된 모습이므로 복호화 후엔 다시 이것을 지워주는 과정이 필요하다.


# 간단한 소개는 끝났으니 그냥 복붙만 하면 실행해볼 수 있는 전체 코드를 소개한다.

# 참고로 pyCrypto 라는 모듈을 사용하니 사전에 설치가 필요하다. 설치법: pip install pycrypto


import hashlib

import Crypto

import Crypto.Random

from Crypto.Cipher import AES


def gen_sha256_hashed_key_salt(key):

salt1 = hashlib.sha256(key).digest()

return hashlib.sha256(salt1+key).digest()


def gen_random_iv():

return Crypto.Random.OSRNG.posix.new().read(AES.block_size)


def AES256Decrypt(key, iv, cipher):

encryptor = AES.new(gen_sha256_hashed_key_salt(key), AES.MODE_CBC, IV=iv)

plain = encryptor.decrypt(cipher)

plain = plain[0:-ord(plain[-1])]

return plain


def AES256Encrypt(key, plain):

length = AES.block_size - (len(plain) % AES.block_size)

plain += chr(length)*length

iv = gen_random_iv()

encryptor = AES.new(gen_sha256_hashed_key_salt(key), AES.MODE_CBC, IV=iv)

return {'cipher': encryptor.encrypt(plain), 'iv': iv}


key = 'password123qwe'

encrypted = AES256Encrypt(key, 'Let me tell you the huge secret! The king has a donkey ear')

decrypted = AES256Decrypt(key, encrypted['iv'], encrypted['cipher'])

print decrypted


# 끝

댓글
  • 프로필사진 쉬운 파이썬 Missing psarentheses in call to 'print' 라는 메세지가 나오면서 실행이 안됩니다.... 왜이런 걸까요 pycrypto는 설치 했습니다... 2017.07.16 17:53 신고
  • 프로필사진 ㅁㄴㅇ 위의 코드는 python2 기준으로 쓰여져 있기 때문에 print문에 괄호가 없습니다만
    python3를 사용하시는 경우 print( ) 형식으로 코드를 고쳐 쓰셔야 합니다.
    2017.09.12 12:01 신고
  • 프로필사진 musu.me devst ㅁㄴㅇ님 말씀 감사합니다 2017.09.27 04:49 신고
  • 프로필사진 Leni plain = plain[0:-ord(plain[-1])] 부분은 왜 해주시는거죠..ㅠ
    해석대로는 plain의 0번째 부터 plain의 마지막부분을 아스키코드로 고친 수 까지...? 인 것 같은데...
    죄송합니다 T_T 어떤 코드죠, 저 부분은?
    2017.09.21 15:35 신고
  • 프로필사진 musu.me devst 안녕하세요
    문자열에서 0번째부터 계산되어나온 수까지의 부분만을 가져오겠다는 의미인데요, 이런 과정을 거치는 이유는
    암호화를 할때 원본 데이터를 16바이트씩 쪼갯는데요 이때 마지막 조각이 16바이트로 딱 맞아떨어지지 않은 경우 이를 16바이트에 맞춰주기위해 부족한 만큼을 붙여준 값입니다.
    이 값들은 실제로 원본엔 존재하지 않은 데이터입니다. 이런 역할을 하는 데이터를 PADDING 이라고 부릅니다.
    2017.09.27 04:48 신고
댓글쓰기 폼
공지사항
Total
32,126
Today
4
Yesterday
43
링크
«   2018/11   »
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30  
글 보관함