swiftencryptioncommoncrypto

CommonCrypto to generate encrypted string with 16 char length


It is the first time I try to use encryption so I am not sure if what I need is achievable with the following code.

MY PROBLEM - I need it to generate an encoded string with 16 characters instead of the 64 character that is being generated at the moment.

I have a preference for using a native swift library instead of an external framework. And because of that could not find much about how to use CommonCrypto. Not sure if it is correct approach as well.

Where I got the example

http://sketchytech.blogspot.co.nz/2016/02/resurrecting-commoncrypto-in-swift-for.html

My usage

let keyString = "1234567812345678"
    let message = "12345678123456781234567812345678"
    let iv = "iv-salt-string--" // string of 16 characters in length

    let encoded = message.aesEncrypt(keyString, iv: iv)!
    print("encoded -> \(encoded)")

    let unencode = encoded.aesDecrypt(keyString, iv: iv)!
    print("unencode -> \(unencode)")

Output

encoded -> S81qV6F31xO8mUA1+HhsF7pHOMeE0f6Bbcmj3Zzk3EFLhQTCmfYlouorrUkYKL6K
unencode -> 12345678123456781234567812345678

Extension

extension String {

    func aesEncrypt(key:String, iv:String, options:Int = kCCOptionPKCS7Padding) -> String? {
        if let keyData = key.dataUsingEncoding(NSUTF8StringEncoding),
            data = self.dataUsingEncoding(NSUTF8StringEncoding),
            cryptData    = NSMutableData(length: Int((data.length)) + kCCBlockSizeAES128) {


                let keyLength              = size_t(kCCKeySizeAES128)
                let operation: CCOperation = UInt32(kCCEncrypt)
                let algoritm:  CCAlgorithm = UInt32(kCCAlgorithmAES128)
                let options:   CCOptions   = UInt32(options)



                var numBytesEncrypted :size_t = 0

                let cryptStatus = CCCrypt(operation,
                    algoritm,
                    options,
                    keyData.bytes, keyLength,
                    iv,
                    data.bytes, data.length,
                    cryptData.mutableBytes, cryptData.length,
                    &numBytesEncrypted)

                if UInt32(cryptStatus) == UInt32(kCCSuccess) {
                    cryptData.length = Int(numBytesEncrypted)
                    let base64cryptString = cryptData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
                    return base64cryptString


                }
                else {
                    return nil
                }
        }
        return nil
    }

    func aesDecrypt(key:String, iv:String, options:Int = kCCOptionPKCS7Padding) -> String? {
        if let keyData = key.dataUsingEncoding(NSUTF8StringEncoding),
            data = NSData(base64EncodedString: self, options: .IgnoreUnknownCharacters),
            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(options)

                var numBytesEncrypted :size_t = 0

                let cryptStatus = CCCrypt(operation,
                    algoritm,
                    options,
                    keyData.bytes, keyLength,
                    iv,
                    data.bytes, data.length,
                    cryptData.mutableBytes, cryptData.length,
                    &numBytesEncrypted)

                if UInt32(cryptStatus) == UInt32(kCCSuccess) {
                    cryptData.length = Int(numBytesEncrypted)
                    let unencryptedMessage = String(data: cryptData, encoding:NSUTF8StringEncoding)
                    return unencryptedMessage
                }
                else {
                    return nil
                }
        }
        return nil
    }
}

Solution

  • You have 16 bytes of input after converting to data from hex. You specify PKCS#7 padding kCCOptionPKCS7Padding. If the data is an exact multiple of the block size PKCS#7 padding must add an entire block of padding to the data to be encrypted making 32-bytes of data. (That is because some padding must always be added and if there is no partial block the only way is to add a block of padding.) On decryption the 16-bytes of padding will be removed so you will get back 16-bytes of data.

    See: PKCS#7 padding.

    If the input data is always a multiple of the block size (16-bytes) then you do not need to add padding, so you do not need to supply the kCCOptionPKCS7Padding as an option.