AES256 encryption in swift string not matching
Asked Answered
C

0

4

In Java/Android we have used

private const val secretKey = "1f23456d2d014be5"
private const val salt = "a986e0093328765e"
private const val ivKey = "9898989890KJHYTR"

fun passwordEncryptMethod(stringToEncrypt: String): String? {
    var encryptedText = ""
    try {
        
        val iv: ByteArray = ivKey.toByteArray()
        val ivspec = IvParameterSpec(iv)

        val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
        val spec: KeySpec = PBEKeySpec(
            secretKey.toCharArray(),
            salt.toByteArray(),
            65536,
            256
        )

        val tmp = factory.generateSecret(spec)
        val secretKey = SecretKeySpec(tmp.encoded, "AES")
        val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec)

        val encryptedByte: ByteArray =
            cipher.doFinal(stringToEncrypt.toByteArray(charset("UTF-8")))
        encryptedText = Base64.encodeToString(encryptedByte, Base64.NO_WRAP)

        return encryptedText

    } catch (e: Exception) {
        Log.i("Error encrypting:", e.message ?: "")
    }
    return encryptedText
}

In iOS Swift I have used . https://gist.github.com/hfossli/7165dc023a10046e2322b0ce74c596f8

Approach 1 using CCKeyDerivationPBKDF & CCCrypt

 let digest = "StringToEncrypt".data(using: .utf8)!
        let password = "1f23456d2d014be5".data(using: .utf8)!
        let salt = "a986e0093328765e".data(using: String.Encoding.utf8)!//AES256.randomSalt()
        let iv = "9898989890KJHYTR".data(using: String.Encoding.utf8)!//AES256.randomIv()
        let key = try AES256.createKey(password: digest, salt: salt)
        var aes = try AES256(key: key, iv: iv)
        let encrypted = try aes.encrypt(password)
        print( #function, (encrypted.base64EncodedString()))

//Helper function

 static func createKey(password: Data, salt: Data) throws -> Data {
        let length = kCCKeySizeAES256
        var status = Int32(0)
        var derivedBytes = [UInt8](repeating: 0, count: length)
        password.withUnsafeBytes { (passwordBytes: UnsafePointer<Int8>!) in
            salt.withUnsafeBytes { (saltBytes: UnsafePointer<UInt8>!) in
                status = CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2),                  // algorithm
                                              passwordBytes,                                // password
                                              password.count,                               // passwordLen
                                              saltBytes,                                    // salt
                                              salt.count,                                   // saltLen
                                              CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256),   // prf
                                              65536,                                        // rounds
                                              &derivedBytes,                                // derivedKey
                                              length)                                       // derivedKeyLen
            }
        }
        guard status == 0 else {
            throw Error.keyGeneration(status: Int(status))
        }
        return Data(bytes: UnsafePointer<UInt8>(derivedBytes), count: length)
    }
mutating func encrypt(_ digest: Data) throws -> Data {
    return try crypt(input: digest, operation: CCOperation(kCCEncrypt))
}

mutating func decrypt(_ encrypted: Data) throws -> Data {
    return try crypt(input: encrypted, operation: CCOperation(kCCDecrypt))
}

private mutating func crypt(input: Data, operation: CCOperation) throws -> Data {
    var outLength = Int(0)
    var outBytes = [UInt8](repeating: 0, count: input.count + kCCBlockSizeAES128)
   // var status: CCCryptorStatus = CCCryptorStatus(kCCSuccess)
    
    
    
    var keyValue = self.key
    
    let status: CCCryptorStatus =
        input.withUnsafeBytes {encryptedBytes in
        iv.withUnsafeBytes {ivBytes in
            keyValue.withUnsafeMutableBytes {keyBytes in
                CCCrypt( // Stateless, one-shot encrypt operation
                    CCOperation(kCCEncrypt),                // op: CCOperation
                    CCAlgorithm(kCCAlgorithmAES),           // alg: CCAlgorithm
                    CCOptions(kCCOptionPKCS7Padding),                                // options: CCOptions
                    keyBytes.baseAddress,                   // key: the "password"
                    key.count,                              // keyLength: the "password" size
                    ivBytes.baseAddress,                // iv: Initialization Vector
                    encryptedBytes.baseAddress,                  // dataIn: Data to encrypt bytes
                    input.count,                    // dataInLength: Data to encrypt size
                   &outBytes, //bufferBytes.baseAddress! + kCCBlockSizeAES128, // dataOut: encrypted Data buffer
                    outBytes.count,                             // dataOutAvailable: encrypted Data buffer size
                    &outLength                   // dataOutMoved: the number of bytes written
                )
            }
        }
    }
    
    
    

    guard status == kCCSuccess else {
        throw Error.cryptoFailed(status: status)
    }
    return Data(bytes: UnsafePointer<UInt8>(outBytes), count: outLength)
}

Approach 2 Based on this link How to use CommonCrypto for PBKDF2 in Swift 2 & 3

But I am getting different base64 encoded string in both platform. Please help.

Cheerful answered 23/3, 2021 at 5:25 Comment(8)
Did you check if the PBKDF2 parameters (digest, salt, iteration count and password) of both codes are identical, and also if the two keys generated with PBKDF2 match?Conclusive
@Conclusive but I did not find anywhere how can I pass secretKey in swiftCheerful
I am not familiar with Swift. PBKDF2, as the name implies, is a password-based key derivation function that derives a key from a password. What is called secretKey in the Android code is the password, see PBEKeySpec(), which should thus correspond to the second parameter password in the Swift code.Conclusive
Yes @Conclusive but stringToEncrypt in Android is the password where it passing to cipher & secretKey passing into PBEKeySpec which is prerequisite for Cipher for android.Cheerful
what iOS version is this on ? Do you run on the device or simulator ? Try different iOS version. I remember there was a bug about this.Wifehood
iOS 14 @MaksimKniazevCheerful
According to your description, the ciphertexts are different (I am getting different base64 encoded string in both case), so it makes sense to isolate the issue. The first thing to do is to compare the keys, which brings me back to my first comment: are you using the same PBKDF2 parameters in both codes and are the generated keys identical?Conclusive
@Conclusive I have updated another approach. Can you please look now ?Cheerful

© 2022 - 2024 — McMap. All rights reserved.