使用 AES (MODE_CBC/NoPadding) 解密 iOS 中加密的文件 Python
Decrypt with AES (MODE_CBC/NoPadding) a file in iOS encrypted in Python
我从 Python 的服务器收到一个以这种方式加密的文件:
import os
from Crypto.Cipher import AES
from Crypto import Random
def pad(s):
return s + b"[=13=]" * (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 的应用程序中做同样的事情,但我是 objective C 的新手。
我无法更改服务器上的代码。
我尝试将 RNCrypto 用于 iOS,但结果很差。
有什么建议么?
谢谢
编辑 1
对不起。这是我在 objective 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
Python 带有 PKCS7 和 0 字节 iv 的代码。
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"[=16=]" * (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)
在这种情况下,RNCryptor 不是一个好的选择,因为它强加了一种与用于加密的方法不匹配的加密格式和方法。
你声明没有填充,但 Python 代码确实用零字节填充了消息,这既不标准,也不安全,并且假设被加密的数据不以空字节结尾.您将不得不在解密后处理剥离空填充。通常的填充是 PKCS#7.
CBC 模式的 iv 被添加到加密数据之前,这是一个很好的方案。您需要将 iv 从加密数据中分离出来,并将其应用于解密函数调用。
不清楚加密密钥的长度是否完全正确或使用的 AES 密钥大小是多少。据推测,Python 方法使用密钥长度来确定 AES 密钥大小,它可以是 128、192 或 256 位,如果不是其中之一,则将密钥填充到长度。您将需要确定这一点并在您的代码中处理它。确实应该指定 AES 密钥大小,并且密钥应该恰好匹配长度。
通过以上内容,您可以使用 Apple 提供的 Common Crypto,特别是 CCCrypt
函数。
有可能修改接收到的数据以匹配 RNCryptor 的要求并在解密后处理填充。
我从 Python 的服务器收到一个以这种方式加密的文件:
import os
from Crypto.Cipher import AES
from Crypto import Random
def pad(s):
return s + b"[=13=]" * (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 的应用程序中做同样的事情,但我是 objective C 的新手。 我无法更改服务器上的代码。 我尝试将 RNCrypto 用于 iOS,但结果很差。 有什么建议么? 谢谢
编辑 1
对不起。这是我在 objective 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 Python 带有 PKCS7 和 0 字节 iv 的代码。
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"[=16=]" * (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)
在这种情况下,RNCryptor 不是一个好的选择,因为它强加了一种与用于加密的方法不匹配的加密格式和方法。
你声明没有填充,但 Python 代码确实用零字节填充了消息,这既不标准,也不安全,并且假设被加密的数据不以空字节结尾.您将不得不在解密后处理剥离空填充。通常的填充是 PKCS#7.
CBC 模式的 iv 被添加到加密数据之前,这是一个很好的方案。您需要将 iv 从加密数据中分离出来,并将其应用于解密函数调用。
不清楚加密密钥的长度是否完全正确或使用的 AES 密钥大小是多少。据推测,Python 方法使用密钥长度来确定 AES 密钥大小,它可以是 128、192 或 256 位,如果不是其中之一,则将密钥填充到长度。您将需要确定这一点并在您的代码中处理它。确实应该指定 AES 密钥大小,并且密钥应该恰好匹配长度。
通过以上内容,您可以使用 Apple 提供的 Common Crypto,特别是 CCCrypt
函数。
有可能修改接收到的数据以匹配 RNCryptor 的要求并在解密后处理填充。