簡體   English   中英

在 iOS 中解密 AES/CBC/PKCS5Padding

[英]Decrypting AES/CBC/PKCS5Padding in iOS

我有一個使用以下代碼在 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 result;
    }
}

我嘗試使用 CommonCrypto 對 Swift 中的解密進行逆向工程,如下所示:

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,
                    &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 作為數據,而我有字符串 - 不確定我的轉換會導致問題。 其次,許多只是簡單地轉換字符串消息,而我直接轉換數據(從文件) - 不應該影響它太多,實際上使代碼更簡單,避免數據->字符串轉換。 但既然它不起作用,我錯過了什么?

好吧,我想我找到了問題所在。 顯然,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
                    &numberBytesDecrypted                           // dataOutMoved: the number of bytes written
                )}
            }
        }
    }
    
    if(cryptStatus == CCCryptorStatus(kCCSuccess)){
        return buffer[..<numberBytesDecrypted]
    } else {
        print("Decryption failed")
        return data
    }
}

好吧,原來我的一個測試文件已損壞,我的解密一直有效。 這是一個沒有 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,
        &buffer,
        buffer.count,
        &bufferLen
    )

    if(status == kCCSuccess) {
        return Data(bytes: buffer, count: bufferLen)}
    else {
        print("Decryption failed")
        return data
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM