복붙노트

[PYTHON] AES + CTR을 사용한 PyCrypto 문제

PYTHON

AES + CTR을 사용한 PyCrypto 문제

대칭 암호화를 사용하여 텍스트를 암호화하는 코드를 작성하고 있습니다. 하지만 올바른 결과를 얻지 못하면 ...

from Crypto.Cipher import AES
import os

crypto = AES.new(os.urandom(32), AES.MODE_CTR, counter = lambda : os.urandom(16))
encrypted = crypto.encrypt("aaaaaaaaaaaaaaaa")
print crypto.decrypt(encrypted)

여기서, 해독 된 텍스트는 원본과 다릅니다.

나는 암호에 대해 많은 것을 정말로 이해하지 못하므로 나와 함께 참아주십시오. CTR 모드에서 매번 임의의 카운터를 제공하는 "카운터"기능이 필요하지만 내 키가 32 바이트 일 때 16 바이트가 필요한 이유는 무엇이며 내 메시지가 16 바이트의 배수이기도하다고 주장하는 이유는 무엇입니까? 이게 정상인가?

카운터가 암호화와 암호 해독 사이에서 변경 되었기 때문에 원본 메시지로 돌아 가지 않는다고 생각합니다. 그렇다면 어쨌든 이론적으로 어떻게 작동해야합니까? 내가 뭘 잘못하고 있죠? 어쨌든, 나는 이것을 알아낼 때까지 ECB에 다시 의지해야합니다. (

해결법

  1. ==============================

    1.카운터는 암호화시와 마찬가지로 암호 해독시 동일한 값을 반환해야합니다. 즉, 사용자가 직관적으로 수행해야하므로 하나의 (모두 안전하지는 않음) 방법은 다음과 같습니다.

    카운터는 암호화시와 마찬가지로 암호 해독시 동일한 값을 반환해야합니다. 즉, 사용자가 직관적으로 수행해야하므로 하나의 (모두 안전하지는 않음) 방법은 다음과 같습니다.

    >>> secret = os.urandom(16)
    >>> crypto = AES.new(os.urandom(32), AES.MODE_CTR, counter=lambda: secret)
    >>> encrypted = crypto.encrypt("aaaaaaaaaaaaaaaa")
    >>> print crypto.decrypt(encrypted)
    aaaaaaaaaaaaaaaa
    

    CTR은 블록 암호이므로 사용자를 놀라게하는 "16시 간"제약은 매우 자연스러운 것입니다.

    물론, 각 호출에서 동일한 값을 반환하는 소위 "카운터"는 매우 안전하지 않습니다. 예를 들어 .... 더 좋아지지 않을 정도로 많이하지 않습니다.

    import array
    
    class Secret(object):
      def __init__(self, secret=None):
        if secret is None: secret = os.urandom(16)
        self.secret = secret
        self.reset()
      def counter(self):
        for i, c in enumerate(self.current):
          self.current[i] = c + 1
          if self.current: break
        return self.current.tostring()
      def reset(self):
        self.current = array.array('B', self.secret)
    
    secret = Secret()
    crypto = AES.new(os.urandom(32), AES.MODE_CTR, counter=secret.counter)
    encrypted = crypto.encrypt(16*'a' + 16*'b' + 16*'c')
    secret.reset()
    print crypto.decrypt(encrypted)
    
  2. ==============================

    2.AES는 블록 암호입니다 : 키와 메시지 블록을 가져 와서 블록을 암호화하거나 암호 해독하는 알고리즘 (더 정확하게는 한 쌍의 알고리즘)입니다. 블록 크기는 키 크기에 관계없이 항상 16 바이트입니다.

    AES는 블록 암호입니다 : 키와 메시지 블록을 가져 와서 블록을 암호화하거나 암호 해독하는 알고리즘 (더 정확하게는 한 쌍의 알고리즘)입니다. 블록 크기는 키 크기에 관계없이 항상 16 바이트입니다.

    CTR은 운영 모드입니다. 블록 암호를 기반으로하는 임의의 길이의 메시지를 암호화하고 해독 할 수있는 스트림 암호를 생성하는 알고리즘입니다.

    CTR은 연속적인 메시지 블록을 연속적인 카운터 값의 암호화와 결합하여 작동합니다. 카운터의 크기는 블록 암호에 대해 유효한 입력이되도록 한 블록이어야합니다.

    발신자가 카운터 기능을 선택하게함으로써 PyCrypto 라이브러리는 많은 로프를 제공합니다. Crypto.Util.Counter를 사용해야합니다. 문서가 말한대로 "성능 향상"뿐만 아니라 스스로 생각해 낼 수있는 것보다 안전한 무언가를 만드는 것이 더 쉽기 때문입니다. 그렇더라도 기본값이 아닌 임의의 초기 값을 사용하도록주의하십시오.

    import binascii
    import os
    from Crypto.Cipher import AES
    from Crypto.Util import Counter
    def int_of_string(s):
        return int(binascii.hexlify(iv), 16)
    def encrypt_message(key, plaintext):
        iv = os.urandom(16)
        ctr = Counter.new(128, initial_value=int_of_string(iv))
        aes = AES.new(key, AES.MODE_CTR, counter=ctr)
        return iv + aes.encrypt(plaintext)
    def decrypt_message(key, ciphertext):
        iv = ciphertext[:16]
        ctr = Counter.new(128, initial_value=int_of_string(iv))
        aes = AES.new(key, AES.MODE_CTR, counter=ctr)
        return aes.decrypt(ciphertext[16:])
    
  3. ==============================

    3.암호의 블록 크기와 동일한 길이 여야합니다. CTR 모드는 카운터를 암호화하고 일반 텍스트를 암호화 된 카운터 블록과 XOR합니다.

    암호의 블록 크기와 동일한 길이 여야합니다. CTR 모드는 카운터를 암호화하고 일반 텍스트를 암호화 된 카운터 블록과 XOR합니다.

    노트:

    표준 면책 조항 : 암호화가 어렵습니다. 자신이하는 일을 이해하지 못한다면 잘못 될 것입니다.

    scrypt를 사용하십시오. scrypt는 AES-CTR을 암호 파생 키와 함께 사용하는 암호화 및 암호 해독을 포함합니다.

    $ pip install scrypt
    
    $ python
    >>> import scrypt
    >>> import getpass
    >>> pw = getpass.getpass("enter password:")
    enter password:
    >>> encrypted = scrypt.encrypt("Guido is a space alien.",pw)
    >>> out = scrypt.decrypt(encrypted,pw)
    >>> out
    'Guido is a space alien.'
    
  4. ==============================

    4.초기화 벡터 ( "counter")는 암호화와 암호 해독 사이에 키가하는 것과 동일하게 유지되어야합니다. 그것은 같은 텍스트를 백만 번 인코딩 할 수 있고 매번 다른 암호 텍스트를 얻을 수 있도록 (알려진 평문 공격과 패턴 일치 / 공격을 방지하기 위해) 사용됩니다. 암호화 할 때와 마찬가지로 해독 할 때 동일한 IV를 사용해야합니다. 일반적으로 스트림의 암호 해독을 시작하면 IV를 해당 스트림의 암호화를 시작할 때 시작한 것과 동일한 값으로 초기화합니다.

    초기화 벡터 ( "counter")는 암호화와 암호 해독 사이에 키가하는 것과 동일하게 유지되어야합니다. 그것은 같은 텍스트를 백만 번 인코딩 할 수 있고 매번 다른 암호 텍스트를 얻을 수 있도록 (알려진 평문 공격과 패턴 일치 / 공격을 방지하기 위해) 사용됩니다. 암호화 할 때와 마찬가지로 해독 할 때 동일한 IV를 사용해야합니다. 일반적으로 스트림의 암호 해독을 시작하면 IV를 해당 스트림의 암호화를 시작할 때 시작한 것과 동일한 값으로 초기화합니다.

    초기화 벡터에 대한 정보는 http://en.wikipedia.org/wiki/Initialization_vector를 참조하십시오.

    os.urandom (16)은 카운터 기능에 대한 요구 사항 인 '결정 론적'이 아닙니다. CTR 모드가 디자인 된 방식대로 증가 함수를 사용하는 것이 좋습니다. 초기 카운터 값은 임의적이어야하지만 연속 값은 초기 값에서 완전히 예측 가능해야합니다 (결정적). 초기 값은 당신을 위해 돌봐 줄 수도 있습니다 (나는 세부적인 것을 모릅니다)

    키, IV 및 입력 크기에 관해서는 선택한 암호가 16 바이트의 블록 크기를 갖는 것처럼 들립니다. 당신이 묘사하는 모든 것이 나에게 맞는 것처럼 보입니다.

  5. ==============================

    5.분명히 늦었을 수도 있고 이전 답변을 간과 한 것일 수도 있지만, PyCrypto 패키지에 따라이 작업을 수행하는 방법에 대한 명확한 진술을 찾지 못했습니다.

    분명히 늦었을 수도 있고 이전 답변을 간과 한 것일 수도 있지만, PyCrypto 패키지에 따라이 작업을 수행하는 방법에 대한 명확한 진술을 찾지 못했습니다.

    Crypto.Util.Counter 패키지는 호출 가능한 상태 저장 카운터를 제공합니다.이 카운터는 매우 유용하지만 적어도 부적절하게 사용하는 것은 쉽습니다.

    예를 들어 다음과 같이 카운터를 만들어야합니다. ctr = Counter.new ( '매개 변수는 여기'). 카운터가 메시지를 암호화하기 위해 카운터 모드 암호 개체에 의해 호출 될 때마다 증가합니다. 이는 좋은 암호 기법에 필요하며 그렇지 않으면 동일한 블록에 대한 정보가 암호문에서 누출 될 수 있습니다.

    이제 같은 암호 개체에서 암호 해독 함수를 호출 할 수 없습니다. 왜냐하면 동일한 암호 개체를 다시 호출하기 때문에 그 사이에 여러 번 증분되었을 수 있습니다. 당신이해야 할 일은 동일한 매개 변수로 초기화 된 다른 카운터로 새로운 암호 객체를 만드는 것입니다. 이렇게하면 암호 해독이 제대로 작동하여 암호화가 수행 된 지점에서 카운터가 시작됩니다.

    아래 작업 예제 :

    # Import modules
    from Crypto.Cipher import AES
    from Crypto import Random
    from Crypto.Util import Counter
    
    
    # Pad for short keys
    pad = '# constant pad for short keys ##'
    
    # Generate a random initialization vector, to be used by both encryptor and decryptor
    # This may be sent in clear in a real communication
    
    random_generator = Random.new()
    IV = random_generator.read(8)
    
    
    # Encryption steps
    
    # Ask user for input and pad or truncate to a 32 bytes (256 bits) key
    prompt = 'Input your key. It will padded or truncated at 32 bytes (256 bits).\n-: '
    user_keye = raw_input(prompt)
    keye = (user_keye + pad)[:32]
    
    # Create counter for encryptor
    ctr_e = Counter.new(64, prefix=IV)
    
    # Create encryptor, ask for plaintext to encrypt, then encrypt and print ciphertext
    encryptor = AES.new(keye, AES.MODE_CTR, counter=ctr_e)
    plaintext = raw_input('Enter message to cipher: ')
    ciphertext = encryptor.encrypt(plaintext)
    print ciphertext
    print
    
    
    # Decryption steps
    
    # Ask user for key: it must be equal to that used for encryption
    prompt = 'Input your key. It will padded or truncated at 32 bytes (256 bits).\n-: '
    user_keyd = raw_input(prompt)
    keyd = (user_keyd + pad)[:32]
    
    # Create counter for decryptor: it is equal to the encryptor, but restarts from the beginning
    
    ctr_d = Counter.new(64, prefix=IV)
    
    # Create decryptor, then decrypt and print decoded text
    decryptor = AES.new(keyd, AES.MODE_CTR, counter=ctr_d)
    decoded_text = decryptor.decrypt(ciphertext)
    print decoded_text
    
  6. from https://stackoverflow.com/questions/3154998/pycrypto-problem-using-aesctr by cc-by-sa and MIT license