เข้ารหัสและถอดรหัสโดยใช้ PyCrypto AES 256


171

ฉันกำลังพยายามสร้างสองฟังก์ชั่นโดยใช้ PyCrypto ที่ยอมรับสองพารามิเตอร์: ข้อความและกุญแจจากนั้นเข้ารหัส / ถอดรหัสข้อความ

ฉันพบลิงก์หลายรายการบนเว็บเพื่อช่วยเหลือฉัน แต่แต่ละลิงก์มีข้อบกพร่อง:

อันนี้ที่ codekoalaใช้ os.urandom ซึ่งเป็นท้อโดย PyCrypto

ยิ่งกว่านั้นคีย์ที่ฉันให้กับฟังก์ชั่นนั้นไม่รับประกันว่าจะมีความยาวตามที่คาดหวัง ฉันจะทำอย่างไรเพื่อให้เกิดขึ้น

นอกจากนี้ยังมีหลายโหมดที่หนึ่งที่แนะนำคืออะไร? ฉันไม่รู้จะใช้อะไร: /

ในที่สุด IV คืออะไร? ฉันสามารถให้ IV ที่แตกต่างกันสำหรับการเข้ารหัสและถอดรหัสหรือจะให้ผลตอบแทนที่แตกต่างกันหรือไม่?

แก้ไข : ลบส่วนรหัสเนื่องจากไม่ปลอดภัย


12
os.urandomได้รับการสนับสนุนบนเว็บไซต์PyCrypto มันใช้ฟังก์ชั่นCryptGenRandomของ Microsoft ซึ่งเป็นCSPRNG
Joel Vroom

5
หรือ/dev/urandomบน Unix
Joel Vroom

2
เพียงชี้แจงให้ชัดเจนในตัวอย่างนี้วลีรหัสผ่านคือคีย์ซึ่งสามารถเป็น 128, 192 หรือ 256 บิต (16, 24 หรือ 32 ไบต์)
ทำเครื่องหมาย

4
มันอาจจะมีมูลค่าการพูดถึงว่า PyCrypto เป็นโครงการที่ตายแล้ว คอมมิชชันล่าสุดคือจาก 2014 PyCryptodomeดูเหมือนเป็นการแทนที่แบบหล่นดี
Overdrivr

1
คำถามนี้เก่า แต่ฉันอยากจะชี้ให้เห็น (ณ ปี 2020) ว่า pycrypto นั้นล้าสมัยและไม่ได้รับการสนับสนุนอีกต่อไป ดูที่หน้า github ของพวกเขา ( github.com/pycrypto/pycrypto ) ดูเหมือนว่าพวกเขาจะทำข้อตกลงครั้งสุดท้ายในปี 2014 ฉันอยากจะใช้ซอฟต์แวร์ cryptographic ที่ไม่มีการพัฒนาอีกต่อไป
irritable_phd_syndrom

คำตอบ:


151

นี่คือการดำเนินการของฉันและทำงานสำหรับฉันด้วยการแก้ไขบางอย่างและเพิ่มการจัดตำแหน่งของวลีและวลีลับที่มี 32 ไบต์และ iv ถึง 16 ไบต์:

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

class AESCipher(object):

    def __init__(self, key): 
        self.bs = AES.block_size
        self.key = hashlib.sha256(key.encode()).digest()

    def encrypt(self, raw):
        raw = self._pad(raw)
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return base64.b64encode(iv + cipher.encrypt(raw.encode()))

    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        iv = enc[:AES.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')

    def _pad(self, s):
        return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)

    @staticmethod
    def _unpad(s):
        return s[:-ord(s[len(s)-1:])]

14
ฉันรู้ว่าสิ่งนี้เกิดขึ้นมาระยะหนึ่งแล้ว แต่ฉันคิดว่าคำตอบนี้อาจทำให้เกิดความสับสน ฟังก์ชั่นนี้ใช้ block_size 32 ไบต์ (256 ไบต์) เพื่อรองข้อมูลอินพุต แต่ AES ใช้ขนาดบล็อก 128 บิต ใน AES256 กุญแจคือ 256 บิต แต่ไม่ใช่ขนาดของบล็อก
แทนนิน

13
ที่จะทำให้มันเป็นอีกวิธีหนึ่ง "self.bs" ควรถูกลบและแทนที่ด้วย "AES.block_size"
Alexis

2
ทำไมคุณถึงคีย์แฮช หากคุณคาดหวังว่านี่เป็นรหัสผ่านคุณไม่ควรใช้ SHA256 ดีกว่าที่จะใช้ฟังก์ชั่นที่สำคัญมาเช่น PBKDF2 ซึ่ง PyCrypto ให้
tweaksp

5
@Chris - SHA256 มอบแฮชขนาด 32 ไบต์ - คีย์ขนาดสมบูรณ์แบบสำหรับ AES256 การสร้าง / การสืบทอดของคีย์นั้นถือว่าเป็นการสุ่ม / ปลอดภัยและควรอยู่นอกขอบเขตของรหัสการเข้ารหัส / ถอดรหัส - การแฮชเป็นเพียงการรับประกันว่ากุญแจนั้นสามารถใช้ได้กับรหัสตัวเลขที่เลือก
zwer

2
ในการเข้าถึง _pad self.bs เป็นสิ่งจำเป็นและใน _unpad ไม่จำเป็น
mnothic

149

คุณอาจต้องใช้สองฟังก์ชั่นต่อไปนี้: pad- เพื่อ pad (เมื่อทำการเข้ารหัส) และunpad- เพื่อ unpad (เมื่อทำการถอดรหัส) เมื่อความยาวของอินพุตไม่ได้เป็นหลาย BLOCK_SIZE

BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS) 
unpad = lambda s : s[:-ord(s[len(s)-1:])]

ดังนั้นคุณจะถามความยาวของคีย์? คุณสามารถใช้ md5sum ของปุ่มแทนที่จะใช้โดยตรง

เพิ่มเติมตามประสบการณ์เล็ก ๆ ของฉันในการใช้ PyCrypto ฉันใช้ IV เพื่อผสมเอาท์พุทของการเข้ารหัสเมื่ออินพุตเหมือนกันดังนั้น IV จึงเลือกเป็นสตริงแบบสุ่มและใช้เป็นส่วนหนึ่งของเอาท์พุทการเข้ารหัสแล้ว ใช้มันเพื่อถอดรหัสข้อความ

และนี่คือการดำเนินการของฉันหวังว่าจะเป็นประโยชน์สำหรับคุณ:

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

class AESCipher:
    def __init__( self, key ):
        self.key = key

    def encrypt( self, raw ):
        raw = pad(raw)
        iv = Random.new().read( AES.block_size )
        cipher = AES.new( self.key, AES.MODE_CBC, iv )
        return base64.b64encode( iv + cipher.encrypt( raw ) ) 

    def decrypt( self, enc ):
        enc = base64.b64decode(enc)
        iv = enc[:16]
        cipher = AES.new(self.key, AES.MODE_CBC, iv )
        return unpad(cipher.decrypt( enc[16:] ))

1
จะเกิดอะไรขึ้นถ้าคุณมีอินพุตที่เป็นจำนวนมากของ BLOCK_SIZE ฉันคิดว่าฟังก์ชั่น unpad จะสับสนเล็กน้อย ...
Kjir

2
@Kjir จากนั้นลำดับของค่า chr (BS) ที่มีความยาว BLOCK_SIZE จะถูกผนวกเข้ากับข้อมูลต้นทาง
มาร์คัส

1
@ Marcus padฟังก์ชั่นเสีย (อย่างน้อยใน Py3) แทนที่ด้วยs[:-ord(s[len(s)-1:])]เพื่อให้ทำงานข้ามรุ่น
Torxed

2
ฟังก์ชั่น @Torxed pad มีประโยชน์ใน CryptoUtil.Padding.pad () พร้อม pycryptodome (การติดตาม pycrypto)
comte

2
ทำไมไม่เพียง แต่มีค่าคงที่ตัวละครเป็นตัวรอง?
Inaimathi

16

ให้ฉันตอบคำถามของคุณเกี่ยวกับ "โหมด" AES256 เป็นชนิดของการเข้ารหัสบล็อก ใช้เป็นอินพุตคีย์ 32- ไบต์และสตริง 16- ไบต์เรียกว่าบล็อกและส่งออกบล็อก เราใช้ AES ในโหมดการทำงานเพื่อเข้ารหัส การแก้ปัญหาข้างต้นแนะนำให้ใช้ CBC ซึ่งเป็นตัวอย่างหนึ่ง อีกอันหนึ่งเรียกว่า CTR และใช้งานง่ายกว่า:

from Crypto.Cipher import AES
from Crypto.Util import Counter
from Crypto import Random

# AES supports multiple key sizes: 16 (AES128), 24 (AES192), or 32 (AES256).
key_bytes = 32

# Takes as input a 32-byte key and an arbitrary-length plaintext and returns a
# pair (iv, ciphtertext). "iv" stands for initialization vector.
def encrypt(key, plaintext):
    assert len(key) == key_bytes

    # Choose a random, 16-byte IV.
    iv = Random.new().read(AES.block_size)

    # Convert the IV to a Python integer.
    iv_int = int(binascii.hexlify(iv), 16) 

    # Create a new Counter object with IV = iv_int.
    ctr = Counter.new(AES.block_size * 8, initial_value=iv_int)

    # Create AES-CTR cipher.
    aes = AES.new(key, AES.MODE_CTR, counter=ctr)

    # Encrypt and return IV and ciphertext.
    ciphertext = aes.encrypt(plaintext)
    return (iv, ciphertext)

# Takes as input a 32-byte key, a 16-byte IV, and a ciphertext, and outputs the
# corresponding plaintext.
def decrypt(key, iv, ciphertext):
    assert len(key) == key_bytes

    # Initialize counter for decryption. iv should be the same as the output of
    # encrypt().
    iv_int = int(iv.encode('hex'), 16) 
    ctr = Counter.new(AES.block_size * 8, initial_value=iv_int)

    # Create AES-CTR cipher.
    aes = AES.new(key, AES.MODE_CTR, counter=ctr)

    # Decrypt and return the plaintext.
    plaintext = aes.decrypt(ciphertext)
    return plaintext

(iv, ciphertext) = encrypt(key, 'hella')
print decrypt(key, iv, ciphertext)

สิ่งนี้มักเรียกว่า AES-CTR ผมจะแนะนำให้ระมัดระวังในการใช้ AES-CBC กับ PyCrypto เหตุผลก็คือคุณจะต้องระบุรูปแบบการแพ็ดดิ้งดังที่ได้อธิบายไว้โดยโซลูชั่นอื่นที่ให้ไว้ โดยทั่วไปถ้าคุณไม่ได้มากระมัดระวังเกี่ยวกับช่องว่างภายในที่มีการโจมตีที่สมบูรณ์หยุดการเข้ารหัส!

ตอนนี้มันเป็นสิ่งสำคัญที่จะทราบว่ากุญแจสำคัญที่จะต้องเป็นแบบสุ่มสตริง 32 ไบต์ ; รหัสผ่านไม่เพียงพอ โดยปกติกุญแจจะถูกสร้างเช่น:

# Nominal way to generate a fresh key. This calls the system's random number
# generator (RNG).
key1 = Random.new().read(key_bytes)

รหัสอาจได้มาจากรหัสผ่านเช่นกัน:

# It's also possible to derive a key from a password, but it's important that
# the password have high entropy, meaning difficult to predict.
password = "This is a rather weak password."

# For added # security, we add a "salt", which increases the entropy.
#
# In this example, we use the same RNG to produce the salt that we used to
# produce key1.
salt_bytes = 8 
salt = Random.new().read(salt_bytes)

# Stands for "Password-based key derivation function 2"
key2 = PBKDF2(password, salt, key_bytes)

แก้ปัญหาบางอย่างข้างต้นขอแนะนำให้ใช้ SHA256 สำหรับ deriving คีย์ แต่โดยทั่วไปถือว่าการปฏิบัติการเข้ารหัสลับที่ไม่ดี ลองอ่านวิกิพีเดียเพื่อเรียนรู้เพิ่มเติมเกี่ยวกับโหมดการทำงาน


iv_int = int (binascii.hexlify (iv), 16) ไม่ทำงานแทนที่ด้วย iv_int = int (binascii.hexlify (iv), 16) พร้อมกับ 'import binascii' และควรทำงาน (บน Python 3.x ) งานที่ดีอย่างอื่น!
Valmond

โปรดทราบว่าเป็นการดีกว่าที่จะใช้โหมดการเข้ารหัส Autehnticated เป็น AES-GCM GCM ใช้โหมด CTR ภายใน
kelalaka

รหัสนี้ทำให้เกิด "TypeError: ประเภทวัตถุ <class 'str'> ไม่สามารถส่งผ่านไปยังรหัส C"
Da Woon Jung

7

สำหรับคนที่ต้องการใช้ urlsafe_b64encode และ urlsafe_b64decode ต่อไปนี้เป็นเวอร์ชั่นที่ใช้งานได้สำหรับฉัน (หลังจากใช้เวลากับปัญหา unicode)

BS = 16
key = hashlib.md5(settings.SECRET_KEY).hexdigest()[:BS]
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s : s[:-ord(s[len(s)-1:])]

class AESCipher:
    def __init__(self, key):
        self.key = key

    def encrypt(self, raw):
        raw = pad(raw)
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return base64.urlsafe_b64encode(iv + cipher.encrypt(raw)) 

    def decrypt(self, enc):
        enc = base64.urlsafe_b64decode(enc.encode('utf-8'))
        iv = enc[:BS]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return unpad(cipher.decrypt(enc[BS:]))

6

คุณสามารถรับข้อความรหัสผ่านไม่ได้โดยใช้รหัสผ่านโดยใช้ฟังก์ชั่นแฮชการเข้ารหัสลับ ( ไม่ใช่hashบิวอินPython ) เช่น SHA-1 หรือ SHA-256 Python มีการสนับสนุนทั้งในไลบรารีมาตรฐาน:

import hashlib

hashlib.sha1("this is my awesome password").digest() # => a 20 byte string
hashlib.sha256("another awesome password").digest() # => a 32 byte string

คุณสามารถตัดค่าแฮชของการเข้ารหัสได้โดยใช้[:16]หรือ[:24]มันจะรักษาความปลอดภัยให้ได้ตามความยาวที่คุณระบุ


13
คุณไม่ควรใช้ฟังก์ชันแฮช SHA-ครอบครัวสำหรับการสร้างที่สำคัญจากรหัสผ่าน - ดูเรียงความ Coda เฮลในหัวข้อ ลองใช้ฟังก์ชั่นการหาค่าคีย์จริงเช่นscryptแทน (เรียงความของ Coda Hale เขียนขึ้นก่อนการตีพิมพ์ของ scrypt)
Benjamin Barenblat

7
สำหรับผู้อ่านในอนาคตหากคุณกำลังหาคีย์จากวลีรหัสผ่านให้มองหา PBKDF2 มันค่อนข้างใช้งานง่ายใน python ( pypi.python.org/pypi/pbkdf2 ) หากคุณต้องการแฮชรหัสผ่าน bcrypt เป็นตัวเลือกที่ดีกว่า
C Fairweather

6

ขอบคุณสำหรับคำตอบอื่น ๆ ซึ่งเป็นแรงบันดาลใจ แต่ไม่ได้ผลสำหรับฉัน

หลังจากใช้เวลาหลายชั่วโมงเพื่อหาว่ามันทำงานอย่างไรฉันก็มากับการใช้งานด้านล่างด้วยPyCryptodomex library ใหม่ล่าสุด(มันเป็นอีกเรื่องที่ฉันจัดการเพื่อตั้งค่าหลังพร็อกซีบน Windows ใน virtualenv .. )

ทำงาน การนำไปใช้ของคุณอย่าลืมจดการแพ็ดการเข้ารหัสการเข้ารหัสขั้นตอน (และในทางกลับกัน) คุณต้องแพ็คและแกะออกจากใจในการสั่งซื้อ

นำเข้า base64
นำเข้า hashlib
จาก Cryptodome.Cipher นำเข้า AES
จาก Cryptodome.Random นำเข้า get_random_bytes

__key__ = hashlib.sha256 (b'16-key key '). digest ()

def เข้ารหัส (ดิบ):
    BS = AES.block_size
    แผ่น = lambda s: s + (BS - len (s)% BS) * chr (BS - len (s)% BS)

    raw = base64.b64encode (pad (raw) .encode ('utf8'))
    iv = get_random_bytes (AES.block_size)
    cipher = AES.new (คีย์ = __key__, โหมด = AES.MODE_CFB, iv = iv)
    return base64.b64encode (iv + cipher.encrypt (ดิบ))

def ถอดรหัส (enc):
    unpad = lambda s: s [: - ord (s [-1:])]

    enc = base64.b64decode (enc)
    iv = enc [: AES.block_size]
    cipher = AES.new (__ key__, AES.MODE_CFB, iv)
    คืนค่า unpad (base64.b64decode (cipher.decrypt (enc [AES.block_size:]))) ถอดรหัส ('utf8'))

ขอบคุณสำหรับตัวอย่างการใช้งานด้วย PyCryptodomeX libs นั่นเป็นประโยชน์มาก!
Ygramul

5

เพื่อประโยชน์ของผู้อื่นนี่คือการถอดรหัสของฉันซึ่งฉันได้รับโดยการรวมคำตอบของ @Cyril และ @Marcus สิ่งนี้จะถือว่าสิ่งนี้เข้ามาผ่านคำขอ HTTP ด้วยการเข้ารหัสข้อความที่ยกมาและการเข้ารหัส base64

import base64
import urllib2
from Crypto.Cipher import AES


def decrypt(quotedEncodedEncrypted):
    key = 'SecretKey'

    encodedEncrypted = urllib2.unquote(quotedEncodedEncrypted)

    cipher = AES.new(key)
    decrypted = cipher.decrypt(base64.b64decode(encodedEncrypted))[:16]

    for i in range(1, len(base64.b64decode(encodedEncrypted))/16):
        cipher = AES.new(key, AES.MODE_CBC, base64.b64decode(encodedEncrypted)[(i-1)*16:i*16])
        decrypted += cipher.decrypt(base64.b64decode(encodedEncrypted)[i*16:])[:16]

    return decrypted.strip()

5

อีกสิ่งหนึ่งเกี่ยวกับเรื่องนี้ (มาจากการแก้ปัญหาด้านบน) แต่

  • ใช้ null สำหรับการเติมเต็ม
  • ไม่ใช้แลมบ์ดา (ไม่เคยเป็นแฟน)
  • ทดสอบด้วย python 2.7 และ 3.6.5

    #!/usr/bin/python2.7
    # you'll have to adjust for your setup, e.g., #!/usr/bin/python3
    
    
    import base64, re
    from Crypto.Cipher import AES
    from Crypto import Random
    from django.conf import settings
    
    class AESCipher:
        """
          Usage:
          aes = AESCipher( settings.SECRET_KEY[:16], 32)
          encryp_msg = aes.encrypt( 'ppppppppppppppppppppppppppppppppppppppppppppppppppppppp' )
          msg = aes.decrypt( encryp_msg )
          print("'{}'".format(msg))
        """
        def __init__(self, key, blk_sz):
            self.key = key
            self.blk_sz = blk_sz
    
        def encrypt( self, raw ):
            if raw is None or len(raw) == 0:
                raise NameError("No value given to encrypt")
            raw = raw + '\0' * (self.blk_sz - len(raw) % self.blk_sz)
            raw = raw.encode('utf-8')
            iv = Random.new().read( AES.block_size )
            cipher = AES.new( self.key.encode('utf-8'), AES.MODE_CBC, iv )
            return base64.b64encode( iv + cipher.encrypt( raw ) ).decode('utf-8')
    
        def decrypt( self, enc ):
            if enc is None or len(enc) == 0:
                raise NameError("No value given to decrypt")
            enc = base64.b64decode(enc)
            iv = enc[:16]
            cipher = AES.new(self.key.encode('utf-8'), AES.MODE_CBC, iv )
            return re.sub(b'\x00*$', b'', cipher.decrypt( enc[16:])).decode('utf-8')

สิ่งนี้จะไม่ทำงานหากอินพุตไบต์ [] มีค่า null ต่อท้ายเนื่องจากในฟังก์ชั่นถอดรหัส () คุณจะกินค่าว่างในการเติมเต็มของคุณบวกกับค่าว่างใด ๆ ที่ตามมา
Buzz Moschetti

ใช่ดังที่ฉันได้กล่าวไว้ข้างต้นตรรกะแผ่นนี้มีโมฆะ หากรายการที่คุณต้องการเข้ารหัส / ถอดรหัสอาจมีค่า null ต่อท้ายให้ใช้หนึ่งในโซลูชันอื่น ๆ ที่นี่
MIkee

3

ฉันได้ใช้ทั้งสองCryptoและPyCryptodomexห้องสมุดและมันก็เป็นอย่างเห็นได้ชัด ...

import base64
import hashlib
from Cryptodome.Cipher import AES as domeAES
from Cryptodome.Random import get_random_bytes
from Crypto import Random
from Crypto.Cipher import AES as cryptoAES

BLOCK_SIZE = AES.block_size

key = "my_secret_key".encode()
__key__ = hashlib.sha256(key).digest()
print(__key__)

def encrypt(raw):
    BS = cryptoAES.block_size
    pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
    raw = base64.b64encode(pad(raw).encode('utf8'))
    iv = get_random_bytes(cryptoAES.block_size)
    cipher = cryptoAES.new(key= __key__, mode= cryptoAES.MODE_CFB,iv= iv)
    a= base64.b64encode(iv + cipher.encrypt(raw))
    IV = Random.new().read(BLOCK_SIZE)
    aes = domeAES.new(__key__, domeAES.MODE_CFB, IV)
    b = base64.b64encode(IV + aes.encrypt(a))
    return b

def decrypt(enc):
    passphrase = __key__
    encrypted = base64.b64decode(enc)
    IV = encrypted[:BLOCK_SIZE]
    aes = domeAES.new(passphrase, domeAES.MODE_CFB, IV)
    enc = aes.decrypt(encrypted[BLOCK_SIZE:])
    unpad = lambda s: s[:-ord(s[-1:])]
    enc = base64.b64decode(enc)
    iv = enc[:cryptoAES.block_size]
    cipher = cryptoAES.new(__key__, cryptoAES.MODE_CFB, iv)
    b=  unpad(base64.b64decode(cipher.decrypt(enc[cryptoAES.block_size:])).decode('utf8'))
    return b

encrypted_data =encrypt("Hi Steven!!!!!")
print(encrypted_data)
print("=======")
decrypted_data = decrypt(encrypted_data)
print(decrypted_data)

2

มันสายไปหน่อย แต่ฉันคิดว่ามันจะมีประโยชน์มาก ไม่มีใครพูดถึงเกี่ยวกับรูปแบบการใช้งานเช่นการเติม PKCS # 7 คุณสามารถใช้ฟังก์ชั่นก่อนหน้านี้แทน pad (เมื่อทำการเข้ารหัส) และ unpad (เมื่อทำการถอดรหัส) .i จะให้รหัสแหล่งที่มาแบบเต็มด้านล่าง

import base64
import hashlib
from Crypto import Random
from Crypto.Cipher import AES
import pkcs7
class Encryption:

    def __init__(self):
        pass

    def Encrypt(self, PlainText, SecurePassword):
        pw_encode = SecurePassword.encode('utf-8')
        text_encode = PlainText.encode('utf-8')

        key = hashlib.sha256(pw_encode).digest()
        iv = Random.new().read(AES.block_size)

        cipher = AES.new(key, AES.MODE_CBC, iv)
        pad_text = pkcs7.encode(text_encode)
        msg = iv + cipher.encrypt(pad_text)

        EncodeMsg = base64.b64encode(msg)
        return EncodeMsg

    def Decrypt(self, Encrypted, SecurePassword):
        decodbase64 = base64.b64decode(Encrypted.decode("utf-8"))
        pw_encode = SecurePassword.decode('utf-8')

        iv = decodbase64[:AES.block_size]
        key = hashlib.sha256(pw_encode).digest()

        cipher = AES.new(key, AES.MODE_CBC, iv)
        msg = cipher.decrypt(decodbase64[AES.block_size:])
        pad_text = pkcs7.decode(msg)

        decryptedString = pad_text.decode('utf-8')
        return decryptedString

import StringIO
import binascii


def decode(text, k=16):
    nl = len(text)
    val = int(binascii.hexlify(text[-1]), 16)
    if val > k:
        raise ValueError('Input is not padded or padding is corrupt')

    l = nl - val
    return text[:l]


def encode(text, k=16):
    l = len(text)
    output = StringIO.StringIO()
    val = k - (l % k)
    for _ in xrange(val):
        output.write('%02x' % val)
    return text + binascii.unhexlify(output.getvalue())


ฉันไม่รู้ว่าใครโหวตคำตอบลง แต่ฉันอยากรู้ว่าทำไม บางทีวิธีนี้อาจไม่ปลอดภัยใช่ไหม คำอธิบายจะดีมาก
Cyril N.

1
@CyrilN คำตอบนี้แสดงให้เห็นว่าการแฮ็รหัสผ่านด้วยการเรียกใช้ SHA-256 เพียงครั้งเดียวก็เพียงพอแล้ว มันไม่ใช่ คุณควรใช้ PBKDF2 หรือคล้ายกันสำหรับการได้มาของรหัสผ่านโดยใช้จำนวนการวนซ้ำที่มาก
Artjom B.

ขอบคุณสำหรับรายละเอียด @ArtjomB.!
Cyril N.

ฉันมีกุญแจและยังมีปุ่ม iv ความยาว 44 ฉันจะใช้ฟังก์ชั่นของคุณได้อย่างไร! อัลกอริทึมทั้งหมดในอินเทอร์เน็ตที่ฉันพบมีปัญหาเกี่ยวกับความยาวของคีย์เวคเตอร์ของฉัน
mahshid.r


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

BLOCK_SIZE=16
def trans(key):
     return md5.new(key).digest()

def encrypt(message, passphrase):
    passphrase = trans(passphrase)
    IV = Random.new().read(BLOCK_SIZE)
    aes = AES.new(passphrase, AES.MODE_CFB, IV)
    return base64.b64encode(IV + aes.encrypt(message))

def decrypt(encrypted, passphrase):
    passphrase = trans(passphrase)
    encrypted = base64.b64decode(encrypted)
    IV = encrypted[:BLOCK_SIZE]
    aes = AES.new(passphrase, AES.MODE_CFB, IV)
    return aes.decrypt(encrypted[BLOCK_SIZE:])

10
โปรดให้รหัสไม่เพียง แต่ยังอธิบายสิ่งที่คุณกำลังทำและทำไมมันถึงดีกว่า / อะไรคือความแตกต่างของคำตอบที่มีอยู่
Florian Koch

แทนที่ md5.new (คีย์) .digest () โดย md5 (คีย์) .digest () และทำงานได้เหมือนเครื่องราง!
A STEFANI
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.