iOS 3des的encryption与android和.net不一样

我想在iOS上使用3des进行一些encryption,必须匹配java和.NET的结果。

Java代码是:

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的代码一样是:

 -(NSString*)new3DESwithoperand:(NSString*)plaintext encryptOrDecrypt:(CCOperation)encryptorDecrypt key:(NSString*)key initVec:(NSString*)initVec { NSData* data = [plaintext dataUsingEncoding:NSUTF8StringEncoding]; const void *vplainText = [data bytes];; size_t plainTextBufferSize = [data length]; NSLog(@"%@, Length: %u",[data description],[data length]); size_t bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1); NSLog(@"%zu, sizof of uint8_t: %zu",bufferPtrSize, sizeof(uint8_t)); size_t movedBytes = 0; uint8_t *bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t)); NSLog(@"%zu",sizeof(bufferPtr)); memset((void*)bufferPtr, 0x0, bufferPtrSize); NSLog(@"%zu",sizeof(bufferPtr)); const void * vkey = [[NSData base64DataFromString:key] bytes]; const void *vinitVec = [[NSData base64DataFromString:initVec] bytes]; NSLog(@"vinitvec: %@",[[NSData base64DataFromString:initVec] description]); CCCryptorStatus ccStatus; ccStatus = CCCrypt(encryptorDecrypt, kCCAlgorithm3DES, kCCOptionPKCS7Padding & kCCModeCBC, vkey, kCCKeySize3DES, vinitVec, vplainText, plainTextBufferSize, (void*)bufferPtr, bufferPtrSize, &movedBytes); NSData* result = [NSData dataWithBytes:(const void*)bufferPtr length:(NSUInteger)movedBytes]; NSString* str = [NSString base64StringFromData:result length:result.length]; NSLog(@"%@",str); return str; 

}

此代码成功地encryption和解密一个string。 但是,它不符合.NET和Java的结果。 谢谢

find了解决上述在iOS和.NET或Java上生成的不同encryption值问题的解决scheme。

解:
1.在Android和.NET中,您必须使用大小为16字节的密钥(例如:key =“1234567890123456”)

在iOS中,您需要使用24字节的密钥大小,但密钥的生成会有所不同。 使用与Android或.NET(16字节)中使用的相同的密钥,并将其附加在同一个密钥的前8个字节中。

key16Byte =“1234567890123456”// Android和.NET密钥key24Byte = key16Byte +“12345678”// ios和Java密钥,先复制8字节的16字节密钥// new24ByteKey =“123456789012345612345678”

  1. 从CCypher模式中删除“&kCCModeCBC”。

  2. 一些值需要CCCrypt函数中的字节,我已经在下面提到的代码中进行了更改。 如keyData,encryptData。

生成不同encryption的原因: Android和.NET – 需要16Byte密钥和内部复制,并生成24Byte密钥。

Java – 它会抛出一个exception“无效的密钥长度”,如果你提供一个16Byte的键值。

iOS – 它生成16Byte和24Byte这两个值的encryption值,而不会抛出任何exception,所以我们得到16Byte密钥的情况下生成不同的encryption的原因。

Java代码

 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代码:

 - (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; } 

正如@Jugal Desai所提到的,iOS和Android / .Net之间的主要区别在于后者会自动从密钥起始处填充密钥(大小为16字节)和另外8个字节! 你救了我:)在这里我提供了简单的修复在Swift 3:

….

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

….

使用base64结果示例完整代码(key hash + ECB + PKCS7Padding的MD5):

 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 "" } 

解密有多严重?

 - (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; } }