iOS 3des 的加密与 android 和 .net 不同
Posted
技术标签:
【中文标题】iOS 3des 的加密与 android 和 .net 不同【英文标题】:Encryption for iOS 3des not same as android and .net 【发布时间】:2014-10-18 06:28:03 【问题描述】:我正在尝试在 ios 上使用 3des 进行一些加密,它必须与 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;
此代码成功地加密和解密了一个字符串。但是,它与 .NET 和 java 的结果不匹配。 谢谢
【问题讨论】:
这被称为 2-key 3DES,已经过时,不安全,尽可能不要在新工作中使用。 【参考方案1】:已经找到解决上述在 iOS 和 .NET 或 Java 上生成的加密值不同的问题。
解决方案: 1. 在 android 和 .NET 中,您必须使用大小为 16 字节的密钥(例如:key="1234567890123456")
在 iOS 中,您需要使用 24 字节大小的密钥,但密钥的生成会有所不同。 使用在 Android 或 .NET 中使用的相同密钥(16 个字节)并将其附加到相同密钥的前 8 个字节。
key16Byte = "1234567890123456" //Android 和 .NET 密钥 key24Byte = key16Byte + "12345678" //ios和Java key,复制16Byte key的前8个字节 //new24ByteKey = "123456789012345612345678"
从 CCypher 模式中移除“& kCCModeCBC”。
某些值需要 CCCrypt 函数中的字节,我已在下面提到的代码中进行了更改。像 keyData、encryptData。
产生不同加密的原因: Android 和 .NET - 它需要 16Byte 的密钥并在内部复制,并生成一个 24Byte 的密钥。
Java - 如果您提供 16 字节的键值,它会引发异常“键长度无效”。
iOS - 它使用 16Byte 和 24Byte 这两个值生成加密值而不抛出任何异常,这就是我们在 16Byte 密钥的情况下生成不同加密的原因。
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;
【讨论】:
我也有同样的问题,问这个问题***.com/questions/40887490/…。如果你能帮助我,我将不胜感激。【参考方案2】:正如@Jugal Desai 所提到的,iOS 和Android/.Net 之间的关键区别在于,后来的那些会自动从密钥的开头用另外8 个字节填充密钥(大小为16 字节)!你救了我 :) 在这里,我提供了 Swift 3 中的简单修复:
....
YOUR_KEY_SIZE_16 = YOUR_KEY_SIZE_16 + YOUR_KEY_SIZE_16[0...7]
....
带有 base64 结果的示例完整代码(密钥哈希的 MD5 + ECB + PKCS7Padding):
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 ""
【讨论】:
【参考方案3】:解密有多严重?
- (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 3des 的加密与 android 和 .net 不同的主要内容,如果未能解决你的问题,请参考以下文章