Python Language
보안 및 암호화
수색…
소개
파이썬은 컴퓨터 및 네트워크 보안 분야에서 가장 보편적 인 언어 중 하나이며 보안 및 암호화 분야에서 큰 잠재력을 가지고 있습니다. 이 주제는 컴퓨터 및 네트워크 보안에서 해싱 및 암호화 / 해독 알고리즘에 이르기까지 파이썬에서 사용되는 암호화 기능과 구현을 다룹니다.
통사론
- hashlib.new (name)
- hashlib.pbkdf2_hmac (이름, 암호, 소금, 라운드, dklen = 없음)
비고
hashlib
많은 메소드는 문자열이 아닌 바이트의 버퍼로 해석 할 수있는 값을 전달해야합니다. 이것은 hashlib.new().update()
와 hashlib.pbkdf2_hmac
입니다. 문자열이있는 경우 문자열 b
앞에 문자열 b
를 추가하여 바이트 버퍼로 변환 할 수 있습니다.
"This is a string"
b"This is a buffer of bytes"
메시지 다이제스트 계산
hashlib
모듈은 new
메소드를 통해 메시지 다이제스트 생성기를 생성 할 수 있습니다. 이러한 생성자는 임의의 문자열을 고정 길이 다이제스트로 변환합니다.
import hashlib
h = hashlib.new('sha256')
h.update(b'Nobody expects the Spanish Inquisition.')
h.digest()
# ==> b'.\xdf\xda\xdaVR[\x12\x90\xff\x16\xfb\x17D\xcf\xb4\x82\xdd)\x14\xff\xbc\xb6Iy\x0c\x0eX\x9eF-='
청크로 큰 파일 청크를 해시하는 데 유용한 digest
를 호출하기 전에 임의의 횟수만큼 update
를 호출 할 수 있습니다. hexdigest
를 사용하여 16 진수 형식의 다이제스트를 얻을 수도 있습니다.
h.hexdigest()
# ==> '2edfdada56525b1290ff16fb1744cfb482dd2914ffbcb649790c0e589e462d3d'
사용 가능한 해싱 알고리즘
hashlib.new
는 생성자를 생성하기 위해 호출 할 때 알고리즘의 이름을 요구합니다. 현재 파이썬 인터프리터에서 사용할 수있는 알고리즘을 찾으려면 hashlib.algorithms_available
사용 hashlib.algorithms_available
.
import hashlib
hashlib.algorithms_available
# ==> {'sha256', 'DSA-SHA', 'SHA512', 'SHA224', 'dsaWithSHA', 'SHA', 'RIPEMD160', 'ecdsa-with-SHA1', 'sha1', 'SHA384', 'md5', 'SHA1', 'MD5', 'MD4', 'SHA256', 'sha384', 'md4', 'ripemd160', 'sha224', 'sha512', 'DSA', 'dsaEncryption', 'sha', 'whirlpool'}
반환 된 목록은 플랫폼 및 인터프리터에 따라 다릅니다. 알고리즘을 사용할 수 있는지 확인하십시오.
hashlib.algorithms_guaranteed
사용하여 사용할 수있는 모든 플랫폼 및 인터프리터에서 사용할 수 있도록 보장 되는 알고리즘도 있습니다.
hashlib.algorithms_guaranteed
# ==> {'sha256', 'sha384', 'sha1', 'sha224', 'md5', 'sha512'}
안전한 암호 해싱
hashlib
모듈에 의해 노출 된 PBKDF2 알고리즘 은 안전한 암호 해싱을 수행하는 데 사용될 수 있습니다. 이 알고리즘은 저장된 해시에서 원래 암호를 복구하기 위해 무차별 대입 공격을 막을 수는 없지만 그러한 공격은 매우 비쌉니다.
import hashlib
import os
salt = os.urandom(16)
hash = hashlib.pbkdf2_hmac('sha256', b'password', salt, 100000)
PBKDF2는 모든 다이제스트 알고리즘과 함께 작동 할 수 있지만, 위 예제는 일반적으로 권장되는 SHA256을 사용합니다. 임의의 소금은 해시 된 암호와 함께 저장되어야하며 입력 된 암호와 저장된 해시를 비교하기 위해 다시 필요합니다. 각 암호는 다른 소금으로 해시해야합니다. 라운드 수에 관해서는 가능한 한 높게 설정하는 것이 좋습니다.
결과를 16 진수로 binascii
려면 binascii
모듈을 사용할 수 있습니다.
import binascii
hexhash = binascii.hexlify(hash)
주의 : PBKDF2가 나쁘지는 않지만, bcrypt 와 특히 scrypt 는 brute-force 공격에 대해 강하다고 간주됩니다. 어느 쪽도 현재 Python 표준 라이브러리의 일부는 아닙니다.
파일 해싱
해시는 가변 길이의 바이트 시퀀스를 고정 길이 시퀀스로 변환하는 함수입니다. 해싱 파일은 여러 가지 이유로 유리할 수 있습니다. 해시는 두 파일이 동일한 지 확인하거나 파일의 내용이 손상되거나 변경되지 않았 음을 확인하는 데 사용할 수 있습니다.
hashlib
를 사용하여 파일의 해시를 생성 할 수 있습니다.
import hashlib
hasher = hashlib.new('sha256')
with open('myfile', 'r') as f:
contents = f.read()
hasher.update(contents)
print hasher.hexdigest()
큰 파일의 경우 고정 길이의 버퍼를 사용할 수 있습니다.
import hashlib
SIZE = 65536
hasher = hashlib.new('sha256')
with open('myfile', 'r') as f:
buffer = f.read(SIZE)
while len(buffer) > 0:
hasher.update(buffer)
buffer = f.read(SIZE)
print(hasher.hexdigest())
pycrypto를 사용한 대칭 암호화
파이썬의 내장 암호화 기능은 현재 해싱으로 제한되어 있습니다. 암호화에는 pycrypto 와 같은 타사 모듈이 필요합니다. 예를 들어, 대칭 암호화 기술 수준으로 간주되는 AES 알고리즘 을 제공합니다. 다음 코드는 암호문을 사용하여 주어진 메시지를 암호화합니다 :
import hashlib
import math
import os
from Crypto.Cipher import AES
IV_SIZE = 16 # 128 bit, fixed for the AES algorithm
KEY_SIZE = 32 # 256 bit meaning AES-256, can also be 128 or 192 bits
SALT_SIZE = 16 # This size is arbitrary
cleartext = b'Lorem ipsum'
password = b'highly secure encryption password'
salt = os.urandom(SALT_SIZE)
derived = hashlib.pbkdf2_hmac('sha256', password, salt, 100000,
dklen=IV_SIZE + KEY_SIZE)
iv = derived[0:IV_SIZE]
key = derived[IV_SIZE:]
encrypted = salt + AES.new(key, AES.MODE_CFB, iv).encrypt(cleartext)
AES 알고리즘은 암호화 키, 초기화 벡터 (IV) 및 암호화 할 실제 메시지의 세 가지 매개 변수를 사용합니다. 무작위로 생성 된 AES 키가있는 경우 해당 키를 직접 사용하고 무작위 초기화 벡터를 생성하면됩니다. 암호 문구는 적당한 크기가 아니며, 실제로는 무작위가 아니기 때문에 엔트로피가 비교적 적기 때문에 직접 사용하는 것이 좋습니다. 대신 PBKDF2 알고리즘 의 내장 구현을 사용하여 비밀번호에서 128 비트 초기화 벡터와 256 비트 암호화 키를 생성합니다.
암호화 된 각 메시지에 대해 다른 초기화 벡터와 키를 갖는 것이 중요합니다. 특히 동일한 메시지 두 개가 동일한 암호화 된 텍스트를 생성하지는 않지만, 다른 암호문으로 암호화 된 메시지에 대해 하나의 암호문을 추측 한 작업을 공격자가 재사용하는 것을 방지합니다. 해독을 위해 동일한 초기화 벡터와 키를 유도하기 위해이 소금을 암호화 된 메시지와 함께 저장해야합니다.
다음 코드는 우리의 메시지를 다시 해독합니다 :
salt = encrypted[0:SALT_SIZE]
derived = hashlib.pbkdf2_hmac('sha256', password, salt, 100000,
dklen=IV_SIZE + KEY_SIZE)
iv = derived[0:IV_SIZE]
key = derived[IV_SIZE:]
cleartext = AES.new(key, AES.MODE_CFB, iv).decrypt(encrypted[SALT_SIZE:])
pycrypto를 사용하여 RSA 서명 생성
RSA 를 사용하여 메시지 서명을 만들 수 있습니다. 유효한 서명은 전용 RSA 키에 대한 액세스 권한으로 만 생성 될 수 있습니다. 반면에 유효성 검증은 해당 공개 키로 가능합니다. 따라서 상대방이 자신의 공개 키를 알고 있으면 서명 된 메시지를 변경하지 않고 확인할 수 있습니다. 예를 들어 전자 메일에 사용되는 방식입니다. 현재이 기능을 사용하려면 pycrypto 와 같은 타사 모듈이 필요합니다.
import errno
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
message = b'This message is from me, I promise.'
try:
with open('privkey.pem', 'r') as f:
key = RSA.importKey(f.read())
except IOError as e:
if e.errno != errno.ENOENT:
raise
# No private key, generate a new one. This can take a few seconds.
key = RSA.generate(4096)
with open('privkey.pem', 'wb') as f:
f.write(key.exportKey('PEM'))
with open('pubkey.pem', 'wb') as f:
f.write(key.publickey().exportKey('PEM'))
hasher = SHA256.new(message)
signer = PKCS1_v1_5.new(key)
signature = signer.sign(hasher)
서명이 비슷하게 작동하는지 확인하지만 개인 키가 아닌 공개 키를 사용합니다.
with open('pubkey.pem', 'rb') as f:
key = RSA.importKey(f.read())
hasher = SHA256.new(message)
verifier = PKCS1_v1_5.new(key)
if verifier.verify(hasher, signature):
print('Nice, the signature is valid!')
else:
print('No, the message was signed with the wrong private key or modified')
주 : 위의 예는 매우 공통적 인 PKCS # 1 v1.5 서명 알고리즘을 사용합니다. pycrypto는 또한 새로운 PKCS # 1 PSS 알고리즘을 구현합니다. 예를 들어, PKCS1_v1_5
를 PKCS1_v1_5
로 PKCS1_PSS
예제를 사용할 수 있습니다. 현재 는 그것을 사용하는 이유 가 거의없는 것 같습니다.
pycrypto를 사용한 비대칭 RSA 암호화
비대칭 암호화는 메시지의 수신자와 비밀 키를 교환하지 않고도 메시지를 암호화 할 수 있다는 이점이 있습니다. 보낸 사람은받는 사람의 공개 키를 알고 있어야하기 때문에 지정된받는 사람 (해당 개인 키가있는 사람) 만 암호를 해독 할 수있는 방법으로 메시지를 암호화 할 수 있습니다. 현재이 기능을 사용하려면 pycrypto 와 같은 타사 모듈이 필요합니다.
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
message = b'This is a very secret message.'
with open('pubkey.pem', 'rb') as f:
key = RSA.importKey(f.read())
cipher = PKCS1_OAEP.new(key)
encrypted = cipher.encrypt(message)
받는 사람은 올바른 개인 키가 있으면 메시지의 암호를 해독 할 수 있습니다.
with open('privkey.pem', 'rb') as f:
key = RSA.importKey(f.read())
cipher = PKCS1_OAEP.new(key)
decrypted = cipher.decrypt(encrypted)
참고 : 위의 예에서는 PKCS # 1 OAEP 암호화 체계를 사용합니다. pycrypto는 PKCS # 1 v1.5 암호화 체계도 구현하지만 알려진 프로토콜로 인해 새로운 프로토콜에는 권장되지 않습니다.