iOS 3DE的加密与android和.net不同

iOS 3DE的加密与android和.net不同,android,ios,objective-c,iphone,.net,Android,Ios,Objective C,Iphone,.net,我正在尝试在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 k

我正在尝试在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;
}
-(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;
- (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代码为:

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

此代码成功加密和解密字符串。但是,它与.NET和java的结果不匹配。
感谢您

找到了解决上述问题的方法,即在iOS和.NET或Java上生成不同的加密值

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

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

key16Byte=“1234567890123456”//Android和.NET键 key24Byte=key16Byte+“12345678”//ios和Java密钥,复制了16字节密钥的前8个字节 //new24ByteKey=“1234567890121345612345678”

  • 从CCypher模式中删除“&kCCModeCBC”

  • 有些值需要CCCrypt函数中的字节,我在下面提到的代码中对其进行了更改。像keyData一样,加密数据

  • 生成不同加密的原因: Android和.NET——它需要16字节的密钥并进行内部复制,生成24字节的密钥

    Java-如果您提供16字节的键值,它会抛出一个异常“无效的键长度”

    iOS-它生成的加密值包含16字节和24字节这两个值,不会引发任何异常,这也是我们在16字节密钥的情况下生成不同加密的原因

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

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

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

    。。。。

    带有base64结果的完整代码示例(MD5表示密钥哈希+ECB+PKCS7Padding):

    func-tripleDesEncrypt(键串:String,传递:String)->String{
    让keyData=keyString.data(使用:.utf8)!
    var digestData=数据(计数:Int(CC_MD5_DIGEST_长度))
    _=digestData.WithUnsafemtableBytes{digestBytes in
    keyData.withUnsafeBytes{messageBytes in
    CC_MD5(messageBytes,CC_LONG(keyData.count),digestBytes)
    }
    }
    digestData=digestData+digestData[0…7]
    让data=pass.data(使用:.utf8)!
    设dataNS=数据为NSData
    让cryptData=NSMutableData(长度:Int(dataNS.length)+kCCBlockSize3DES)!
    let keyLength=大小(kCCKeySize3DES)
    let操作:cOperation=UInt32(kCCEncrypt)
    let算法:CCAlgorithm=UInt32(kCCAlgorithm3DES)
    let选项:CCOptions=UInt32(kCCOptionECBMode+kCCOptionPKCS7Padding)
    var numBytesEncrypted:size\u t=0
    让cryptStatus=CCCrypt(操作,
    算法,
    选项,
    (digestData作为NSData)。字节,
    键长,
    无
    dataNS.bytes,
    数据长度,
    cryptData.mutableBytes,
    cryptData.length,
    &(未加密)
    如果UInt32(加密状态)=UInt32(kCCSuccess){
    cryptData.length=Int(numBytesEncrypted)
    //并非所有数据都是UTF-8字符串,因此使用Base64
    让base64cryptString=cryptData.base64EncodedString(选项:NSData.Base64EncodingOptions.LineLength76个字符)
    返回base64cryptString
    }否则{
    打印(“错误:\(加密状态)”)
    }
    返回“”
    }
    
    我也有同样的问题,问这个问题。如果您能帮助我,我将不胜感激。这被称为2键3DES,是过时的,不安全的,如果可能的话,不应该在新的工作中使用。