2

我正在尝试从 VB.NET 重新创建 PasswordDeriveBytes 的实现,到目前为止,我已经在 iOS 目标 C 代码中实现了它,它给了我与 Java 实现不同的结果。

我们尝试重新创建 PasswordDeriveBytes 实现的原因是因为客户端服务器端正在使用它来加密/解密数据,并且根据我的搜索,PasswordDeriveBytes 使用过时的 PBKDF1。Java 实现正在返回预期的加密值,并且正在由服务器成功解密。但是从 iOS ObjC 实现返回的值是不正确的。

下面是构造函数的 Java 实现,取自这个答案:Java 和 C# 之间的加密差异

public static class PasswordDeriveBytes{

private final MessageDigest hash;

private final byte[] firstToLastDigest;
private final byte[] outputBuffer;

private int position = 0;

public PasswordDeriveBytes(String password, byte[] salt, int iterations) {
    try {
        this.hash = MessageDigest.getInstance("SHA-1");

        this.hash.update(password.getBytes("UTF-8"));
        this.hash.update(salt);
        this.firstToLastDigest = this.hash.digest();
        // At this point, the Obj-C and Java values are the same
        // this.firstToLastDigest = b8fa3d36....

        for (int i = 1; i < iterations - 1; i++) {
            System.out.println( "  Iterate " + i);
            hash.update(firstToLastDigest);
            hash.digest(firstToLastDigest, 0, firstToLastDigest.length);
        }

        this.outputBuffer = hash.digest(firstToLastDigest);
        // However at this point, they become different
        // Java has outputBuffer = f498e100...
        // Obj-C has outputBuffer = <d7d5fa71...

    } catch (UnsupportedEncodingException|NoSuchAlgorithmException | DigestException e) {
        throw new IllegalStateException("SHA-1 digest should always be available", e);
    }
}

下面是构造函数的 Objective C 代码,使用这个库:https ://github.com/TakahikoKawasaki/nv-ios-digest

@implementation PasswordDeriveBytesObjC
{
    SHA1 *hash;
    Byte *firstToLastDigest;
    Byte *outputBuffer;

    int position;
}

- (instancetype)initWithPassword:(NSString *)password salt:(NSData *)salt iterations:(int)iterations
{
    self = [[[self class] alloc] init];
    if (self){
        hash = [[SHA1 alloc] init];

        const char* ASCIIpassword = [password cStringUsingEncoding:NSUTF8StringEncoding];
        NSData *passwordData = [NSData dataWithBytes:ASCIIpassword length:strlen(ASCIIpassword)];

        [hash updateWith:[passwordData bytes] length:(CC_LONG)[passwordData length]];
        [hash updateWith:[salt bytes] length:(CC_LONG)[salt length]];
        firstToLastDigest = [hash final];
        // At this point, the Obj-C and Java values are the same
        // firstToLastDigest = <b8fa3d36....

        for ( int i = 1; i < iterations - 1; i++ ){
            [hash updateWith:firstToLastDigest length:(CC_LONG)strlen(firstToLastDigest)];
        }

        [hash updateWith:firstToLastDigest length:(CC_LONG)strlen(firstToLastDigest)];
        outputBuffer = [hash final];  
        // However at this point, they become different
        // Java has outputBuffer = f498e100...
        // Obj-C has outputBuffer = <d7d5fa71...

    }
    return self;
}

据我研究,hash.digest(input)java的实现与Obj-C相同,[hash updateWith:firstToLastDigest length:(CC_LONG)strlen(firstToLastDigest)]; outputBuffer = [hash final];但我得到不同的结果。

在这一点上,我对为什么它们获得不同的值没有其他想法,因此欢迎任何形式的指导或建议。

4

1 回答 1

1

在扯掉我的头发 4 天后回答我自己的问题。

似乎 CommonCrypto 的 CC_SHA1_Final() 并没有重置CC_SHA1_CTX对象上下文,尽管苹果文档说明它会导致输出差异。

来自 Apple 文档:https ://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/CC_SHA1_Final.3cc.html

CC_SHA1_Final() 将消息摘要放在 md 中,它必须为 CC_SHA1_DIGEST_LENGTH == 20 字节的输出留出空间,并擦除 CC_SHA1_CTX。

我必须编辑 nv-ios-digest 库并手动重置CC_SHA1_CTX每个- (unsigned char *)final方法中的对象,如下所示:

- (unsigned char *)final
{
    CC_SHA1_Final(_digest, &_context);  // <-- _context does not reset
    CC_SHA1_Init(&_context);  // <-- manually reset the CC_SHA1_CTX object

    _description = [NSString stringWithFormat:
                    @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
                    _digest[ 0], _digest[ 1], _digest[ 2], _digest[ 3],
                    _digest[ 4], _digest[ 5], _digest[ 6], _digest[ 7],
                    _digest[ 8], _digest[ 9], _digest[10], _digest[11],
                    _digest[12], _digest[13], _digest[14], _digest[15],
                    _digest[16], _digest[17], _digest[18], _digest[19]];

    return _digest;
}

希望这可以帮助某人。:)

于 2016-02-05T11:51:52.383 回答