跳过elif语句? [英] Skipping elif statement?

查看:107
本文介绍了跳过elif语句?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用pycryptodome创建简单的加密/解密,但不断出现以下错误:

Am trying to create a simple encryption/decryption using pycryptodome but keeping getting the following error:

ValueError: Error 3 while encrypting in CBC mode

经过一些挖掘,我发现如果没有足够的数据可以得到此错误加密,因为实际上没有填充。问题是我添加了填充功能。调试后,似乎我的代码从字面上完全跳过了填充部分并导致了此错误。我在做什么错?

after some digging I saw that you get this error if there is not enough data to encrypt, as in there is no padding in effect. The thing is that I've added a padding function. After debugging it seems as if my code literally skips the padding part completely and causes this error. What am I doing wrong?

import os, random
from Crypto.Cipher import AES
from Crypto.Hash import SHA256

def encrypt(key, filename):
    chunksize = 64*1024
    outputfile = filename + "(encrypted)"
    filesize = str(os.path.getsize(filename)).zfill(16)

    IV =''
    for i in range(16):
        IV += chr(random.randint(0, 0xFF))

    encryptor = AES.new(key, AES.MODE_CBC, IV.encode("latin-1"))

    with open(filename, 'rb') as infile:
        with open(outputfile, 'wb') as outfile:
            outfile.write(filesize.encode("latin-1"))
            outfile.write(IV.encode("latin-1"))

            while True:
                chunk = infile.read(chunksize)
                print(len(chunk))
                if len(chunk) == 0:
                    break
                elif len(chunk) % 16 != 0:
                    chunk += ' ' * (16 - (len(chunk) % 16))

                outfile.write(encryptor.encrypt(chunk))

def decrypt(key, filename):
    chunksize = 64 *1024
    outputfile = filename[:11]
    with open(filename, 'rb') as infile:
        filesize = int(infile.read(16))
        IV = infile.read(16)
        decryptor = AES.new(key, AES.MODE_CBC, IV.encode("latin-1"))
        with open(outputfile, 'wb') as outfile:
            while True:
                chunk = infile.read(chunksize)
                if len(chunk) == 0:
                    break
                outfile.write(decryptor.decrypt(chunk))
            outfile.truncate(filesize)

def getkey (password):
    hasher = SHA256.new(password.encode("latin-1"))
    return hasher.digest()

def main():
    choice = input ("do you want to [E]ncrypt of [D]ecrypt?")
    if choice == 'E':
        filename = input("File to encrypt >")
        password = input("Password >")
        encrypt(getkey(password), filename)
        print("Encryption done!")
    elif choice == 'D':
        filename = input("File to Decrypt >")
        password = input("Password >")
        decrypt(getkey(password), filename)
        print("Decryption done!")
    else:
        print("No option selected")

if __name__ == '__main__':
    main()

*我正在使用python 3.6

*I am using python 3.6

编辑:
此处是我运行代码时完整的控制台输出:

Here are the full console output when I run the code:

   C:\Users\itayg\AppData\Local\Programs\Python\Python36\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2017.1.2\helpers\pydev\pydevd.py" --multiproc --qt-support --client 127.0.0.1 --port 21111 --file C:/Users/itayg/PycharmProjects/PyCrypto/encrypt.py
Connected to pydev debugger (build 171.4249.47)
pydev debugger: process 12876 is connecting

do you want to [E]ncrypt of [D]ecrypt?E
File to encrypt >grades.jpg
Password >123
65536
49373
Traceback (most recent call last):
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2017.1.2\helpers\pydev\pydevd.py", line 1585, in <module>
    globals = debugger.run(setup['file'], None, None, is_module)
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2017.1.2\helpers\pydev\pydevd.py", line 1015, in run
    pydev_imports.execfile(file, globals, locals)  # execute the script
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2017.1.2\helpers\pydev\_pydev_imps\_pydev_execfile.py", line 18, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "C:/Users/itayg/PycharmProjects/PyCrypto/encrypt.py", line 66, in <module>
    main()
  File "C:/Users/itayg/PycharmProjects/PyCrypto/encrypt.py", line 55, in main
    encrypt(getkey(password), filename)
  File "C:/Users/itayg/PycharmProjects/PyCrypto/encrypt.py", line 29, in encrypt
    outfile.write(encryptor.encrypt(chunk))
  File "C:\Users\itayg\AppData\Local\Programs\Python\Python36\lib\site-packages\pycryptodome-3.4.6-py3.6-win-amd64.egg\Crypto\Cipher\_mode_cbc.py", line 167, in encrypt
    raise ValueError("Error %d while encrypting in CBC mode" % result)
ValueError: Error 3 while encrypting in CBC mode


推荐答案

好,让我们解决一些代码错误的问题。首先最明显的一个-您的填充将在Python 3.5+上中断(并且用户的菜单将在2.x上中断),因为 infile.read()会给您 bytes 数组,因此尝试添加由 chunk + =''*(16-(len(chunk)%16))会导致错误。首先需要将空白填充转换为 bytes 数组: chunk + = b''*(16-(len(chunk)%16) )

Ok, let's fix a few things that are wrong with your code. First the most obvious one - your padding would break on Python 3.5+ (and your user 'menu' would break on 2.x) because infile.read() would give you bytes array so trying to add a string formed by chunk += ' ' * (16 - (len(chunk) % 16)) would result in an error. You would need to convert your whitespace pad to bytes array first: chunk += b' ' * (16 - (len(chunk) % 16))

但是这样的空格填充是个坏主意-当您以后解密文件时,如何知道多少(如果有) ,您添加的填充?您需要将其存储在某个位置,然后通过 filesize 值在标头中进行操作,告诉潜在的攻击者您的文件有多大,以及添加了多少空白您可能会遭受oracle填充攻击(下面的代码有可能,因此在不添加适当的MAC的情况下不要使用它来传递消息)。

But whitespace padding like this is a bad idea - when you're later decrypting your file how will you know how much, if any, padding you've added? You need to store this somewhere - and you do in the 'header' via the filesize value, telling a potential attacker how exactly big is your file and how much padding was added opening you to a padding oracle attack (which is possible with the bellow code so do not use it for passing messages without adding a proper MAC to it).

您可以使用的强大填充方案-我个人更喜欢 PKCS#7 只需填充不均匀的块或添加 n 个字节值为 n 的全新块-这样,解密后,您可以从块中选择最后一个字节,并确切知道要填充多少个字节,以便剥离它们。因此,将您的加密部分替换为:

There are plenty of robust padding schemes that you can use - I personally prefer PKCS#7 which is simply padding your uneven block or adding a whole new block with n number of bytes with the value of n - that way, after decryption, you can pick the last byte from your block and know exactly how many bytes were padded so you can strip them. So, replace your encryption portion with:

def encrypt(key, filename):
    outputfile = filename + "(encrypted)"
    chunksize = 1024 * AES.block_size  # use the cipher's defined block size as a multiplier
    IV = bytes([random.randint(0, 0xFF) for _ in range(AES.block_size)])  # bytes immediately
    encryptor = AES.new(key, AES.MODE_CBC, IV)
    with open(filename, 'rb') as infile:
        with open(outputfile, 'wb') as outfile:
            outfile.write(IV)  # write the IV
            padded = False
            while not padded:  # loop until the last block is padded
                chunk = infile.read(chunksize)
                chunk_len = len(chunk)
                # if no more data or the data is shorter than the required block size
                if chunk_len == 0 or chunk_len % AES.block_size != 0:
                    padding = AES.block_size - (chunk_len % AES.block_size)
                    chunk += bytes([padding]) * padding
                    # on Python 2.x replace with: chunk += chr(padding_len) * padding_len
                    padded = True
                outfile.write(encryptor.encrypt(chunk))

我还更改了 chunksize 以匹配您正在使用的块大小( AES.block_size 的倍数)-碰巧64是16的倍数,但是您应该注意那些东西。

I've also changed your chunksize to match the block size you're using (multiples of AES.block_size) - it just happens that 64 is a multiple of 16 but you should pay attention to those things.

现在我们已经对加密进行了整理,解密就是所有这些,但要反向执行-解密所有块,读取最后一个块的最后一个字节并删除 n 个字节,从后面匹配最后一个字节的值:

Now that we have the encryption sorted out, the decryption is all this but in reversal - decrypt all blocks, read the last byte of the last block and remove n amount of bytes from behind matching the value of the last byte:

def decrypt(key, filename):
    outputfile = filename[:-11] + "(decrypted)"
    chunksize = 1024 * AES.block_size  # use the cipher's defined block size as a multiplier
    with open(filename, 'rb') as infile:
        IV = infile.read(AES.block_size)
        decryptor = AES.new(key, AES.MODE_CBC, IV)
        with open(outputfile, 'wb') as outfile:
            old_chunk = b''  # stores last chunk, needed for reading data with a delay
            stripped = False
            while not stripped:  # delayed loop until the last block is stripped
                chunk = decryptor.decrypt(infile.read(chunksize))  # decrypt as we read
                if len(chunk) == 0:  # no more data
                    padding = old_chunk[-1]  # pick the padding value from the last byte
                    if old_chunk[-padding:] != bytes([padding]) * padding:
                        raise ValueError("Invalid padding...")
                    old_chunk = old_chunk[:-padding]  # strip the padding
                    stripped = True
                outfile.write(old_chunk)  # write down the 'last' chunk
                old_chunk = chunk  # set the new chunk for checking in the next loop

这篇关于跳过elif语句?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆