effbe57e创建于 2024年11月25日历史提交
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2024. All rights reserved.
 */
package zip4cj.crypto.PBKDF2

public class PBKDF2Engine {
    private var parameters: PBKDF2Parameters

    private var prf: ?PRF

    public init(parameters: PBKDF2Parameters) {
        this(parameters, None)
    }

    public init(parameters: PBKDF2Parameters, prf: ?PRF) {
        this.parameters = parameters
        this.prf = prf
    }

    public func deriveKey(inputPassword: Array<Rune>, dkLen: Int64, useUtf8ForPassword: Bool): Array<Byte> {
        var p: Array<Byte> = Zip4cjUtil.convertCharArrayToByteArray(inputPassword, useUtf8ForPassword)
        
        assertPRF(p)
        var dklength = dkLen
        if (dklength == 0) {
            dklength = prf.getOrThrow().getHLen()
        }
        return PBKDF2(prf.getOrThrow(), parameters.getSalt(), parameters.getIterationCount(), dkLen)
    } 

    private func assertPRF(P: Array<Byte>): Unit {
        if (prf.isNone()) {
            prf = MacBasedPRF(parameters.getHashAlgorithm())
        }
        this.prf?.initialize(P)
    }

    private func PBKDF2(prf: PRF, S: Array<Byte>, c: Int32, dkLen: Int64): Array<Byte> {
        var hLen = prf.getHLen()
        var l = ceil(dkLen, hLen)
        var r = dkLen - (l - 1) * hLen
        var T = Array<Byte>(Int64(l * hLen), repeat: 0)
        var ti_offset: Int64 = 0
        for (i in 1..=l) {
            _F(T, ti_offset, prf, S, c, i)
            ti_offset += hLen
        }
        if (r < hLen) {
            // Incomplete last block
            let DK = Array<Byte>(dkLen, repeat: 0)
            T.copyTo(DK, 0, 0, dkLen)
            return DK
        }
        return T
    }

    private func ceil(a: Int64, b: Int64): Int64 {
        var m: Int64 = 0
        if (a % b > 0) {
            m = 1
        }
        return a / b + m
    }

    private func _F(dest: Array<Byte>, offset: Int64, prf: PRF, S: Array<Byte>, c: Int32, blockIndex: Int64): Unit {
        var hLen = prf.getHLen()
        var U_r = Array<Byte> (Int64(hLen), repeat: 0)

        // U0 = S || INT (i)
        var U_i = Array<Byte>(S.size + 4, repeat: 0)
        S.copyTo(U_i, 0, 0, S.size)
        
        INT(U_i, S.size, blockIndex)

        for (_ in 0..c) {
            U_i = prf.doFinal(U_i)
            xor(U_r, U_i)
        }
        U_r.copyTo(dest, 0, offset, hLen)
    }

    private func xor(dest: Array<Byte>, src: Array<Byte>): Unit {
        for (i in 0..dest.size) {
            dest[i] ^= src[i]
        }
    }

    @OverflowWrapping
    protected func INT(dest: Array<Byte>, offset: Int64, i: Int64): Unit {
        dest[offset] = UInt8(i / (256 * 256 * 256))
        dest[offset + 1] = UInt8(i / (256 * 256))
        dest[offset + 2] = UInt8(i / (256))
        dest[offset + 3] = UInt8(i)
    }

    public func getParameters(): PBKDF2Parameters {
        return parameters
    }

    public func setParameters(parameters: PBKDF2Parameters): Unit {
        this.parameters = parameters
    }

    public func setPseudoRandomFunction(prf: PRF): Unit {
        this.prf = prf
    }
}