2

这是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="

我正在寻找的是 obj-c 加密方法将“bar”加密为“0WUc+boDvbU=”,就像 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();
    }
}

obj-c 代码

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

4 回答 4

4

有很多关于加密的错误信息,我不想再传播了。但是,我在这里要说的大部分内容都是正确的,只是为了限制范围并保持简洁而进行了一些细微的简化。

当您使用任何类型的加密加密和解密文本时,您通常从某种密码开始。与流行的看法相反,密码并不能解锁任何东西。相反,密码与其他因素(盐、初始向量、散列等)相结合以生成和加密密钥。从密码到加密密钥的细节是密钥扩散算法。相同的加密算法(例如 AES 或 DES)在不同的平台上具有不同的密钥扩散算法是很常见的。不幸的是,这意味着在一个平台上加密的数据无法在另一个平台上解密。

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

于 2013-11-18T14:03:38.750 回答
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=

于 2013-11-19T21:49:35.877 回答
1

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

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

于 2013-11-17T21:52:28.310 回答
0

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

于 2013-11-19T15:03:52.013 回答