用AES(MODE_CBC / NoPadding)解密用Python加密的iOS文件

时间:2022-08-02 18:28:37

I receive from a Server in Python a file encrypted in this manner:

我从Python中的服务器接收以这种方式加密的文件:

import os
from Crypto.Cipher import AES
from Crypto import Random


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


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


def encrypt_file(file_name, key):
    with open("epub/" + file_name, 'rb') as fo:
        plaintext = fo.read()
    enc = encrypt(plaintext, key)
    file_name = "enc/" + file_name
    with open(file_name, 'wb') as fo:
        fo.write(enc)


for list in os.listdir('./epub'):
    if list.find('.epub') != -1:
        key = '0123456789012345'
        encrypt_file(list, key)

My App in Android decrypt file in this manner:

Android中的我的应用程序以这种方式解密文件:

FileInputStream epubCifr = new FileInputStream(Environment.getExternalStorageDirectory() + "/Skin/readium/epub_content/" + title + "/" + title + ".epub");
FileOutputStream epubDec = new FileOutputStream(Environment.getExternalStorageDirectory() + "/Skin/readium/epub_content/" + title + "/" + title + "_dec.epub");

SecretKeySpec sks = new SecretKeySpec(key, "AES");

Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, sks);
CipherInputStream cis = new CipherInputStream(epubCifr, cipher);
int b;
byte[] d = new byte[16];
while ((b = cis.read(d)) != -1)
    epubDec.write(d, 0, b);

epubDec.flush();
epubDec.close();
cis.close();

Now. I would do the same thing in an app for iOS but I'm a newbie in objective C. I can't change code on Server. I tried to use RNCrypto for iOS but with poor results. Any suggestions? Thanks

现在。我会在iOS的应用程序中做同样的事情,但我是目标C的新手。我无法在服务器上更改代码。我尝试在iOS上使用RNCrypto但效果不佳。有什么建议?谢谢

EDIT 1

Sorry. This is my code in objective C. I think that there are some settings in RNCryptor that are wrong.

抱歉。这是我在目标C中的代码。我认为RNCryptor中有一些设置是错误的。

int blockSize = 16;

NSInputStream *cryptedStream = [NSInputStream inputStreamWithFileAtPath:@"epub.epub"];
NSOutputStream *decryptedStream = [NSOutputStream outputStreamToFileAtPath:@"epub_dec.epub" append:NO];

[cryptedStream open];
[decryptedStream open];

__block NSMutableData *data = [NSMutableData dataWithLength:blockSize];
__block RNEncryptor *decryptor = nil;

dispatch_block_t readStreamBlock = ^{
    [data setLength:blockSize];
    NSInteger bytesRead = [cryptedStream read:[data mutableBytes] maxLength:blockSize];
    if (bytesRead < 0) {
    }
    else if (bytesRead == 0) {
        [decryptor finish];
    }
    else {
        [data setLength:bytesRead];
        [decryptor addData:data];
        NSLog(@"Sent %ld bytes to decryptor", (unsigned long)bytesRead);
    }
};

decryptor = [[RNEncryptor alloc] initWithSettings:kRNCryptorAES256Settings
password:@"0123456789012345"
handler:^(RNCryptor *cryptor, NSData *data) {
    NSLog(@"Decryptor recevied %ld bytes", (unsigned long)data.length);
    [decryptedStream write:data.bytes maxLength:data.length];
    if (cryptor.isFinished) {
        [decryptedStream close];
    }
    else {
        readStreamBlock();
    }
}];

readStreamBlock();

EDIT 2 Python code with PKCS7 and iv of 0 bytes.

编辑2使用PKCS7和iv为0字节的Python代码。

from Crypto.Cipher import AES
from Crypto import Random
from pkcs7 import PKCS7Encoder


def pad(s):
    encoder = PKCS7Encoder()
    return encoder.encode(s)
    #return s + b"\0" * (AES.block_size - len(s) % AES.block_size)


def encrypt(message, key):
    message = pad(message)
    #iv = Random.new().read(AES.block_size)
    iv = b'0000000000000000'
    cipher = AES.new(key, AES.MODE_CBC, iv)
    return iv + cipher.encrypt(message)


def encrypt_file(file_name, key):
    with open("epub/" + file_name, 'rb') as fo:
        plaintext = fo.read()
    enc = encrypt(plaintext, key)
    file_name = "enc/" + file_name
    with open(file_name, 'wb') as fo:
        fo.write(enc)

key = '0123456789012345'
encrypt_file("epub1.epub", key)
decrypt_file("epub1.epub", key)

1 个解决方案

#1


RNCryptor in this case is not a good choice because it imposes a format and method for encryption that does not match the method being used to encrypt.

在这种情况下,RNCryptor不是一个好的选择,因为它强加的加密格式和方法与用于加密的方法不匹配。

You state that there is no padding but the Python code does pad the message with zero bytes, this is both non-standard, insecure and assumes that the data being encrypted does not end with a null byte. You will have to handle stripping the null padding after decryption. The usual padding is PKCS#7.

您声明没有填充,但Python代码确实用零字节填充消息,这是非标准的,不安全的并且假设被加密的数据不以空字节结束。解密后,您必须处理剥离空填充。通常的填充是PKCS#7。

The iv for CBC mode is prepended to the encrypted data, this is a good scheme. You will need to separate the iv from the encryption data and apply it to the decryption function call.

用于CBC模式的iv预先加密数据,这是一个很好的方案。您需要将iv与加密数据分开,并将其应用于解密函数调用。

It is not clear that the encryption key is exactly the correct length or what AES key size is being used. Presumably the Python method is using the length of the key to determine the AES key size, it can be 128, 192 or 256 bits and if not one of these padding the key to length. You will need to determine this and handle it in your code. The AES key size should really be specified and the key should be exactly the matching length.

目前尚不清楚加密密钥是否与正确的长度或正在使用的AES密钥大小完全相同。据推测,Python方法是使用密钥的长度来确定AES密钥大小,它可以是128,192或256位,如果不是其中一个填充长度的关键。您需要确定这一点并在代码中处理它。应该确实指定AES密钥大小,密钥应该完全匹配长度。

With the above you can use the Apple supplied Common Crypto, specifically CCCrypt function.

有了上述内容,您可以使用Apple提供的Common Crypto,特别是CCCrypt功能。

It is potentially possible to modify the received data to match the requirements of RNCryptor and handle the padding after the decryption.

有可能修改接收的数据以匹配RNCryptor的要求并在解密后处理填充。

#1


RNCryptor in this case is not a good choice because it imposes a format and method for encryption that does not match the method being used to encrypt.

在这种情况下,RNCryptor不是一个好的选择,因为它强加的加密格式和方法与用于加密的方法不匹配。

You state that there is no padding but the Python code does pad the message with zero bytes, this is both non-standard, insecure and assumes that the data being encrypted does not end with a null byte. You will have to handle stripping the null padding after decryption. The usual padding is PKCS#7.

您声明没有填充,但Python代码确实用零字节填充消息,这是非标准的,不安全的并且假设被加密的数据不以空字节结束。解密后,您必须处理剥离空填充。通常的填充是PKCS#7。

The iv for CBC mode is prepended to the encrypted data, this is a good scheme. You will need to separate the iv from the encryption data and apply it to the decryption function call.

用于CBC模式的iv预先加密数据,这是一个很好的方案。您需要将iv与加密数据分开,并将其应用于解密函数调用。

It is not clear that the encryption key is exactly the correct length or what AES key size is being used. Presumably the Python method is using the length of the key to determine the AES key size, it can be 128, 192 or 256 bits and if not one of these padding the key to length. You will need to determine this and handle it in your code. The AES key size should really be specified and the key should be exactly the matching length.

目前尚不清楚加密密钥是否与正确的长度或正在使用的AES密钥大小完全相同。据推测,Python方法是使用密钥的长度来确定AES密钥大小,它可以是128,192或256位,如果不是其中一个填充长度的关键。您需要确定这一点并在代码中处理它。应该确实指定AES密钥大小,密钥应该完全匹配长度。

With the above you can use the Apple supplied Common Crypto, specifically CCCrypt function.

有了上述内容,您可以使用Apple提供的Common Crypto,特别是CCCrypt功能。

It is potentially possible to modify the received data to match the requirements of RNCryptor and handle the padding after the decryption.

有可能修改接收的数据以匹配RNCryptor的要求并在解密后处理填充。