【问题标题】:Decrypt with AES (MODE_CBC/NoPadding) a file in iOS encrypted in Python使用 AES (MODE_CBC/NoPadding) 解密 iOS 中用 Python 加密的文件
【发布时间】:2015-05-07 10:08:10
【问题描述】:

我从 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)

我在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();

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

编辑 1

对不起。这是我在目标 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();

编辑 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)

【问题讨论】:

  • 如果你的问题是关于你的 Objective-C 代码的,你应该发布它,以便我们可以看到它有什么问题。

标签: android python ios encryption aes


【解决方案1】:

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

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

CBC 模式的 iv 被添加到加密数据之前,这是一个很好的方案。您需要将 iv 从加密数据中分离出来,并将其应用于解密函数调用。

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

通过以上内容,您可以使用 Apple 提供的 Common Crypto,特别是 CCCrypt 函数。

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

【讨论】:

  • 谢谢。那么,您能否建议我一些示例来使用 AES 中的 CCCRypt 加密和解密文件?
  • 当然。您需要流媒体功能吗?
  • 不一定。加密文件存储在设备上
  • SO Answer。但是你会有一些工作。删除kCCOptionPKCS7Padding 选项。找出密钥大小并根据需要设置算法:kCCKeySizeAES* 其中* 是 128、192 或 254。在答案中处理 iv 并去除任何填充。 CCCrypt 将填充空白,但我不会依赖它,如有必要,请自行填充键。
  • 有效。谢谢。在答案的编辑中,我输入了我修改过的 python 代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-30
  • 2019-11-01
  • 1970-01-01
  • 2013-09-21
  • 2021-03-05
  • 2019-05-30
相关资源
最近更新 更多