AES Encryption .net to swift

后端 未结 2 1231
死守一世寂寞
死守一世寂寞 2021-01-01 06:36

.Net Code :

public string AESEncrypt(string clearText,string key)
        {
            string EncryptionKey = key; // \"MAKV2SPBNI99212\";
            byte[         


        
2条回答
  •  被撕碎了的回忆
    2021-01-01 06:44

    As far as I tested both your codes, C# and Swift, the main difference causing your issue is string encoding.


    But before going there, I need to note that your code is full of bad practices about using Data and NSData, passing the address of Data or [UInt8] etc, etc. Some of them are critical.

    The one super-ciritical is this line:

    let buffer = UnsafeMutablePointer.allocate(capacity: buffer_size)
    

    You need to allocate a buffer_size-byte memory region, you do not want buffer_size references to NSData.

    Some other fragile lines:

    let ptrData = myPassData.bytes.assumingMemoryBound(to: Int8.self)
    let ptrSalt = saltData.bytes.assumingMemoryBound(to: UInt8.self)
    let keyPtr = UnsafeMutablePointer(mutating: key)
    

    These lines are strongly dependent on the code generation of the current implementation of Swift and on your current settings.

    Simply saying, it is astonishing that your code seems to work without crashing.


    So, I started with re-writing your Swift code as follows:

    func testCrypt(data: Data, keyData: Data, ivData: Data, operation:Int) -> Data {
        assert(keyData.count == Int(kCCKeySizeAES128) || keyData.count == Int(kCCKeySizeAES192) || keyData.count == Int(kCCKeySizeAES256))
    
        let buffer_size = data.count + kCCBlockSizeAES128
        var buffer: [UInt8] = Array(repeating: 0, count: buffer_size)
        var num_bytes_encrypted : size_t = 0
        let operation = CCOperation(operation)
        let algoritm = CCAlgorithm(kCCAlgorithmAES)
        let options = CCOptions(kCCOptionPKCS7Padding)
    
        let cryptoStatus = keyData.withUnsafeBytes {keyDataBytes in
            ivData.withUnsafeBytes {ivDataBytes in
                data.withUnsafeBytes {dataBytes in
                    CCCrypt(operation, algoritm, options, keyDataBytes, keyData.count, ivDataBytes, dataBytes, data.count, &buffer, buffer_size, &num_bytes_encrypted)
                }
            }
        }
    
        if cryptoStatus == CCCryptorStatus(kCCSuccess){
            let myResult = Data(bytes: buffer, count: num_bytes_encrypted)
            return myResult
        } else {
            return Data()
        }
    }
    
    
    func testDeCrypt(data: Data, keyData: Data, ivData: Data, operation: Int) -> Data {
        assert(keyData.count == Int(kCCKeySizeAES128) || keyData.count == Int(kCCKeySizeAES192) || keyData.count == Int(kCCKeySizeAES256))
    
        var decryptedData = Data(count: data.count)
        var num_bytes_decrypted: size_t = 0
        let operation = CCOperation(operation)
        let algoritm = CCAlgorithm(kCCAlgorithmAES)
        let options = CCOptions(kCCOptionPKCS7Padding)
    
        let cryptoStatus = keyData.withUnsafeBytes {keyDataBytes in
            ivData.withUnsafeBytes {ivDataBytes in
                data.withUnsafeBytes {dataBytes in
                    decryptedData.withUnsafeMutableBytes {decryptedDataBytes in
                        CCCrypt(operation, algoritm, options, keyDataBytes, keyData.count, ivDataBytes, dataBytes, data.count, decryptedDataBytes, decryptedData.count, &num_bytes_decrypted)
                    }
                }
            }
        }
    
        if cryptoStatus == CCCryptorStatus(kCCSuccess) {
            decryptedData.count = num_bytes_decrypted
            return decryptedData
        } else {
            return Data()
        }
    }
    
    extension String {
        func AESEncryptedString(withKey keyString: String) -> String? {
    
            let salt: [UInt8] = [0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76]
            var key = [UInt8](repeating: 0, count: 48)
    
            CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2), keyString, keyString.utf8.count, salt, salt.count, CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1), 1024, &key, 48)
    
            let initialVector = Array(key[32..<48])
    
            key = Array(key[0..<32])
    
            let keyData = Data(bytes: key)
            let ivData = Data(bytes: initialVector)
    
            let rawData = self.data(using: .unicode)!
            let encryptedData = testCrypt(data: rawData, keyData: keyData, ivData: ivData, operation: kCCEncrypt)
    
            let decryptedData = testDeCrypt(data: encryptedData, keyData: keyData, ivData: ivData, operation: kCCDecrypt)
    
            let decrypted = String(bytes: decryptedData, encoding: .unicode)!
    
            print("Encrypted Data: \(encryptedData.base64EncodedString()) \n with count: \(encryptedData.base64EncodedString().characters.count)")
            print("Decrypted: \(decrypted)")
    
            let encryptedString  = encryptedData.base64EncodedString()
    
            return encryptedString
        }
    
    }
    

    (String.Encoding.utf16 is just an alias of String.Encoding.unicode, so I replaced the line using .utf16 to .unicode.)

    The part your C# code converts string to byte array:

    byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
    

    And the part generating Data in Swift:

    let rawData = self.data(using: .unicode)!
    

    Those two lines generate different byte sequences, as .unicode conforms to canonical UTF-16 representation, which contains a BOM at the top of the result, but System.Text.Encoding.Unicode does not add a BOM.


    So, change the two lines including .unicode to .utf16LittleEndian:

    let rawData = self.data(using: .utf16LittleEndian)!
    
    let decrypted = String(bytes: decryptedData, encoding: .utf16LittleEndian)!
    

    Try and see what you get with these changes.

提交回复
热议问题