iosswiftencryptioncommoncrypto

Cannot convert value of type 'UnsafeRawBufferPointer' to expected argument type 'UnsafeMutableRawPointer?'


I was followed this answer to encrypt the data. The encryption is success. But I am stuck with the decrypting the data. I've lot of datas are encrypted. But I used another answers for decryption and decrypted data is not as original. I tried to decrypt the data form the same answer but it is success but the decrypted data is just empty. So, I tried to update the deprication of decryption code but I can't resolve this error when converting clearData to bytes in the line let cryptStatus = clearData.withUnsafeBytes { (cryptBytes)

Cannot convert value of type 'UnsafeRawBufferPointer' to expected argument type 'UnsafeMutableRawPointer?'

Can you please help me to resolve the error? Thank you.

import Accelerate
import CommonCrypto

Encryption:

func encrypt() {
    
    let data = "Hello,World".data(using: .utf8)!
    let keyData = "SOME_SECRET_CODE".data(using: .utf8)!

    if let cryptData    = NSMutableData(length: Int((data.count)) + kCCBlockSizeAES128) {
        
        let keyLength              = size_t(kCCKeySizeAES128)
        let operation: CCOperation = UInt32(kCCEncrypt)
        let algoritm:  CCAlgorithm = UInt32(kCCAlgorithmAES128)
        let options:   CCOptions   = UInt32(kCCOptionPKCS7Padding)
        
        var numBytesEncrypted :size_t = 0

        let cryptStatus = CCCrypt(operation,
                                  algoritm,
                                  options,
                                  (keyData as NSData).bytes, keyLength,
                                  "",
                                  (data as NSData).bytes, data.count,
                                  cryptData.mutableBytes, cryptData.length,
                                  &numBytesEncrypted)
        
        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
              
            print("Encryption Success...")
            cryptData.length = Int(numBytesEncrypted)
             
            self.decrypt(data: cryptData as Data, keyData: keyData)
            
        }else {
        
            print("Encryption isn't success!")
        }
    }else{
        
        print("Can't encrypt")
    }
     
}

Decryption:

 func decrypt(data:Data, keyData:Data){
    let keyLength = keyData.count
    let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
    if (validKeyLengths.contains(keyLength) == false) {
       
        fatalError("Invalid key length")
    }

    let ivSize = kCCBlockSizeAES128;
    let clearLength = size_t(data.count - ivSize)
    var clearData = Data(count:clearLength)

    var numBytesDecrypted :size_t = 0
    let options   = CCOptions(kCCOptionPKCS7Padding)

    let cryptStatus = clearData.withUnsafeBytes { (cryptBytes) -> CCCryptorStatus in
        
        data.withUnsafeBytes { (dataBytes) -> CCCryptorStatus in
            
            keyData.withUnsafeBytes { (keyBytes) -> CCCryptorStatus in
                
                return CCCrypt(CCOperation(kCCDecrypt),
                        CCAlgorithm(kCCAlgorithmAES128),
                        options,
                        keyBytes, keyLength,
                        dataBytes,
                        dataBytes+kCCBlockSizeAES128, clearLength,
                        cryptBytes, clearLength, // Error here
                        &numBytesDecrypted)
            }
        }
    }
    /*
    let cryptStatus = clearData.withUnsafeMutableBytes {cryptBytes in
        data.withUnsafeBytes {dataBytes in
            keyData.withUnsafeBytes {keyBytes in
                CCCrypt(CCOperation(kCCDecrypt),
                        CCAlgorithm(kCCAlgorithmAES128),
                        options,
                        keyBytes, keyLength,
                        dataBytes,
                        dataBytes+kCCBlockSizeAES128, clearLength,
                        cryptBytes, clearLength,
                        &numBytesDecrypted)
            }
        }
    }
    */
    clearData.count = numBytesDecrypted

    if UInt32(cryptStatus) == UInt32(kCCSuccess) {
        clearData.count = numBytesDecrypted
        
        if let string = String(data: clearData, encoding: .utf8){
            print("Decrypted: \(string)")
        }else{
            
            print("Decryption failed! \(clearData.count)")
        }
    }
    else {

        fatalError("Decryption failed")
    }
 }

Solution

  • Your code needs a little refactoring and you're good to go.

       let cryptStatus: CCCryptorStatus = clearData.withUnsafeBytes {cryptBytes in
            data.withUnsafeBytes {dataBytes in
                keyData.withUnsafeMutableBytes {keyBytes in
                    return CCCrypt(CCOperation(kCCDecrypt),
                                   CCAlgorithm(kCCAlgorithmAES128),
                                   options,
                                   cryptBytes, keyLength,
                                   dataBytes,
                                   dataBytes+kCCBlockSizeAES128, clearLength,
                                   keyBytes.baseAddress!, clearLength, 
                                   &numBytesDecrypted)
                }
            }
        }
    

    Now there will be a compile time error saying Cannot use mutating member on immutable value: 'keyData' is a 'let' constant

    In order to get rid of this error, just modify the keyData parameter of your decrypt func like below.

    func decrypt(data:Data, keyData: inout Data)
    

    Function Call

    self.decrypt(data: cryptData as Data, keyData: &keyData)
    

    inout Parameters: All parameters passed into a Swift function are constants, so you can’t change them. If you want, you can pass in one or more parameters as inout, which means they can be changed inside your function, and those changes reflect in the original value outside the function.