0

I am running into the issue of my decrypt_file function unable to decrypt text which was encrypted, No errors are provided just unexpected returns.

The encryption function uses salt and a password to encrypt a text file, then saves it as a .enc file, Then after attempting to run my decrypt_file function, it identifies the salt, iv, password, iterations, ect but does not decrypt() properly. Here is the code. And a dry run. Any guidance or help would be appreciated.

Encryption/Decryption:

from Crypto import Random
from Crypto.Cipher import AES
from base64 import b64encode, b64decode
from os import urandom
import hashlib

def key_generation(password, salt, iterations):
    assert iterations > 0
    print "Salt: " + salt, '\n', "Password: " + password
    key = password + salt #Combines [password] and [salt] to create a [key]
    for i in range(iterations): #Hashes the [key]
        key = hashlib.sha256(key).digest() #Using Sha256 it hashes the [key] based on amount of [iterations]
    print '\nKey: ' + key #Debug Print
    return key

def pad(s):
    return s + b"\0" * (AES.block_size - len(s) % AES.block_size)

def encryption(message, password, salt, iterations, key_size=256):
    key = key_generation(password, salt, iterations)
    message = pad(message)
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    print "Random IV: " + iv
    enc = salt + iv + cipher.encrypt(message)
    print "Length: " + str(len(enc))
    enc = pad(enc)
    print "Length: " + str(len(enc))
    return enc


def decryption(ciphertext, password, iterations):
    salt = ciphertext[0:16]
    iv = ciphertext[:AES.block_size]
    print len(str(iv))
    print len(str(salt))
    key = key_generation(password, salt, iterations)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    plaintext = cipher.decrypt(ciphertext[AES.block_size:])
    print "Plaintext: " + plaintext
    return plaintext.rstrip(b"\0")

def encrypt_file(file_name, password, salt, iterations):
    with open(file_name, 'rb') as fo:
        plaintext = fo.read()
        print "Text: " + plaintext
    enc = encryption(plaintext, password, salt, iterations)
    print "Encrypted Contents: " + enc
    with open(file_name + ".enc", 'wb') as fo:
        fo.write(enc)

def decrypt_file(file_name, password, iterations):
    with open(file_name, 'rb') as fo:
        ciphertext = fo.read()
        print "Cipher'd Text: " + ciphertext
    dec = decryption(ciphertext, password, iterations)
    with open(file_name[:-4], 'wb') as fo:
        fo.write(dec)

encrypt_file('HelloWorld.txt', 'password', 'randomsalt', 64000)
decrypt_file('HelloWorld.txt.enc', 'password', 64000)

Dry Run:

Encrypt:

Text: }¦—Z“Íd¥çgZw?øÈH™«Nœfra¥)ÊãjnÞª»^}K^Ì„¦ý
×¾Šv“_3w€mG9‚ä¤Å¥žUƯ0£Óy®0²
nrfÖÖ «–‰¯ò
Salt: randomsalt 
Password: password

Key: /Îbdヘ5è!ニヒAᆰv=L*øK/ò)Ü
Random IV: eミý1ËÈUÓbIワᄡムl
Length: 138
Length: 144
Encrypted Contents: randomsalteミý1ËÈUÓbIワᄡムl$֭>oリ)<L゙y\I!%wÙßÞlモÊJt$ワ
è   Ì-ᄈMᄀ8ヘ!ᄚܩᄃÆ4ÒO9AÃðO.ä3}ヘål{ヌヒ@ÿËzᄋgDᆰ\éUʼaà8タLᅠMupaÔAミマX0ンᄉi3ヨ˧cᄃ;ᆱÛo

Decrypt:

Cipher'd Text: randomsalteミý1ËÈUÓbIワᄡムl$֭>oリ)<L゙y\I!%wÙßÞlモÊJt$ワ
è   Ì-ᄈMᄀ8ヘ!ᄚܩᄃÆ4ÒO9AÃðO.ä3}ヘål{ヌヒ@ÿËzᄋgDᆰ\éUʼaà8タLᅠMupaÔAミマX0ンᄉi3ヨ˧cᄃ;ᆱÛo
16
16
Salt: randomsalteミý1Ë 
Password: password

Key: 1ÜA !TzxGÑ`wß~|º‹|¡(—ª-%òÇŒÖ
Plaintext: Rネ*SᄊÕñÛ.
t-Îテýト͛'úᄎSタ&2ᆴæマéヌᄏýýᄑtçØÉe?×ûìrモᄈÞcᄎᄇ×_Kメ
ᄎÀ~ä'ᄅ,ᄉ-Èᄀt&gSð:WÕ|
メ^リøᄃ]ノヤÏYvísgl/ᆵレホ*`\ᄚåᄌŴÇlヒÓ!Â`゚
  • Take a look at [this post](http://stackoverflow.com/q/22816617/589259) and my answer there. – Maarten Bodewes Apr 03 '14 at 07:24
  • After reviewing that post, I am somewhat confused based on your answer. I am some what new to this, and I am confused by what you said "You are transferring your ciphertext and key as strings. You should make sure that the bytes that make up the ciphertext and keys stay intact." What would be the most effective way to make sure that the bytes stay intact. Thanks for taking the time to expand on this question as I am being confused by this. – Archimedes - Charles Apr 03 '14 at 19:30
  • Please take a look at - for instance - this q/a about representing byte arrays: http://stackoverflow.com/questions/7380460/byte-array-in-python – Maarten Bodewes Apr 03 '14 at 21:55
  • Aren't your salt and IV identical during decryption? I'm no Python expert, but maybe that is incorrect? Maybe you can display the values in hexadecimals instead of bytes? Printing out just the bytes will give you a lot of unreadable garbage; hexadecimals is a lot better for bytes. – Maarten Bodewes Apr 03 '14 at 22:10

1 Answers1

0

So please print things out in hexadecimals. You can then clearly see that indeed during decrypt that the salt and IV were overlapping. In your code you were also assuming a different length salt than that was given.

from Crypto import Random
from Crypto.Cipher import AES
from base64 import b64encode, b64decode
from os import urandom
import hashlib
import binascii


def key_generation(password, salt, iterations):
    assert iterations > 0
    print "Salt: " + tohex(salt), '\n', "Password: " + password
    key = password + salt #Combines [password] and [salt] to create a [key]
    for i in range(iterations): #Hashes the [key]
        key = hashlib.sha256(key).digest() #Using Sha256 it hashes the [key] based on amount of [iterations]
    return key

def pad(s):
    return s + b"\0" * (AES.block_size - len(s) % AES.block_size)

def encryption(message, password, salt, iterations, key_size=256):

    print " === ENCRYPTION === "

    key = key_generation(password, salt, iterations)
    print "Key: " + tohex(key)
    message = pad(message)
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    print "Random IV: " + tohex(iv)
    enc = salt + iv + cipher.encrypt(message)
    return enc


def decryption(ciphertext, password, iterations):

    print " === DECRYPTION === "

    salt = ciphertext[0:10]
    iv = ciphertext[10:10+AES.block_size]
    print "Random IV: " + tohex(iv)
    key = key_generation(password, salt, iterations)
    print "Key: " + tohex(key)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    plaintext = cipher.decrypt(ciphertext[10+AES.block_size:])
    print "Plaintext: " + plaintext
    return plaintext.rstrip(b"\0")

def encrypt_file(file_name, password, salt, iterations):
    with open(file_name, 'rb') as fo:
        plaintext = fo.read()
        print "Text: " + plaintext
    enc = encryption(plaintext, password, salt, iterations)
    print "Encrypted Contents: " + enc
    with open(file_name + ".enc", 'wb') as fo:
        fo.write(enc)

def decrypt_file(file_name, password, iterations):
    with open(file_name, 'rb') as fo:
        ciphertext = fo.read()
        print "Cipher'd Text: " + ciphertext
    dec = decryption(ciphertext, password, iterations)
    with open(file_name + ".dec", 'wb') as fo:
        fo.write(dec)

def tohex(data):
    return binascii.hexlify(data)

encrypt_file('HelloWorld.txt', 'password', 'randomsalt', 64000)
decrypt_file('HelloWorld.txt.enc', 'password', 64000)
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • That makes a lot more sense, I was going to use a "#" as padding, even though its not "pretty", but after you showed me the tohex function. I appreciate all the help. – Archimedes - Charles Apr 03 '14 at 23:24
  • I've gotta sleep, question within 2 min. please. – Maarten Bodewes Apr 04 '14 at 00:59
  • If you don't get this its okay, but while you might still be here, I got a quick question you might be able to answer quickly with. For the encrypt_file('HelloWorld.txt', 'password', 'randomsalt', 64000) decrypt_file('HelloWorld.enc', 'password', 64000, '.txt') Is there a way to set the first '' where you select the file name, to a directory path such as: "G:/Dir/Dir/Dir/HelloWorld.enc" and have it still work? I attempted to substitute the first '' with "G:/Dir/Dir/Dir/HelloWorld.enc", but it does not open that file correctly to display its contents. – Archimedes - Charles Apr 04 '14 at 01:08
  • Dunno, I'm more specialized in crypto. Try something like `'C:\\Python25\\Lib\\idlelib\\path_to_libs'`. G'night :) – Maarten Bodewes Apr 04 '14 at 01:20
  • Thank you Owlstead, I do appreciate the help you provided and I hope you have a good night sleep. :) – Archimedes - Charles Apr 04 '14 at 01:25