为什么这个Des Encryption的iOS实现不会产生与Java相同的结果?

时间:2013-11-14 17:32:42

标签: java ios objective-c encryption

这是Java PBEWithMD5AndDES 实现算法。

在不使用任何外部库的情况下,在iOS平台上查找Objective-C 中的确切等效项。接受的解决方案应该只依赖于iOS SDK中包含的库。

下面的Java使用密码“foo”加密“bar”,因为“0WUc + boDvbU =”

new DesEncrypter("foo").encrypt("bar") == "0WUc+boDvbU="

但是obj-c代码使用密码“foo”“bar”,因为“VRWOhmfj2g8 =”

 NSString* encrypted = [ self encrypt:@"bar"]; == "VRWOhmfj2g8="

我正在寻找的是将“bar”加密为“0WUc + boDvbU =”的obj-c加密方法,就像Java一样。

Java代码:

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;


public class DesEncrypter {
    private Cipher ecipher;

    private Cipher dcipher;

    private byte[] salt = {(byte) 0x10, (byte) 0x1B, (byte) 0x12, (byte) 0x21, (byte) 0xba, (byte) 0x5e,
            (byte) 0x99, (byte) 0x12};

    public DesEncrypter(String passphrase) throws Exception {
        int iterationCount = 2;
        KeySpec keySpec = new PBEKeySpec(passphrase.toCharArray(), salt, iterationCount);
        SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);
        ecipher = Cipher.getInstance(key.getAlgorithm());
        dcipher = Cipher.getInstance(key.getAlgorithm());

        AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);

        ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
        dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
    }

    public String encrypt(String str) throws Exception {
        return new BASE64Encoder().encode(ecipher.doFinal(str.getBytes())).trim();
    }

    public String decrypt(String str) throws Exception {
        return new String(dcipher.doFinal(new BASE64Decoder().decodeBuffer(str))).trim();
    }
}

对象代码

- (NSString*) encrypt:(NSString*)encryptValue {
    const void *vplainText;
    size_t plainTextBufferSize = [encryptValue length];
    vplainText = (const void *) [encryptValue UTF8String];
    CCCryptorStatus ccStatus;
    uint8_t *bufferPtr = NULL;
    size_t bufferPtrSize = 0;
    size_t movedBytes = 0;
    bufferPtrSize = (plainTextBufferSize + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1);
    bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
    memset((void *)bufferPtr, 0x0, bufferPtrSize);
    unsigned char salt [] =  {0x10,0x1B,0x12,0x21,0xba,0x5e,0x99,0x12};
    NSString *key = @"foo";
    const void *vkey = (const void *) [key UTF8String];
    ccStatus = CCCrypt(kCCEncrypt,kCCAlgorithmDES,kCCOptionPKCS7Padding,vkey,kCCKeySizeDES,salt,vplainText,
                       plainTextBufferSize,(void *)bufferPtr,bufferPtrSize,&movedBytes);
    NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
    NSString *result = [myData base64Encoding];
    return result;
}

4 个答案:

答案 0 :(得分:4)

有很多关于加密的错误信息,我不想再传播了。但是,我在这里要说的是 MOSTLY 是真的,只是略微简化以限制范围并保持简洁。

使用任何类型的加密对文本进行加密和解密时,通常都会使用某种密码。与流行的看法相反,该密码不会解锁任何东西。相反,密码与其他因素(Salt,Initial Vectors,Hashing等)组合以生成和加密密钥。从密码到加密密钥的细节是密钥扩散算法。对于相同的加密算法(例如AES或DES),在不同平台中具有不同的密钥扩散算法是常见的。不幸的是,这意味着在一个平台上加密的数据无法在另一个平台上解密。

这并不意味着任务是不可能的。它只表示您在跨平台工作时必须找到兼容的实现或设置。

答案 1 :(得分:2)

您忘记准备密钥,因为此算法需要使用密钥。如果我们这样做,输出与Java版本相同。

- (NSString *)encrypt:(NSString *)encryptValue {
    // first of all we need to prepare key with md5
    // setup md5 context with salt and key
    NSString *key = @"foo";
    unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH];
    memset(md5Buffer, 0, CC_MD5_DIGEST_LENGTH);
    NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
    CC_MD5_CTX md5Ctx;
    CC_MD5_Init(&md5Ctx);
    CC_MD5_Update(&md5Ctx, [keyData bytes], [keyData length]);
    unsigned char salt[] =  {0x10,0x1B,0x12,0x21,0xba,0x5e,0x99,0x12};
    CC_MD5_Update(&md5Ctx, salt, 8);
    CC_MD5_Final(md5Buffer, &md5Ctx);

    // do md5 hashing
    CC_MD5(md5Buffer, CC_MD5_DIGEST_LENGTH, md5Buffer);

    // our key is ready, let's prepare other buffers and moved bytes length
    NSData *encryptData = [encryptValue dataUsingEncoding:NSUTF8StringEncoding];
    size_t resultBufferSize = [encryptData length] + kCCBlockSizeDES;
    unsigned char resultBuffer[resultBufferSize];
    size_t moved = 0;

    // DES-CBC requires an explicit Initialization Vector (IV)
    // IV - second half of md5 key
    unsigned char IV[kCCBlockSizeDES];
    memcpy(IV, md5Buffer + CC_MD5_DIGEST_LENGTH / 2, sizeof(IV));

    CCCryptorStatus cryptorStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES,
                                        kCCOptionPKCS7Padding, md5Buffer,
                                        CC_MD5_DIGEST_LENGTH/2, IV,
                                        [encryptData bytes], [encryptData length],
                                        resultBuffer, resultBufferSize, &moved);

    if (cryptorStatus == kCCSuccess) {
        return [[NSData dataWithBytes:resultBuffer length:moved] base64EncodedStringWithOptions:0];
    } else {
        return nil;
    }
}

输出:0WUc + boDvbU =

答案 2 :(得分:1)

一种可能性是String.getBytes()将在平台的默认字符集中返回byte []。最好使用String.getBytes(“UTF-8”)

java代码的迭代次数设置为2,我在目标c版本中没有看到。

答案 3 :(得分:0)

只是一个建议,你在iOS上尝试过不同的填充选项吗?看起来你正在使用的当前填充是kCCOptionPKCS7Padding。这是一个简单的改变,也许会提供一些额外的信息......