【问题标题】:pycrypto - Ciphertext with incorrect lengthpycrypto - 长度不正确的密文
【发布时间】:2015-01-16 19:37:56
【问题描述】:

我已经使用 pycrypto 生成了一个公钥和私钥,并使用导出密钥将它们保存到一个文件中:

from Crypto.PublicKey import RSA
bits=2048
new_key = RSA.generate(bits, e=65537)

prv = open('keymac.pem','w')
prv.write(new_key.exportKey('PEM'))
prv.close()
pub = open('pubmac.pem', 'w')
pub.write(new_key.publickey().exportKey('PEM'))
pub.close()

我使用公钥加密文件(在http://insiderattack.blogspot.com/2014/07/encrypted-file-transfer-utility-in.html#comment-form之后)

当我读取文件进行解密时,我得到“长度不正确的密文”。

我在 Deepal Jayasekara 示例的解密代码周围添加了一个 try-except 块:

try:
    encryptedonetimekey = filetodecrypt.read(512)
    privatekey = open("keymac.pem", 'r').read()
    rsaofprivatekey = RSA.importKey(privatekey)
    pkcs1ofprivatekey = PKCS1_OAEP.new(rsaofprivatekey)
    aesonetimekey = pkcs1ofprivatekey.decrypt(encryptedonetimekey)

   except Exception as decrypprivkeyerr:
       print "Decryption of the one time key using the private key        failed!!"
       print "Key error == %s" %decrypprivkeyerr
     raise Exception("Decryption using Private key failed error = %s" %decrypprivkeyerr)

我错过了什么吗?我应该以不同的方式保存私钥吗?我没有正确读取私钥吗?

【问题讨论】:

  • 如果你以字节的形式读取它,记得用'b'打开它,否则在使用读取的字符串之前尝试修剪。

标签: python pycrypto


【解决方案1】:

这并不能直接回答你的问题,但它可能会给你一些问题的线索。我使用两个函数将内容加密到文件中,而不是直接加密文件。一个用于加密(在我的情况下为用户名和密码)到一个文件,然后另一个用于解密该数据以根据需要使用。

注意填充的需要

在文件中创建加密内容:

from Crypto.Cipher import AES
import base64
import os
import argparse

parser = argparse.ArgumentParser(description='Arguments used to generate new credentials file, Use: -u for username, -p for password')
parser.add_argument('-u', help='Specify username', required=True)
parser.add_argument('-p', help='Specify password', required=True)
parser.add_argument('-b', help='Specify debug', required=False, action='store_true')
args = vars(parser.parse_args())


def encrypt(username, password):
    #Encrypt Credentials To '.creds' file, including 'secret' for username and password
    dir_path = os.path.dirname(os.path.realpath(__file__))
    # the block size for the cipher object; must be 16 per FIPS-197
    BLOCK_SIZE = 16

    # the character used for padding--with a block cipher such as AES, the value
    # you encrypt must be a multiple of BLOCK_SIZE in length.  This character is
    # used to ensure that your value is always a multiple of BLOCK_SIZE
    PADDING = '{'

    # one-liner to sufficiently pad the text to be encrypted
    pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING

    # generate a random secret key
    user_secret = os.urandom(BLOCK_SIZE)
    pass_secret = os.urandom(BLOCK_SIZE)

    # one-liners to encrypt/encode and decrypt/decode a string
    # encrypt with AES, encode with base64

    EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
    # create a cipher object using the random secret
    user_cipher = AES.new(user_secret)
    pass_cipher = AES.new(pass_secret)

    # encode a string
    user_encoded = EncodeAES(user_cipher, username)
    pass_encoded = EncodeAES(pass_cipher, password)
    try:
        with open('.creds', 'w') as filename:
            filename.write(user_encoded + '\n')
            filename.write(user_secret + '\n')
            filename.write(pass_encoded + '\n')
            filename.write(pass_secret + '\n')
            filename.close()
            print '\nFile Written To: ', dir_path + '/.creds'
    except Exception, e:
        print e

    if args['b']:
        print((user_encoded, user_secret), (pass_encoded, pass_secret))

username = args['u']
password = args['p']

encrypt(username, password)

解密数据

def decrypt(dir_path, filename):
    #Read '.creds' file and return unencrypted credentials (user_decoded, pass_decoded)

    lines = [line.rstrip('\n') for line in open(dir_path + filename)]

    user_encoded = lines[0]
    user_secret = lines[1]
    pass_encoded = lines[2]
    pass_secret = lines[3]

    # the character used for padding--with a block cipher such as AES, the value
    # you encrypt must be a multiple of BLOCK_SIZE in length.  This character is
    # used to ensure that your value is always a multiple of BLOCK_SIZE
    PADDING = '{'

    DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)

    # create a cipher object using the random secret
    user_cipher = AES.new(user_secret)
    pass_cipher = AES.new(pass_secret)

    # decode the encoded string
    user_decoded = DecodeAES(user_cipher, user_encoded)
    pass_decoded = DecodeAES(pass_cipher, pass_encoded)

    return (user_decoded, pass_decoded)

【讨论】:

    【解决方案2】:

    错误消息“长度不正确的密文”已经告诉了我们所有人。这意味着, 密文超过了可以通过(密钥长度, 1024.2048..)/8。为了解决这个问题,可以分离密文并解密 它们在一个循环中,然后组装所有解密的字节字符串。我在 Python 3.6 中的代码供参考:

    # 1024/8
    default_length = 128
    encrypt_str = str(data["content"])
    sign_str = str(data["sign"])
    try:
        rsa_private_key = RSA.importKey(private_key)
        encrypt_byte = base64.b64decode(encrypt_str.encode())
        length = len(encrypt_byte)
        cipher = PKCS115_Cipher(rsa_private_key)
        if length < default_length:
            decrypt_byte = cipher.decrypt(encrypt_byte, 'failure')
        else:
            offset = 0
            res = []
            while length - offset > 0:
                if length - offset > default_length:
                    res.append(cipher.decrypt(encrypt_byte[offset: offset + 
                        default_length], 'failure'))
                else:
                    res.append(cipher.decrypt(encrypt_byte[offset:], 'failure'))
                offset += default_length
            decrypt_byte = b''.join(res)
        decrypted = decrypt_byte.decode()
    

    【讨论】:

    • 为什么要把密文分成(密钥长度/8)的块?为什么特别是 8?
    猜你喜欢
    • 1970-01-01
    • 2018-04-25
    • 1970-01-01
    • 2021-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-11
    • 1970-01-01
    相关资源
    最近更新 更多