program story

암호에 따라 문자열을 인코딩하는 간단한 방법은 무엇입니까?

inputbox 2020. 8. 3. 08:21
반응형

암호에 따라 문자열을 인코딩하는 간단한 방법은 무엇입니까?


파이썬에는 암호를 사용하여 문자열을 인코딩 / 디코딩하는 간단한 방법이 있습니까?

이 같은:

>>> encode('John Doe', password = 'mypass')
'sjkl28cn2sx0'
>>> decode('sjkl28cn2sx0', password = 'mypass')
'John Doe'

따라서 "John Doe"문자열은 'sjkl28cn2sx0'으로 암호화됩니다. 원래 문자열을 얻으려면 소스 코드의 암호 인 'mypass'키를 사용하여 해당 문자열을 "잠금 해제"합니다. 암호로 Word 문서를 암호화 / 암호 해독 할 수있는 방법이되고 싶습니다.

이 암호화 된 문자열을 URL 매개 변수로 사용하고 싶습니다. 나의 목표는 강력한 보안이 아니라 난독 화입니다. 미션 크리티컬은 인코딩되지 않습니다. 데이터베이스 테이블을 사용하여 키와 값을 저장할 수는 있지만 미니멀리스트하려고합니다.


가정 당신이하는 유일한 으로부터 물건을 모호하게됩니다 간단한 난독 찾고 매우 캐주얼 관찰자, 당신은 타사 라이브러리를 사용하고자되지 않습니다. Vigenere 암호와 같은 것을 추천합니다. 단순한 고대 암호 중 가장 강한 것 중 하나입니다.

비제 네르 암호

빠르고 쉽게 구현할 수 있습니다. 다음과 같은 것 :

import base64

def encode(key, string):
    encoded_chars = []
    for i in xrange(len(string)):
        key_c = key[i % len(key)]
        encoded_c = chr(ord(string[i]) + ord(key_c) % 256)
        encoded_chars.append(encoded_c)
    encoded_string = "".join(encoded_chars)
    return base64.urlsafe_b64encode(encoded_string)

디코드는 키를 빼는 것을 제외하고 거의 동일합니다.

인코딩하는 문자열이 짧거나 사용 된 암호의 길이를 추측하기 어려운 경우 깨기가 훨씬 어렵습니다.

암호화 기능을 찾고 있다면 PyCrypto가 최선의 방법 일 것입니다.하지만 이전 답변은 일부 세부 사항을 간과합니다. PyCrypto의 ECB 모드를 사용하려면 메시지 길이가 16 자 여야합니다. 그래서, 당신은 패드해야합니다. 또한 URL 매개 변수로 사용 base64.urlsafe_b64_encode()하려면 표준 매개 변수 대신을 사용 하십시오. 이렇게하면 base64 알파벳의 일부 문자가 URL 안전 문자로 바뀝니다 (이름에서 알 수 있듯이).

그러나,이 매우 난독 화 계층은 이것을 사용하기 전에 귀하의 요구에 충분 하다는 것을 절대적으로 확신해야합니다 . 필자가 링크 한 Wikipedia 기사는 암호 해독에 대한 자세한 지침을 제공하므로 적당한 양의 판단을 가진 사람은 쉽게 해독 할 수 있습니다.


보안이 아닌 모호함을 원한다고 명시 적으로 말하면 제안한 것의 약점으로 인해 당신을 견책하는 것을 피할 수 있습니다 :)

따라서 PyCrypto를 사용하면

from Crypto.Cipher import AES
import base64

msg_text = 'test some plain text here'.rjust(32)
secret_key = '1234567890123456' # create new & store somewhere safe

cipher = AES.new(secret_key,AES.MODE_ECB) # never use ECB in strong systems obviously
encoded = base64.b64encode(cipher.encrypt(msg_text))
# ...
decoded = cipher.decrypt(base64.b64decode(encoded))
print decoded.strip()

누군가 데이터베이스와 코드베이스를 보유하고 있다면 암호화 된 데이터를 해독 할 수 있습니다. secret_key를 안전하게 유지하십시오!


@smehmood의 Vigenere 암호 답변에 언급 된 "encoded_c"는 "key_c"여야합니다.

작동하는 인코딩 / 디코딩 기능은 다음과 같습니다.

import base64
def encode(key, clear):
    enc = []
    for i in range(len(clear)):
        key_c = key[i % len(key)]
        enc_c = chr((ord(clear[i]) + ord(key_c)) % 256)
        enc.append(enc_c)
    return base64.urlsafe_b64encode("".join(enc))

def decode(key, enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc)
    for i in range(len(enc)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)

다음은 @qneill의 답변에 대한 Python 3 버전의 함수입니다 .

import base64
def encode(key, clear):
    enc = []
    for i in range(len(clear)):
        key_c = key[i % len(key)]
        enc_c = chr((ord(clear[i]) + ord(key_c)) % 256)
        enc.append(enc_c)
    return base64.urlsafe_b64encode("".join(enc).encode()).decode()

def decode(key, enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc).decode()
    for i in range(len(enc)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)

파이썬 3은 문자열 / 바이트 배열을 두 가지 다른 개념으로 나누고이를 반영하기 위해 API를 업데이트했기 때문에 추가 인코딩 / 디코딩이 필요합니다.


파이썬에는 내장 된 암호화 체계가 없습니다. 또한 암호화 된 데이터 저장소를 진지하게 고려해야합니다. 한 개발자가 안전하지 않은 것으로 이해하는 사소한 암호화 체계와 완구 체계는 경험이 부족한 개발자에 의해 안전한 체계로 오인 될 수 있습니다. 암호화하면 올바르게 암호화하십시오.

그러나 적절한 암호화 체계를 구현하기 위해 많은 작업을 수행 할 필요는 없습니다. 우선 , 암호화 휠을 다시 발명하지 말고 신뢰할 수있는 암호화 라이브러리를 사용하여이를 처리하십시오. Python 3의 경우 신뢰할 수있는 라이브러리는 cryptography입니다.

또한 암호화 및 암호 해독이 바이트에 적용되는 것이 좋습니다 . 문자 메시지를 먼저 바이트로 인코딩하십시오. stringvalue.encode()UTF8로 인코딩하고을 사용하여 쉽게 다시 되돌릴 수 있습니다 bytesvalue.decode().

마지막으로, 암호화 및 암호 해독시 암호가 아닌 대해 이야기 합니다. 키는 사람이 기억할 수 없어야하며, 비밀 위치에 저장하지만 기계는 읽을 수있는 반면 암호는 사람이 읽을 수 있고 기억할 수 있습니다. 약간의주의를 기울이면 암호에서 키를 파생 시킬있습니다 .

그러나 웹 응용 프로그램이나 프로세스가 클러스터에서 계속 실행되도록 사용자의주의를 기울이지 않고 실행하려면 키를 사용하려고합니다. 비밀번호는 최종 사용자 만 특정 정보에 액세스해야하는 경우에 사용됩니다. 그럼에도 불구하고 일반적으로 암호로 응용 프로그램을 보호 한 다음 사용자 계정에 연결된 키를 사용하여 암호화 된 정보를 교환합니다.

대칭 키 암호화

Fernet – AES CBC + HMAC, 강력 추천

cryptography라이브러리가 포함 Fernet 조리법 , 암호화를 사용하기위한 모범 사례 조리법을. Fernet은 광범위한 프로그래밍 언어로 즉시 구현할 수 있는 개방형 표준 이며, 메시지 변조를 방지하기 위해 버전 정보, 타임 스탬프 및 HMAC 서명으로 AES CBC 암호화를 패키지로 제공합니다.

Fernet을 사용하면 메시지를 매우 쉽게 암호화 및 해독 하고 보안을 유지할 수 있습니다. 비밀로 데이터를 암호화하는 이상적인 방법입니다.

Fernet.generate_key()보안 키를 생성하는 데 사용 하는 것이 좋습니다 . 암호도 사용할 수 있지만 (다음 섹션) 완전한 32 바이트 비밀 키 (암호화하려면 16 바이트, 서명에는 16 바이트)가 생각할 수있는 대부분의 암호보다 안전합니다.

Fernet이 생성하는 키는 bytesURL 및 파일 안전 base64 문자를 가진 객체이므로 인쇄 가능합니다.

from cryptography.fernet import Fernet

key = Fernet.generate_key()  # store in a secure location
print("Key:", key.decode())

암호화 또는 암호 해독 메시지하려면 만들 Fernet()지정된 키를 가진 인스턴스를, 및 호출 Fernet.encrypt()하거나 Fernet.decrypt(), 암호화에 일반 텍스트 메시지와 암호화 된 토큰 모두는 bytes객체.

encrypt()decrypt()기능과 같을 것이다 :

from cryptography.fernet import Fernet

def encrypt(message: bytes, key: bytes) -> bytes:
    return Fernet(key).encrypt(message)

def decrypt(token: bytes, key: bytes) -> bytes:
    return Fernet(key).decrypt(token)

데모:

>>> key = Fernet.generate_key()
>>> print(key.decode())
GZWKEhHGNopxRdOHS4H4IyKhLQ8lwnyU7vRLrM3sebY=
>>> message = 'John Doe'
>>> encrypt(message.encode(), key)
'gAAAAABciT3pFbbSihD_HZBZ8kqfAj94UhknamBuirZWKivWOukgKQ03qE2mcuvpuwCSuZ-X_Xkud0uWQLZ5e-aOwLC0Ccnepg=='
>>> token = _
>>> decrypt(token, key).decode()
'John Doe'

비밀번호가있는 Fernet – 비밀번호에서 파생 된 키로 보안을 다소 약화시킵니다.

강력한 키 파생 방법사용하는 경우 비밀 키 대신 암호를 사용할 수 있습니다 . 그런 다음 메시지에 솔트와 HMAC 반복 횟수를 포함시켜야하므로 암호화 된 값은 먼저 솔트, 카운트 및 페넷 토큰을 분리하지 않으면 더 이상 Fernet과 호환되지 않습니다.

import secrets
from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d

from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

backend = default_backend()
iterations = 100_000

def _derive_key(password: bytes, salt: bytes, iterations: int = iterations) -> bytes:
    """Derive a secret key from a given password and salt"""
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(), length=32, salt=salt,
        iterations=iterations, backend=backend)
    return b64e(kdf.derive(password))

def password_encrypt(message: bytes, password: str, iterations: int = iterations) -> bytes:
    salt = secrets.token_bytes(16)
    key = _derive_key(password.encode(), salt, iterations)
    return b64e(
        b'%b%b%b' % (
            salt,
            iterations.to_bytes(4, 'big'),
            b64d(Fernet(key).encrypt(message)),
        )
    )

def password_decrypt(token: bytes, password: str) -> bytes:
    decoded = b64d(token)
    salt, iter, token = decoded[:16], decoded[16:20], b64e(decoded[20:])
    iterations = int.from_bytes(iter, 'big')
    key = _derive_key(password.encode(), salt, iterations)
    return Fernet(key).decrypt(token)

데모:

>>> message = 'John Doe'
>>> password = 'mypass'
>>> password_encrypt(message.encode(), password)
b'9Ljs-w8IRM3XT1NDBbSBuQABhqCAAAAAAFyJdhiCPXms2vQHO7o81xZJn5r8_PAtro8Qpw48kdKrq4vt-551BCUbcErb_GyYRz8SVsu8hxTXvvKOn9QdewRGDfwx'
>>> token = _
>>> password_decrypt(token, password).decode()
'John Doe'

출력에 솔트를 포함하면 임의의 솔트 값을 사용할 수 있으므로 암호 재사용 또는 메시지 반복에 관계없이 암호화 된 출력이 완전히 무작위로 보장됩니다. 반복 횟수를 포함하면 오래된 메시지의 암호 해독 기능을 잃지 않으면 서 시간이 지남에 따라 CPU 성능 향상을 조정할 수 있습니다.

비슷한 크기의 풀에서 올바르게 임의의 암호를 생성하는 경우 암호 만 Fernet 32 ​​바이트 임의 키만큼 안전 할 수 있습니다. 32 바이트는 256 ^ 32 개의 키 수를 제공하므로 74 자의 알파벳 (26 개의 상위, 26 개의 하위, 10 자리 및 12 개의 가능한 기호)을 사용하는 경우 암호의 math.ceil(math.log(256 ** 32, 74))길이 는 최소 == 42 자 여야합니다 . 그러나 잘 선택된 많은 수의 HMAC 반복 은 엔트로피 부족을 어느 정도 완화시킬 수 있습니다. 이는 침입자가 침입을 저지르는 데 훨씬 더 많은 비용을 초래하기 때문입니다.

짧지 만 합리적으로 안전한 암호를 선택해도이 체계가 손상되지는 않으며, 이는 무차별 대입 공격자가 검색해야하는 가능한 값의 수를 줄입니다. 보안 요구 사항에 맞는 강력한 암호 를 선택하십시오 .

대안

모호한

대안은 암호화하지 않는 것 입니다. Vignere는 보안 수준이 낮은 암호를 사용하거나 자체적으로 구현 한 구현을 사용하려는 유혹을받지 마십시오. 이러한 접근 방식에는 보안이 없지만 경험이 부족한 개발자에게는 미래에 코드를 유지 관리하는 작업이 주어질 수 있습니다. 보안의 환상은 전혀 보안이 아닌 것보다 나쁩니다.

모호한 부분 만 있으면 데이터를 base64로 지정하십시오. URL 안전 요구 사항의 경우 base64.urlsafe_b64encode()기능 이 좋습니다. 여기에 비밀번호를 사용하지 말고 인코딩 만하면됩니다. 기껏해야 압축과 같은 압축을 추가하십시오 zlib.

import zlib
from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d

def obscure(data: bytes) -> bytes:
    return b64e(zlib.compress(data, 9))

def unobscure(obscured: bytes) -> bytes:
    return zlib.decompress(b64d(obscured))

이 회전 b'Hello world!'b'eNrzSM3JyVcozy_KSVEEAB0JBF4='.

무결성 만

신뢰할 수없는 클라이언트에게 전송 된 후 데이터를 변경하지 않고 신뢰할 수 있도록하는 방법 만 있으면 데이터 에 서명하고 SHA1을 사용하여 hmac라이브러리사용할 수 있습니다 (여전히 HMAC 서명에 안전하다고 간주되는 경우 )

import hmac
import hashlib

def sign(data: bytes, key: bytes, algorithm=hashlib.sha256) -> bytes:
    assert len(key) >= algorithm().digest_size, (
        "Key must be at least as long as the digest size of the "
        "hashing algorithm"
    )
    return hmac.new(key, data, algorithm).digest()

def verify(signature: bytes, data: bytes, key: bytes, algorithm=hashlib.sha256) -> bytes:
    expected = sign(data, key, algorithm)
    return hmac.compare_digest(expected, signature)

이를 사용하여 데이터에 서명 한 다음 데이터에 서명을 첨부하여 클라이언트에 보냅니다. 데이터를 다시 받으면 데이터를 분할하고 서명하고 확인하십시오. 기본 알고리즘을 SHA256으로 설정 했으므로 32 바이트 키가 필요합니다.

key = secrets.token_bytes(32)

이 형식을 직렬화 및 역 직렬화로 다양한 형식으로 패키지화 하는 itsdangerous라이브러리 를 살펴볼 수 있습니다 .

AES-GCM 암호화를 사용하여 암호화 및 무결성 제공

Fernet은 암호화 된 데이터의 무결성을 보장하기 위해 HMAC 서명으로 AEC-CBC를 기반으로합니다. 악의적 인 공격자는 암호문이 서명되어 있기 때문에 입력이 잘못된 서클에서 서비스를 바쁘게 운영하기 위해 시스템의 넌센스 데이터를 제공 할 수 없습니다.

갈루아 / 카운터 모드의 블록 암호는 암호문을 생성하고 태그 때문에 동일한 목적을 제공하기 위해 사용될 수 있고, 동일한 목적을 제공 할 수있다. 단점은 Fernet과 달리 다른 플랫폼에서 재사용하기 쉬운 단일 크기의 레시피가 없다는 것입니다. AES-GCM은 또한 패딩을 사용하지 않으므로이 암호화 암호문은 입력 메시지의 길이와 일치합니다 (Fernet / AES-CBC는 메시지를 고정 된 길이의 블록으로 암호화하여 메시지 길이를 다소 모호하게합니다).

AES256-GCM은 일반적인 32 바이트 비밀을 키로 사용합니다.

key = secrets.token_bytes(32)

그런 다음 사용

import binascii, time
from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.exceptions import InvalidTag

backend = default_backend()

def aes_gcm_encrypt(message: bytes, key: bytes) -> bytes:
    current_time = int(time.time()).to_bytes(8, 'big')
    algorithm = algorithms.AES(key)
    iv = secrets.token_bytes(algorithm.block_size // 8)
    cipher = Cipher(algorithm, modes.GCM(iv), backend=backend)
    encryptor = cipher.encryptor()
    encryptor.authenticate_additional_data(current_time)
    ciphertext = encryptor.update(message) + encryptor.finalize()        
    return b64e(current_time + iv + ciphertext + encryptor.tag)

def aes_gcm_decrypt(token: bytes, key: bytes, ttl=None) -> bytes:
    algorithm = algorithms.AES(key)
    try:
        data = b64d(token)
    except (TypeError, binascii.Error):
        raise InvalidToken
    timestamp, iv, tag = data[:8], data[8:algorithm.block_size // 8 + 8], data[-16:]
    if ttl is not None:
        current_time = int(time.time())
        time_encrypted, = int.from_bytes(data[:8], 'big')
        if time_encrypted + ttl < current_time or current_time + 60 < time_encrypted:
            # too old or created well before our current time + 1 h to account for clock skew
            raise InvalidToken
    cipher = Cipher(algorithm, modes.GCM(iv, tag), backend=backend)
    decryptor = cipher.decryptor()
    decryptor.authenticate_additional_data(timestamp)
    ciphertext = data[8 + len(iv):-16]
    return decryptor.update(ciphertext) + decryptor.finalize()

Fernet이 지원하는 것과 동일한 실제 사용 사례를 지원하는 타임 스탬프를 포함 시켰습니다.

이 페이지의 다른 접근법, Python 3

AES CFB- CBC와 유사하지만 채울 필요가 없습니다.

이것은 비록 틀리지 만 All Іѕ Vаиітy가 따르는 접근법입니다 . 이것은 cryptography버전이지만 암호문에 IV를 포함 한다는 점에 유의 하십시오 .IV를 전역으로 저장해서는 안됩니다 (IV를 재사용하면 키의 보안이 약화되고 모듈로 저장하면 다시 생성됩니다) 다음 파이썬 호출로 모든 암호문을 해독 할 수 없게합니다) :

import secrets
from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

backend = default_backend()

def aes_cfb_encrypt(message, key):
    algorithm = algorithms.AES(key)
    iv = secrets.token_bytes(algorithm.block_size // 8)
    cipher = Cipher(algorithm, modes.CFB(iv), backend=backend)
    encryptor = cipher.encryptor()
    ciphertext = encryptor.update(message) + encryptor.finalize()
    return b64e(iv + ciphertext)

def aes_cfb_decrypt(ciphertext, key):
    iv_ciphertext = b64d(ciphertext)
    algorithm = algorithms.AES(key)
    size = algorithm.block_size // 8
    iv, encrypted = iv_ciphertext[:size], iv_ciphertext[size:]
    cipher = Cipher(algorithm, modes.CFB(iv), backend=backend)
    decryptor = cipher.decryptor()
    return decryptor.update(encrypted) + decryptor.finalize()

여기에는 HMAC 서명에 대한 추가 방어 기능이 없으며 타임 스탬프가 없습니다. 직접 추가해야합니다.

위의 내용은 또한 기본 암호화 구성 요소를 잘못 결합하는 것이 얼마나 쉬운 지 보여줍니다. IV 값을 잘못 처리하면 IV가 유실되어 데이터가 손상되거나 암호화 된 메시지를 읽을 수 없게됩니다. Fernet을 대신 사용하면 그러한 실수로부터 보호 할 수 있습니다.

AES ECB – 안전하지 않음

이전에 AES ECB 암호화를 구현 했지만 여전히 Python 3에서이를 지원해야하는 경우에도 그렇게 할 수 cryptography있습니다. ECB는 실제 응용 프로그램에 대해 충분히 안전하지 않다는 동일한 경고가 적용됩니다 . 패딩의 자동 처리를 추가하여 Python 3에 대한 답변을 다시 구현합니다.

from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend

backend = default_backend()

def aes_ecb_encrypt(message, key):
    cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=backend)
    encryptor = cipher.encryptor()
    padder = padding.PKCS7(cipher.algorithm.block_size).padder()
    padded = padder.update(msg_text.encode()) + padder.finalize()
    return b64e(encryptor.update(padded) + encryptor.finalize())

def aes_ecb_decrypt(ciphertext, key):
    cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=backend)
    decryptor = cipher.decryptor()
    unpadder = padding.PKCS7(cipher.algorithm.block_size).unpadder()
    padded = decryptor.update(b64d(ciphertext)) + decryptor.finalize()
    return unpadder.update(padded) + unpadder.finalize()

다시 말하지만, HMAC 서명이 없으므로 ECB를 사용해서는 안됩니다. 위의 내용은 cryptography일반적인 암호화 구성 요소, 실제로 사용하지 않아야 할 구성 요소를 처리 할 수 있다는 것을 설명하기 위한 것입니다.


면책 조항 : 의견에서 언급했듯이 실제 응용 프로그램의 데이터를 보호하는 데 사용해서는 안됩니다 .

XOR 암호화에 어떤 문제가 있습니까?

https://crypto.stackexchange.com/questions/56281/breaking-a-xor-cipher-of-known-key-length

https://github.com/hellman/xortool


언급했듯이 PyCrypto 라이브러리에는 암호 모음이 포함되어 있습니다. XOR "암호"를 사용하여 직접 원하지 않는 경우 더티 작업을 수행 할 수 있습니다.

from Crypto.Cipher import XOR
import base64

def encrypt(key, plaintext):
  cipher = XOR.new(key)
  return base64.b64encode(cipher.encrypt(plaintext))

def decrypt(key, ciphertext):
  cipher = XOR.new(key)
  return cipher.decrypt(base64.b64decode(ciphertext))

암호는 평문을 채울 필요없이 다음과 같이 작동합니다.

>>> encrypt('notsosecretkey', 'Attack at dawn!')
'LxsAEgwYRQIGRRAKEhdP'

>>> decrypt('notsosecretkey', encrypt('notsosecretkey', 'Attack at dawn!'))
'Attack at dawn!'

base64 인 코드 / 디코드 기능에 대한 https://stackoverflow.com/a/2490376/241294의 크레딧입니다 (저는 파이썬 초보자입니다).


다음은 AES (PyCrypto) 및 base64를 사용하여 URL 안전 암호화 및 암호 해독을 구현 한 것입니다.

import base64
from Crypto import Random
from Crypto.Cipher import AES

AKEY = 'mysixteenbytekey' # AES key must be either 16, 24, or 32 bytes long

iv = Random.new().read(AES.block_size)


def encode(message):
    obj = AES.new(AKEY, AES.MODE_CFB, iv)
    return base64.urlsafe_b64encode(obj.encrypt(message))


def decode(cipher):
    obj2 = AES.new(AKEY, AES.MODE_CFB, iv)
    return obj2.decrypt(base64.urlsafe_b64decode(cipher))

https://bugs.python.org/issue4329 (TypeError : 문자 매핑은 정수, 없음 또는 유니 코드를 반환해야합니다) 와 같은 문제가 발생 하면 다음과 같이 디코딩하는 동안 str (cipher)을 사용하십시오

obj2.decrypt (base64.urlsafe_b64decode (str (cipher))) 반환

In [13]: encode("Hello World")
Out[13]: b'67jjg-8_RyaJ-28='

In [14]: %timeit encode("Hello World")
100000 loops, best of 3: 13.9 µs per loop

In [15]: decode(b'67jjg-8_RyaJ-28=')
Out[15]: b'Hello World'

In [16]: %timeit decode(b'67jjg-8_RyaJ-28=')
100000 loops, best of 3: 15.2 µs per loop

python3의 인코딩 / 디코딩 기능 작동 (qneill의 답변에서 거의 적응되지 않음) :

def encode(key, clear):
    enc = []
    for i in range(len(clear)):
        key_c = key[i % len(key)]
        enc_c = (ord(clear[i]) + ord(key_c)) % 256
        enc.append(enc_c)
    return base64.urlsafe_b64encode(bytes(enc))

def decode(key, enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc)
    for i in range(len(enc)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + enc[i] - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)

좋은 답변 감사합니다. 독창적 인 것은 없지만 다음은 유용한 파이썬 기능을 사용하여 qneill의 답변을 점진적으로 다시 작성합니다. 그들이 코드를 단순화하고 명확히하는 데 동의하기를 바랍니다.

import base64


def qneill_encode(key, clear):
    enc = []
    for i in range(len(clear)):
        key_c = key[i % len(key)]
        enc_c = chr((ord(clear[i]) + ord(key_c)) % 256)
        enc.append(enc_c)
    return base64.urlsafe_b64encode("".join(enc))


def qneill_decode(key, enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc)
    for i in range(len(enc)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)

enumerate()-목록에있는 항목을 색인과 연결

문자열의 문자를 반복

def encode_enumerate(key, clear):
    enc = []
    for i, ch in enumerate(clear):
        key_c = key[i % len(key)]
        enc_c = chr((ord(ch) + ord(key_c)) % 256)
        enc.append(enc_c)
    return base64.urlsafe_b64encode("".join(enc))


def decode_enumerate(key, enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc)
    for i, ch in enumerate(enc):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(ch) - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)

목록 이해를 사용하여 목록 작성

def encode_comprehension(key, clear):
    enc = [chr((ord(clear_char) + ord(key[i % len(key)])) % 256)
                for i, clear_char in enumerate(clear)]
    return base64.urlsafe_b64encode("".join(enc))


def decode_comprehension(key, enc):
    enc = base64.urlsafe_b64decode(enc)
    dec = [chr((256 + ord(ch) - ord(key[i % len(key)])) % 256)
           for i, ch in enumerate(enc)]
    return "".join(dec)

종종 파이썬에서는리스트 인덱스가 전혀 필요하지 않습니다. zip 및 cycle을 사용하여 루프 인덱스 변수를 완전히 제거하십시오.

from itertools import cycle


def encode_zip_cycle(key, clear):
    enc = [chr((ord(clear_char) + ord(key_char)) % 256)
                for clear_char, key_char in zip(clear, cycle(key))]
    return base64.urlsafe_b64encode("".join(enc))


def decode_zip_cycle(key, enc):
    enc = base64.urlsafe_b64decode(enc)
    dec = [chr((256 + ord(enc_char) - ord(key_char)) % 256)
                for enc_char, key_char in zip(enc, cycle(key))]
    return "".join(dec)

그리고 일부 테스트 ...

msg = 'The quick brown fox jumps over the lazy dog.'
key = 'jMG6JV3QdtRh3EhCHWUi'
print('cleartext: {0}'.format(msg))
print('ciphertext: {0}'.format(encode_zip_cycle(key, msg)))

encoders = [qneill_encode, encode_enumerate, encode_comprehension, encode_zip_cycle]
decoders = [qneill_decode, decode_enumerate, decode_comprehension, decode_zip_cycle]

# round-trip check for each pair of implementations
matched_pairs = zip(encoders, decoders)
assert all([decode(key, encode(key, msg)) == msg for encode, decode in matched_pairs])
print('Round-trips for encoder-decoder pairs: all tests passed')

# round-trip applying each kind of decode to each kind of encode to prove equivalent
from itertools import product
all_combinations = product(encoders, decoders)
assert all(decode(key, encode(key, msg)) == msg for encode, decode in all_combinations)
print('Each encoder and decoder can be swapped with any other: all tests passed')

>>> python crypt.py
cleartext: The quick brown fox jumps over the lazy dog.
ciphertext: vrWsVrvLnLTPlLTaorzWY67GzYnUwrSmvXaix8nmctybqoivqdHOic68rmQ=
Round-trips for encoder-decoder pairs: all tests passed
Each encoder and decoder can be swapped with any other: all tests passed

안전을 원한다면 암호로 Fernet을 사용할 수 있습니다. 별도로 저장하지 않으려는 경우 정적 "소금"을 사용할 수 있습니다. 사전 및 무지개 공격 방지 기능 만 손실됩니다. 길거나 짧은 암호를 선택할 수 있기 때문에 선택했습니다. AES에서는 쉽지 않습니다.

from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import base64

#set password
password = "mysecretpassword"
#set message
message = "secretmessage"

kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt="staticsalt", iterations=100000, backend=default_backend())
key = base64.urlsafe_b64encode(kdf.derive(password))
f = Fernet(key)

#encrypt
encrypted = f.encrypt(message)
print encrypted

#decrypt
decrypted = f.decrypt(encrypted)
print decrypted

너무 복잡하면 누군가가 simplecrypt를 제안했습니다.

from simplecrypt import encrypt, decrypt
ciphertext = encrypt('password', plaintext)
plaintext = decrypt('password', ciphertext)

참고 : Windows + Python 3.6 + 관련 문제 pycrypto( pip install pycryptoWindows 에서는 불가능 ) 또는 pycryptodome( 포크에서 지원 from Crypto.Cipher import XOR하지 않기 때문에 여기에 대한 답변 XOR실패했습니다 . 또한 라이브러리 에는 종속성이 있으므로 옵션이 아닙니다.pycrypto... AESTypeError: Object type <class 'str'> cannot be passed to C codesimple-cryptpycrypto


패키지를 사용하는 솔루션은 다음 cryptography과 같이 평소와 같이 설치할 수 있습니다 pip install cryptography.

import base64
from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

def encrypt(plaintext, password):
    f = Fernet(base64.urlsafe_b64encode(PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=b'abcd', iterations=1000, backend=default_backend()).derive(password.encode())))
    return f.encrypt(plaintext.encode()).decode()

def decrypt(ciphertext, password):
    f = Fernet(base64.urlsafe_b64encode(PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=b'abcd', iterations=1000, backend=default_backend()).derive(password.encode())))
    return f.decrypt(ciphertext.encode()).decode()

용법:

>>> encrypt('John Doe', password='mypass')
'gAAAAABciC64VNUoeLVoPKut7HxlPcsqJZTFf99EMYTmnR9jFkZBNMxklIDc5WZ6k3TxfcFSDO-4PRZUsOvywtGLSFwOzToO_g=='

>>> decrypt('gAAAAABciC64VNUoeLVoPKut7HxlPcsqJZTFf99EMYTmnR9jFkZBNMxklIDc5WZ6k3TxfcFSDO-4PRZUsOvywtGLSFwOzToO_g==', password='mypass')
'John Doe'

노트 :


이것은 작동하지만 암호 길이는 정확해야합니다 8. 이것은 간단하며 pyDes 가 필요합니다 .

from pyDes import *

def encode(data,password):
    k = des(password, CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
    d = k.encrypt(data)
    return d

def decode(data,password):
    k = des(password, CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
    d = k.decrypt(data)
    return d

x = encode('John Doe', 'mypass12')
y = decode(x,'mypass12')

print x
print y

산출:

³.\Þ\åS¾+æÅ`;Ê
John Doe

원본 메시지의 CRC 체크섬을 포함하는 @qneill 코드의 다른 구현으로, 검사에 실패하면 예외가 발생합니다.

import hashlib
import struct
import zlib

def vigenere_encode(text, key):
    text = '{}{}'.format(text, struct.pack('i', zlib.crc32(text)))

    enc = []
    for i in range(len(text)):
        key_c = key[i % len(key)]
        enc_c = chr((ord(text[i]) + ord(key_c)) % 256)
        enc.append(enc_c)

    return base64.urlsafe_b64encode("".join(enc))


def vigenere_decode(encoded_text, key):
    dec = []
    encoded_text = base64.urlsafe_b64decode(encoded_text)
    for i in range(len(encoded_text)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(encoded_text[i]) - ord(key_c)) % 256)
        dec.append(dec_c)

    dec = "".join(dec)
    checksum = dec[-4:]
    dec = dec[:-4]

    assert zlib.crc32(dec) == struct.unpack('i', checksum)[0], 'Decode Checksum Error'

    return dec

AES를 사용하여 비밀번호로 문자열을 암호화 할 수 있습니다. 그러나 사람들은 암호를 쉽게 추측 할 수 없도록 강력한 암호를 선택하고 싶을 것입니다 (죄송합니다. 죄송합니다. 보안 전문가입니다).

AES는 키 크기가 우수하지만 PyCrypto와 함께 사용하기도 쉽습니다.


외부 라이브러리는 비밀 키 암호화 알고리즘을 제공합니다.

예를 들어 CypherPyCrypto모듈 은 다양한 암호화 알고리즘을 제공합니다.

  • Crypto.Cipher.AES
  • Crypto.Cipher.ARC2
  • Crypto.Cipher.ARC4
  • Crypto.Cipher.Blowfish
  • Crypto.Cipher.CAST
  • Crypto.Cipher.DES
  • Crypto.Cipher.DES3
  • Crypto.Cipher.IDEA
  • Crypto.Cipher.RC5
  • Crypto.Cipher.XOR

MeTooCryptoOpenSSL을 위한 Python래퍼이며 다른 기능들 중에서도 강력한 범용 암호화 라이브러리를 제공합니다. 대칭 암호 (예 : AES)가 포함됩니다.


여기에 온 사람 (및 풍부한 사람)은 많은 설정이없는 한 줄짜리를 찾고있는 것처럼 보였지만 다른 대답은 제공하지 않습니다. 그래서 저는 base64를 제시합니다.

이제 이것은 기본적인 난독 화에 불과하며 ** 보안을 위해 절대로 괜찮지 않습니다 ** 에 있지만 일부 라이너는 다음과 같습니다.

from base64 import urlsafe_b64encode, urlsafe_b64decode

def encode(data, key):
    return urlsafe_b64encode(bytes(key+data, 'utf-8'))

def decode(enc, key):
    return urlsafe_b64decode(enc)[len(key):].decode('utf-8')

print(encode('hi', 'there')) # b'dGhlcmVoaQ=='
print(decode(encode('hi', 'there'), 'there')) # 'hi'

몇 가지 참고할 사항 :

  • I / O에 따라 더 많거나 적은 바이트 대 문자열 인코딩 / 디코딩을 직접 처리하고 싶을 것입니다. 조사 bytes()bytes::decode()
  • base64는 사용 된 문자 유형으로 쉽게 인식 할 수 있으며 =문자로 끝나는 경우가 많습니다 . 나와 같은 사람들은 웹 사이트에서 볼 때 자바 스크립트 콘솔에서 디코딩하는 것을 절대적으로 수행합니다. btoa(string)(js) 만큼 쉽다
  • b64에서와 같이 순서는 키 + 데이터입니다. 끝에 나타나는 문자는 시작 부분에있는 문자에 따라 다릅니다 (바이트 오프셋 때문에 Wikipedia 에 대한 좋은 설명이 있습니다). 이 시나리오에서 인코딩 된 문자열의 시작은 해당 키로 인코딩 된 모든 항목에서 동일합니다. 플러스는 데이터가 더 난독 화된다는 것입니다. 다른 방법으로 수행하면 키에 관계없이 모든 사람이 데이터 부분을 정확하게 동일하게 만듭니다.

자, 원하는 것이 어떤 종류의 키가 필요하지 않지만 난독 화가 필요한 경우 어떤 종류의 키없이 base64를 다시 사용할 수 있습니다.

from base64 import urlsafe_b64encode, urlsafe_b64decode

def encode(data):
    return urlsafe_b64encode(bytes(data, 'utf-8'))

def decode(enc):
    return urlsafe_b64decode(enc).decode()

print(encode('hi')) # b'aGk='
print(decode(encode('hi'))) # 'hi'

안전한 암호화를 원할 경우 :

파이썬 2의 경우 keyczar http://www.keyczar.org/ 를 사용해야합니다

파이썬 3의 경우 keyczar를 사용할 수있을 때까지 간단한 암호를 작성했습니다 http://pypi.python.org/pypi/simple-crypt

둘 다 키 강화를 사용하여 대부분의 다른 답변보다 안전합니다. 사용하기 쉬우므로 보안이 중요하지 않은 경우에도 사용할 수 있습니다.


따라서 미션 크리티컬이 인코딩되지 않기 때문에 난독 화 를 위해 암호화하고 싶습니다 .

시저의 암호를 보여 드리겠습니다

여기에 이미지 설명을 입력하십시오

Caesar의 암호 또는 Caesar 이동은 가장 단순하고 가장 널리 알려진 암호화 기술 중 하나입니다. 이것은 평문의 각 문자가 알파벳 아래의 고정 된 수의 문자로 대체되는 대체 암호 유형입니다. 예를 들어, 왼쪽 이동이 3이면 D는 A로 바뀌고 E는 B가됩니다.

참조 용 샘플 코드 :

def encrypt(text,s): 
        result = "" 

        # traverse text 
        for i in range(len(text)): 
            char = text[i] 

            # Encrypt uppercase characters 
            if (char.isupper()): 
                result += chr((ord(char) + s-65) % 26 + 65) 

            # Encrypt lowercase characters 
            else: 
                result += chr((ord(char) + s - 97) % 26 + 97) 

        return result 

    def decrypt(text,s): 
        result = "" 

        # traverse text 
        for i in range(len(text)): 
            char = text[i] 

            # Encrypt uppercase characters 
            if (char.isupper()): 
                result += chr((ord(char) - s-65) % 26 + 65) 

            # Encrypt lowercase characters 
            else: 
                result += chr((ord(char) - s - 97) % 26 + 97) 

        return result 

    #check the above function 
    text = "ATTACKATONCE"
    s = 4
    print("Text  : " + text) 
    print("Shift : " + str(s)) 
    print("Cipher: " + encrypt(text,s))
    print("Original text: " + decrypt(encrypt(text,s),s))

장점 : 요구 사항을 충족하고 간단하며 인코딩 작업을 수행합니다.

단점 : 단순한 무차별 강제 알고리즘으로 크랙 할 수 있습니다 (아무도 모든 추가 결과를 시도하지는 않을 것입니다).

참고 URL : https://stackoverflow.com/questions/2490334/simple-way-to-encode-a-string-according-to-a-password

반응형