【问题标题】:Decrypting AES/CBC/PKCS5Padding in iOS在 iOS 中解密 AES/CBC/PKCS5Padding
【发布时间】:2020-11-11 11:13:10
【问题描述】:

我有一个在 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 作为数据,而我有字符串 - 不确定我的转换会导致问题。其次,许多只是简单地转换字符串消息,而我直接转换数据(来自文件) - 不应该对其产生太大影响,实际上使代码更简单,避免了数据->字符串转换。 但既然它不起作用,我错过了什么?

【问题讨论】:

    标签: ios encryption aes


    【解决方案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
                        &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,
              &buffer,
              buffer.count,
              &bufferLen
          )
      
          if(status == kCCSuccess) {
              return Data(bytes: buffer, count: bufferLen)}
          else {
              print("Decryption failed")
              return data
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-13
        • 1970-01-01
        • 2021-01-05
        相关资源
        最近更新 更多