대칭키 암호(Symmetric-key Cryptography)
해당 장은 대칭키 암호화에 대한 내용을 다루는 챕터이다.
대칭키 암호화의 특징:
암호화에 사용한 암호키가 노출되게 되면 보안에 매우 취약해진다.
- 곧, 해당 암호화 키를 관리하는 메커니즘이 중요하다.
- 네트워크간 키를 주고 받는게 까다롭다. (서로 사용할 수 있는 비밀 경로나 비밀 네트워크를 통해 전달하는 방법)
- 암호화 원리는 논리합(XOR) 연산을 기반으로 함
XOR: 같으면 거짓, 다르면 참
ex) P = 11010011 / K = 01010101 P ^ K = (11010011)^(01010101) = Q(10000110) 곧, QK=P, QP=K 가 성립하게 된다. 이는 XOR의 특징이다.
이렇게 되면 매우 취약한 암호화기술이 되기 때문에 수학 연산을 같이 사용하며, 데이터 변환 방식에 따라 블록 암화(Block Cipher)와 스트림 암호(Stream Cipher)로 구분된다.
- 블록암호(Block Cipher)
- 암호화 키 크기: 64256비트 블록 크기로 연산 수행
- 대표적인 블록 암호: DES, 3DES, AES, Blowfish, Twofish 등 / 국내 개발 SEED, ARIA, HIGHT 등
- 평문 블록을 암호 블록으로 만들 때 적용되는 방식에 따라 파이스텔 블록 구조와 SPN 블록 구조로 구분됨
- 파이스텔 블록 구조: DES, Blowfish, Twofish, SEED 등
- SPN 블록 구조: AES(Rijndael,레인달, 랜섬웨어들이 많이 사용), IDEA, SHARK, ARIA 등
- 각 블록에 대해 어떤 방식으로 암호화 하냐에 따른 분류
- ECB(Electronic Codebook), CBC(Cihpher Block Chaining), OFB(Output Feedback), CFB(Cipher Feedback), CTR(Counter) 등
스트림 암호: 이진화된 평문 스트림과 이진 키 스트림은 비트 단위로 XOR하는 방식, 속도빠르고 구현이 편함 무선통신환경에서 많이 사용 / RC4, GSM 무선통신 보안을 위한 표준인 A5/1, A5/2, A5/3 등이 있다.
3DES(Date Encryption Standard): 56비트키 암호화 알고리즘, DES는 1999년 22시간만에 크랙되었고 최근에는 천만원대 머신으로 1주일이면 크랙 가능함. 이를 보안하여 나온데 3DES(Triple)
- AES(Rijindael 알고리즘)
- Advanced Encryption Standard의 약자, DES를 대체하는 2001년에 개발된 알고리즘
- 벨기에의 Joan Daeme, Vincent Rijmen이 개발, 개발자의 이름을 따서 레인달이라고 정의함
- DES(파이스텔 구조)와 다르게 SPN 블록 구조를 사용
- 키는 보통 128, 192, 256비트 사용 / 암호화 블록은 128비트
Pycrypto 설치하기
해당 모듈은 SHA256와 같은 해시 함수, AES, DES, RSA 등과 같은 다양한 암호화 알고리즘을 제공한다. pip를 사용해서 설치가 가능하기 때문에 pip install pycryto
사용해 설치 가능하다. 확인은 아래와 같이 할 수 있다.
>>> import Crypto
>>>
3DES 구현
from Crypto.Cipher import DES3
from Crypto.Hash import SHA256 as SHA
class myDES(): #암호화 메소드 enc(), 복호화 메소드 dec()
def __init__(self, keytext, ivtext):
hash = SHA.new() #객체 생성 및 hash에 할당
hash.update(keytext.encode('utf-8')) # 유니코드 인자를 받지 않아 변환 필요
key = hash.digest()
self.key = key[:24] #24바이트로 슬라이싱함
hash.update(ivtext.encode('utf-8'))
iv = hash.digest()
self.iv = iv[:8] # iv의 처음 8바이트를 초기화 벡터값으로 할당
def enc(self, plaintext):
plaintext = make8string(plaintext) #길이를 조정해주는 함수
des3 = DES3.new(self.key, DES3.MODE_CBC, self.iv)
encmsg = des3.encrypt(plaintext)
return encmsg
def dec(self, chipertext):
des3 = DES3.new(self.key, DES3.MODE_CBC, self.iv)
decmsg = dec3.decrypt(ciphertext)
return decmsg
#8바이트 이상의 msg일 경우 0을 추가하여 길이를 맞쳐줌
def make8string(msg):
msglen = len(msg)
filler = ''
if msglen%8 != 0:
filler = '0'*(8 - msglen%8)
msg += filler
return msg
def main():
keytext = 'qingfro9'
ivtext = '1234'
msg = 'qingfro9'
myChipher = myDES(keytext, ivtext)
ciphered = myChipher.enc(msg)
dechiphered = myChipher.dec(ciphered)
print('ORIGINAL: \t%s' %msg)
print('CIPHERD: \t%s' %chipered)
print('DECIPHERED: \t%s' %dechiphered)
if __name__ == '__main__':
main()
AES 알고리즘 구현
#AES CBC모드 암호화 및 복호화 코드
from Crypto.Cipher import AES
from Crypto.Hash import SHA256 as SHA
class myAES():
def __init__(self, keytext, ivtext):
hash = SHA.new()
hash.update(keytext.encode('utf-8'))
key = hash.digest()
self.key = key[:16] # AES는 192비트(24바이트), 256비트(32바이트)를 지원
#self.key = key[:24] -> 192비트 키로 암호화 할 경우
#self.key = key -> 256비트 키로 암호화 할 경우
hash.update(ivtext.encode('utf-8'))
iv = hash.digest()
self.iv = iv[:16]
def makeEnabled(self, plaintext):
# 입력되는 plaintext의 크기가 16바이트 배수가 아닌 경우 #을 끝에 추가하여 16배수로 만듬
fillersize = 0
textsize = len(plaintext)
if textsize%16 != 0:
fillersize = 16-textsize%16
filler = '0'*fillersize
header = '%d' %(fillersize)
gap = 16-len(header)
header += '#'*gap
return header+plaintext+filler
def enc(self, plaintext):
plaintext = self.makeEnabled(plaintext)
des3 = AES.new(self.key, AES.MODE_CBC, self.iv)
encmsg = des3.encrypt(plaintext)
return encmsg
def dec(self, chipertext):
aes3 = AES.new(self.key, AES.MODE_CBC, self.iv)
decmsg = aes3.decrypt(chipertext)
header = decmsg[:16].decode() # 16바이트를 유니코드로 변환 / 변수 header에 할당
fillersize = int(header.split('#')[0]) # 추가된 '#'의 개수를 16-filersize하여 정보 획득
if fillersize != 0:
decmsg = decmsg[16:-fillersize]
return decmsg
def main():
keytext = 'qingfro9'
ivtext = '1234'
msg = 'qingfro9'
myChipher = myAES(keytext, ivtext)
chipered = myChipher.enc(msg)
dechiphered = myChipher.dec(chipered)
print('ORIGINAL: \t%s' %msg)
print('CIPHERD: \t%s' %chipered)
print('DECIPHERED: \t%s' %dechiphered)
if __name__ == '__main__':
main()
스트림 암호 구현
Pycrypto는 ARC4 알고리즘을 제공, ARC4는 Alleged RC4를 의미한다. 스트림 암호는 보통 8비트 단위로 암호화를 수행하므로 암호 블록 크기를 1바이트이다. ECB 모드만 사용가능하므로 초기화 벡터는 필요 없으며, ARC4 암호는 암호키만 정의되면 1문자 이상의 임의의 세미지에 대한 암.복호화가 가능하다.
from Crypto.Cipher import ARC4
from Crypto.Hash import SHA256 as SHA
class myARC4():
def __init__(self, keytext):
self.key = keytext
def enc(self, plaintext):
arc4 = ARC4.new(self.key)
encmsg = arc4.encrypt(plaintext)
return encmsg
def dec(self, chipertext):
arc4 = ARC4.new(self.key)
decmsg = arc4.decrypt(chipertext)
return decmsg
def main():
keytext = 'qingfro9'
msg = 'qingfro9'
myChipher = myARC4(keytext)
chipered = myChipher.enc(msg)
dechiphered = myChipher.dec(chipered)
print('ORIGINAL: \t%s' %msg)
print('CIPHERD: \t%s' %chipered)
print('DECIPHERED: \t%s' %dechiphered)
if __name__ == '__main__':
main()
코드가 매우 간단하다. python에서 다 해주니 꿀! :-) main에 msg 값을 변경하면 쉽게 암호화 가능.
혹시 두개를 같이 섞어서 쓸수잇나요? des aes 둘다 가능하게
답글삭제