Encrypt / decrypt data in python with salt

前端 未结 2 385
春和景丽
春和景丽 2021-01-30 11:34

I\'d like to know basically how can I encrypt data with a generated salt key and then decrypt it using python ?

i\'ve gone trough a lot of websites and modules, and they

相关标签:
2条回答
  • 2021-01-30 12:30

    The short answer to your question is that you combine the password and the salt and hash them repeatedly to create your key. Then you append the salt onto the ciphertext so that you can generate the key for decryption. To ensure that I had the right answer, I made a few functions to do the work. They are given below.

    In my answer, I've made use of pycrypto, so we need to import a few of those libraries.

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

    To aid readability, I've defined a few constants that I'll use later on.

    # salt size in bytes
    SALT_SIZE = 16
    
    # number of iterations in the key generation
    NUMBER_OF_ITERATIONS = 20
    
    # the size multiple required for AES
    AES_MULTIPLE = 16
    

    To use a salt, I've done a password-based encryption scheme. I've used the RSA PKCS #5 standard for password-based encryption key generation and padding, adapted for the AES encryption algorithm.

    To generate the key, the password and the salt are concatenated. This combination is hashed as many times as requested.

    def generate_key(password, salt, iterations):
        assert iterations > 0
    
        key = password + salt
    
        for i in range(iterations):
            key = hashlib.sha256(key).digest()  
    
        return key
    

    To pad the text, you figure out how many extra bytes you have beyond an even multiple of 16. If it is 0, you add 16 bytes of padding, if it is 1, you add 15, etc. This way you always add padding. The character you pad with is the character with the same value as the number of padding bytes (chr(padding_size)), to aid the removal of the padding at the end (ord(padded_text[-1])).

    def pad_text(text, multiple):
        extra_bytes = len(text) % multiple
    
        padding_size = multiple - extra_bytes
    
        padding = chr(padding_size) * padding_size
    
        padded_text = text + padding
    
        return padded_text
    
    def unpad_text(padded_text):
        padding_size = ord(padded_text[-1])
    
        text = padded_text[:-padding_size]
    
        return text
    

    Encryption requires generating a random salt and using that along with the password to generate the encryption key. The text is padded using the above pad_text function and then encrypted with a cipher object. The ciphertext and salt are concatenated and returned as a result. If you wanted to send this as plaintext, you would need to encode it with base64.

    def encrypt(plaintext, password):
        salt = Crypto.Random.get_random_bytes(SALT_SIZE)
    
        key = generate_key(password, salt, NUMBER_OF_ITERATIONS)
    
        cipher = AES.new(key, AES.MODE_ECB)
    
        padded_plaintext = pad_text(plaintext, AES_MULTIPLE)
    
        ciphertext = cipher.encrypt(padded_plaintext)
    
        ciphertext_with_salt = salt + ciphertext
    
        return ciphertext_with_salt
    

    Decryption proceeds backwards, pulling the salt off of the ciphertext and using that to decrypt the remainder of the ciphertext. Then the plaintext is unpadded using unpad_text.

    def decrypt(ciphertext, password):
        salt = ciphertext[0:SALT_SIZE]
    
        ciphertext_sans_salt = ciphertext[SALT_SIZE:]
    
        key = generate_key(password, salt, NUMBER_OF_ITERATIONS)
    
        cipher = AES.new(key, AES.MODE_ECB)
    
        padded_plaintext = cipher.decrypt(ciphertext_sans_salt)
    
        plaintext = unpad_text(padded_plaintext)
    
        return plaintext
    

    Let me know if you have any other questions/clarifications.

    0 讨论(0)
  • 2021-01-30 12:33

    You don't need anything else than RNCryptor:

    import rncryptor
    
    data = '...'
    password = '...'
    
    # rncryptor.RNCryptor's methods
    cryptor = rncryptor.RNCryptor()
    encrypted_data = cryptor.encrypt(data, password)
    decrypted_data = cryptor.decrypt(encrypted_data, password)
    assert data == decrypted_data
    
    # rncryptor's functions
    encrypted_data = rncryptor.encrypt(data, password)
    decrypted_data = rncryptor.decrypt(encrypted_data, password)
    assert data == decrypted_data
    

    It provides semantically secure (random salt and IV for each encryption) encryption and includes secure integrity checking (ciphertext cannot be manipulated without noticing) through HMAC.

    RNCryptor also has a specific data format so you don't have to think about that and implementations in many languages.

    0 讨论(0)
提交回复
热议问题