Encryption for iOS 3des not same as android and .net

后端 未结 3 477
春和景丽
春和景丽 2020-12-15 02:28

I\'m trying do some encrypt something using 3des on the iOS that must match the results from java and .NET.

Java code is :

public cl         


        
相关标签:
3条回答
  • 2020-12-15 02:37

    How serious in decrypted?

    - (NSString *)encrypt:(NSString *)encryptValue key:(NSString *)key24Byte IV:(NSString *)IV{
        // first of all we need to prepare key
        if([key length] != 24)
            return @"Require 24 byte key, call function generate24ByteKeySameAsAndroidDotNet with a 16Byte key same as used in Android and .NET"; //temporary error message
    
    
        NSData *keyData = [key24Byte dataUsingEncoding:NSUTF8StringEncoding];
    
        // our key is ready, let's prepare other buffers and moved bytes length
        NSData *encryptData = [encryptValue dataUsingEncoding:NSUTF8StringEncoding];
        size_t resultBufferSize = [encryptData length] + kCCBlockSize3DES;
        unsigned char resultBuffer[resultBufferSize];
        size_t moved = 0;
    
        // DES-CBC requires an explicit Initialization Vector (IV)
        // IV - second half of md5 key
        NSMutableData *ivData = [[IV dataUsingEncoding:NSUTF8StringEncoding]mutableCopy];
        NSMutableData *iv = [NSMutableData dataWithData:ivData];
    
        CCCryptorStatus cryptorStatus = CCCrypt(kCCEncrypt, kCCAlgorithm3DES,
                                                kCCOptionPKCS7Padding , [keyData bytes],
                                                kCCKeySize3DES, [iv bytes],
                                                [encryptData bytes], [encryptData length],
                                                resultBuffer, resultBufferSize, &moved);
    
        if (cryptorStatus == kCCSuccess) {
            return [[NSData dataWithBytes:resultBuffer length:moved] base64EncodedStringWithOptions:0];
        } else {
            return nil;
        }
    }
    
    0 讨论(0)
  • 2020-12-15 02:51

    Have found a solution for the above problem of encryption value generated different on iOS and .NET or Java.

    Solution:
    1. In Android and .NET you have to use a key of size 16 Bytes (eg: key="1234567890123456")

    In iOS you need to use a key size of 24 bytes but the generation of key makes a little difference. Use the same key as used in Android or .NET (16 bytes) and append it with the first 8 Bytes of the same key.

    key16Byte = "1234567890123456" //Android and .NET key key24Byte = key16Byte + "12345678" //ios and Java key, Replicated first 8 Bytes of 16Byte key //new24ByteKey = "123456789012345612345678"

    1. Remove "& kCCModeCBC" from CCypher Mode.

    2. Some values require bytes in CCCrypt function which I have changed in the below mentioned code below. like keyData, encryptData.

    Reason for different encryption generated: Android and .NET - It takes 16Byte key and internally replicates, and generates a 24Byte key.

    Java - It throws an Exception "Invalid key length", if you provide a 16Byte key value.

    iOS - It generates encryption value with 16Byte and 24Byte both values without throwing any exception, so is the reason we get a different encryption generated in case of 16Byte key.

    Java Code

    public class EncryptionHelper {
    
    // Encrypts string and encode in Base64
    public static String encryptText(String plainText,String key, String IV) throws Exception {
       // ---- Use specified 3DES key and IV from other source --------------
        byte[] plaintext = plainText.getBytes();//input
        byte[] tdesKeyData = key.getBytes();// your encryption key
    
        byte[] myIV = IV.getBytes();// initialization vector
    
        Cipher c3des = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        SecretKeySpec myKey = new SecretKeySpec(tdesKeyData, "DESede");
        IvParameterSpec ivspec = new IvParameterSpec(myIV);
    
        c3des.init(Cipher.ENCRYPT_MODE, myKey, ivspec);
        byte[] cipherText = c3des.doFinal(plaintext);
        String encryptedString = Base64.encodeToString(cipherText,
                Base64.DEFAULT);
        // return Base64Coder.encodeString(new String(cipherText));
        return encryptedString;
    }
    

    iOS Code:

    - (NSString *)encrypt:(NSString *)encryptValue key:(NSString *)key24Byte IV:(NSString *)IV{
        // first of all we need to prepare key
        if([key length] != 24)
            return @"Require 24 byte key, call function generate24ByteKeySameAsAndroidDotNet with a 16Byte key same as used in Android and .NET"; //temporary error message
    
    
        NSData *keyData = [key24Byte dataUsingEncoding:NSUTF8StringEncoding];
    
        // our key is ready, let's prepare other buffers and moved bytes length
        NSData *encryptData = [encryptValue dataUsingEncoding:NSUTF8StringEncoding];
        size_t resultBufferSize = [encryptData length] + kCCBlockSize3DES;
        unsigned char resultBuffer[resultBufferSize];
        size_t moved = 0;
    
        // DES-CBC requires an explicit Initialization Vector (IV)
        // IV - second half of md5 key
        NSMutableData *ivData = [[IV dataUsingEncoding:NSUTF8StringEncoding]mutableCopy];
        NSMutableData *iv = [NSMutableData dataWithData:ivData];
    
        CCCryptorStatus cryptorStatus = CCCrypt(kCCEncrypt, kCCAlgorithm3DES,
                                                kCCOptionPKCS7Padding , [keyData bytes],
                                                kCCKeySize3DES, [iv bytes],
                                                [encryptData bytes], [encryptData length],
                                                resultBuffer, resultBufferSize, &moved);
    
        if (cryptorStatus == kCCSuccess) {
            return [[NSData dataWithBytes:resultBuffer length:moved] base64EncodedStringWithOptions:0];
        } else {
            return nil;
        }
    }
    

    iOS

    -(NSString *)generate24ByteKeySameAsAndroidDotNet:(NSString *)key{
        NSString *new24ByteKey = key;
    
        ;
        new24ByteKey = [new24ByteKey stringByAppendingString:[key substringWithRange:NSMakeRange(0, 8)]];
    
        return new24ByteKey;
    }
    
    0 讨论(0)
  • 2020-12-15 02:58

    As @Jugal Desai mentioned, the key difference between iOS and Android/.Net is that the later ones automatically fill the key (with size 16 bytes) with another 8 bytes from the start of the key! You saved me :) Here I provide the simple fix in Swift 3:

    ....

    YOUR_KEY_SIZE_16 = YOUR_KEY_SIZE_16 + YOUR_KEY_SIZE_16[0...7]
    

    ....

    Sample complete code (MD5 for key hash + ECB + PKCS7Padding) with base64 result:

    func tripleDesEncrypt(keyString: String, pass: String) -> String{
        let keyData = keyString.data(using: .utf8)!
    
        var digestData = Data(count: Int(CC_MD5_DIGEST_LENGTH))
    
        _ = digestData.withUnsafeMutableBytes {digestBytes in
    
            keyData.withUnsafeBytes {messageBytes in
                CC_MD5(messageBytes, CC_LONG(keyData.count), digestBytes)
            }
        }
    
        digestData = digestData + digestData[0...7]
        let data = pass.data(using: .utf8)!
        let dataNS = data as NSData
    
        let cryptData    = NSMutableData(length: Int(dataNS.length) + kCCBlockSize3DES)!
    
        let keyLength              = size_t(kCCKeySize3DES)
        let operation: CCOperation = UInt32(kCCEncrypt)
        let algoritm:  CCAlgorithm = UInt32(kCCAlgorithm3DES)
        let options:   CCOptions   = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
    
        var numBytesEncrypted :size_t = 0
    
        let cryptStatus = CCCrypt(operation,
            algoritm,
            options,
            (digestData as NSData).bytes,
            keyLength,
            nil,
            dataNS.bytes,
            dataNS.length,
            cryptData.mutableBytes,
            cryptData.length,
            &numBytesEncrypted)
    
        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
            cryptData.length = Int(numBytesEncrypted)
    
            // Not all data is a UTF-8 string so Base64 is used
            let base64cryptString = cryptData.base64EncodedString(options: NSData.Base64EncodingOptions.lineLength76Characters)
            return base64cryptString
        } else {
            print("Error: \(cryptStatus)")
        }
        return ""
    }
    
    0 讨论(0)
提交回复
热议问题