#ios #encryption #aes
#iOS #шифрование #aes
Вопрос:
У меня есть файл, который был зашифрован на Android с помощью этого кода:
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AESUtils {
private static final String IV_STRING = "123456789876543";
private String key = "mysecretkey12345";
public static byte[] encryptData(String key, byte[] byteContent) {
byte[] encryptedBytes = null;
try {
byte[] enCodeFormat = key.getBytes();
SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
byte[] initParam = IV_STRING.getBytes();
IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
encryptedBytes = cipher.doFinal(byteContent);
} catch (Exception e) {
e.printStackTrace();
}
return encryptedBytes;
}
public static byte[] decryptData(String key, byte[] encryptedBytes) {
byte[] result = null ;
try {
byte[] sEnCodeFormat = key.getBytes();
SecretKeySpec secretKey = new SecretKeySpec(sEnCodeFormat, "AES");
byte[] initParam = IV_STRING.getBytes();
IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
result = cipher.doFinal(encryptedBytes);
} catch (Exception e) {
e.printStackTrace();
}
return resu<
}
}
Я попытался перепроектировать дешифрование в Swift, используя CommonCrypto следующим образом:
import CommonCrypto
let keyStr:String = "mysecretkey12345"
let ivStr:String = "123456789876543"
func aesDecrypt(data:NSData) -> Data? {
let k:NSData = keyStr.data(using: .utf8)! as NSData
let dbytes = data.bytes
let kbytes=k.bytes
if let keyData = keyStr.data(using: .utf8),
let cryptData = NSMutableData(length: Int((data.length)) kCCBlockSizeAES128) {
let keyLength = size_t(kCCKeySizeAES128)
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionPKCS7Padding)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
kbytes, keyLength,
ivStr,
dbytes, data.length,
cryptData.mutableBytes, cryptData.length,
amp;numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.length = Int(numBytesEncrypted)
return (cryptData.copy() as! Data)
}
else {
return nil
}
}
return nil
}
Я новичок в шифровании, но из своих исследований я обнаружил, что CC использует CBC по умолчанию, а PKCS7Padding в основном идентичен PKCS5Padding. Однако дешифрование не дает ожидаемых результатов!
Код swift был скопирован из разных источников, включая множество решений, предложенных здесь, в stackoverflow. Основная проблема заключается в том, что в большинстве примеров в качестве данных используются key и iv, тогда как у меня есть строки — не уверен, что мое преобразование вызывает проблемы. Во-вторых, многие просто преобразуют строковые сообщения, тогда как я конвертирую данные (из файлов) напрямую — это не должно слишком сильно влиять на это, на самом деле упрощает код, избегая преобразования данных-> строки.
Но поскольку это не работает, что я пропустил?
Ответ №1:
Хорошо, я думаю, я понял проблему. Очевидно, что существует проблема с NSData.bytes, и нужно работать с unsafebytes. Кроме того, моя проблема может заключаться в том, что IV не был частью данных, как предполагалось во многих примерах, поэтому я пропустил 16 байт при расшифровке. Следующий код работает для меня, надеюсь, он кому-нибудь поможет!
func decrypt(data: Data) -> Data {
let key: Data = keyStr.data(using: .utf8) ?? Data()
let iv: Data = ivStr.data(using: .utf8) ?? Data()
if(keyStr.count == kCCKeySizeAES128){print("Key OKAY")} else {print("Key NOT okay")}
if(ivStr.count == kCCBlockSizeAES128){print("IV OKAY")} else {print("IV NOT okay")}
var buffer = Data(count: data.count)
var numberBytesDecrypted: Int = 0
let cryptStatus: CCCryptorStatus = key.withUnsafeBytes {keyBytes in
data.withUnsafeBytes {dataBytes in
buffer.withUnsafeMutableBytes {bufferBytes in iv.withUnsafeBytes {ivBytes in
CCCrypt( // Stateless, one-shot encrypt operation
CCOperation(kCCDecrypt), // op: CCOperation
CCAlgorithm(kCCAlgorithmAES128), // alg: CCAlgorithm
CCOptions(kCCOptionPKCS7Padding), // options: CCOptions
keyBytes.baseAddress, // key: the "password"
key.count, // keyLength: the "password" size
ivBytes.baseAddress, // iv: Initialization Vector
dataBytes.baseAddress!, // dataIn: Data to decrypt bytes
data.count, // dataInLength: Data to decrypt size
bufferBytes.baseAddress, // dataOut: decrypted Data buffer
data.count, // dataOutAvailable: decrypted Data buffer size
amp;numberBytesDecrypted // dataOutMoved: the number of bytes written
)}
}
}
}
if(cryptStatus == CCCryptorStatus(kCCSuccess)){
return buffer[..<numberBytesDecrypted]
} else {
print("Decryption failed")
return data
}
}
Ответ №2:
Хорошо, оказалось, что один из моих тестовых файлов был поврежден, и моя расшифровка работала все время. Вот более простая версия без withUnsafeBytes:
func decrypt(data: Data) -> Data {
let key:Data = keyStr.data(using: .utf8)!
let iv:Data = ivStr.data(using: .utf8)!
var buffer = [UInt8](repeating: 0, count: data.count kCCBlockSizeAES128)
var bufferLen: Int = 0
let status = CCCrypt(
CCOperation(kCCDecrypt),
CCAlgorithm(kCCAlgorithmAES128),
CCOptions(kCCOptionPKCS7Padding),
[UInt8](key),
kCCBlockSizeAES128,
[UInt8](iv),
[UInt8](data),
data.count,
amp;buffer,
buffer.count,
amp;bufferLen
)
if(status == kCCSuccess) {
return Data(bytes: buffer, count: bufferLen)}
else {
print("Decryption failed")
return data
}
}