【问题标题】:PBKDF2 Lua Implementation IssuePBKDF2 Lua 实现问题
【发布时间】:2018-11-05 07:03:04
【问题描述】:

我正在尝试用纯 lua 编写一个 PBKDF2 实现。我写它是因为我想在不允许外部库的沙盒 lua 环境中使用它。我查看了来自 IETF 的标准文档,并且已经看过了。以下是我想出的代码:

do
    package.preload["pbkdf2"] = function()

        local hmac = require 'hmac'
        local len = string.len
        local gsub = string.gsub
        local format = string.format
        local byte = string.byte
        local char = string.char
        local concat = table.concat
        local ceil = math.ceil

        local function toBytes(str)
            local tmp = {}
            for i = 1, len(str) do
                tmp[i] = byte(str, i)
            end
            return tmp
        end

        local function toString(bArray)
            local tmp = {}
            for i = 1, #bArray do
                tmp[i] = char(bArray[i])
            end
            tmp = concat(tmp)
            return tmp
        end

        -- transform a string of bytes in a string of hexadecimal digits
        local function asHex(s)
            local h = gsub(s, ".", function(c)
                return format("%02x", byte(c))
            end)
            return h
        end

        local num2string = function(l, n)
            local s = {}
            for i = 1, n do
                local idx = (n + 1) - i
                s[idx] = char(l & 255)
                l = l >> 8
            end
            s = concat(s)
            return s
        end

        local buildBlock = function(hFun, password, salt, c, int)
            local tmp
            local tmp2

            for i = 1, c do
                if i == 1 then
                    print(int)
                    print(salt .. int)
                    -- PRF(password, salt || INT_32_BE(i)
                    -- return result of hash as a byte string
                    tmp = hmac.hash(hFun, password, salt .. num2string(int, 4), true)
                else
                    -- returns result of hash as byte string
                    tmp2 = hmac.hash(hFun, password, tmp, true)
                    -- transform to byte arrays
                    tmp2 = toBytes(tmp2)
                    tmp = toBytes(tmp)
                    assert(#tmp == #tmp2)
                    -- apply XOR over bytes in both arrays
                    -- save results to final array
                    for j = 1, #tmp do
                        -- perform XOR operation on both elements in the respective arrays
                        tmp[j] = tmp[j] ~ tmp2[j]
                    end
                    -- transform back into byte string to pass to next hash
                    tmp = toString(tmp)
                end
            end
            return tmp
        end

        local truncate = function(str, pos)
            return string.sub(str, 1, pos)
        end

        local deriveKey = function(hFun, message, salt, c, dLen)
            local hLen = hFun.outputSize

            -- the derived key cannot be larger than (2^32 * hLen)
            if dLen > (2^32) * hLen then error("The derived key cannot be larger than 2^32 times the output size of the hash function.") end

            -- the block size is the desired key length divided by the output size of the underlying hash function, rounded up
            local blockSize = ceil(dLen/hLen)

            -- to store our blocks
            local final = {}

            for i = 1, blockSize do
                -- lets make our blocks in here
                final[i] = buildBlock(hFun, message, salt, c, i)
            end

            local result
            if #final == 1 then
                result = final[1] -- we only have one block
            else
                result = concat(final) -- turns final into a bytestring to be outputted
            end
            --if #result > dLen then truncate(final, dLen) end
            assert(#result == dLen)
            return asHex(result) -- outputs as a hex value
        end
        return {deriveKey = deriveKey}
    end
end

此代码未得到正确答案。用here提供的测试向量测试这段代码,假设底层PRF是HMAC-SHA256,输出如下:

key: "password"
salt: "salt"
c: 1
dkLen: 32

Got: 13463842ec330934dc124494b40d8baade465b72f3fcadad741f2d0e052fd2f5
Expected: 120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b

key: "password"
salt: "salt"
c: 2
dkLen: 32

Got: 8b82aed26f503effdbc6c14bc7f0338b2b90e387f14ac1f91f9ad74e618f9558
Expected: AE4D0C95AF6B46D32D0ADFF928F06DD02A303F8EF3C251DFD6E2D85A95474C43

我相信这可能与字符串到字节的编码有关,但我无法确定究竟是什么导致了这个问题。当我测试我的 HMAC 代码时,我不得不依赖在线生成器,因为我找不到 HMAC-SHA224 和 HMAC-SHA256 的向量。对于相同的键、消息组合,一些计算器会给我完全不同的输出值。这可能是因为他们如何处理输入,但我不确定。如果有更有经验的人能帮我解决这个问题,我将不胜感激。

编辑:这个问题解决了。似乎只需要将 int 作为长度为 4 的二进制字符串传递。我用修复程序更新了代码。

编辑 2:我再次阅读标准以意识到解决方案一直在我面前(标准将 i 编码为 32 位大端整数)。

【问题讨论】:

  • 这条线很奇怪if #result > dLen then truncate(final, dLen) end
  • 我的意思是删除那行 @EgorSkriptunoff 它和 truncate 方法本身对上述问题没有任何影响。
  • 表达式salt .. int 看起来很可疑:您正在将整数转换为其十进制表示,并将此字符串与“salt”连接起来。
  • @EgorSkriptunoff 打印 salt .. int 的值会在 int = 1 时给出“salt1”,实际上传入“salt1.0”会为 PBKDF 提供不同的答案,但是一个仍然不正确的。在 int 上使用 math.floor 和 tostring 也不会改变事情。感谢您迄今为止的帮助。
  • 您应该计算 salt..num2string(int, 4) 代替(将 int 转换为长度为 4 的 big-endian 二进制字符串)

标签: lua sha256 hmac pbkdf2


【解决方案1】:

解决方案是将 int 转换为长度为 4 的二进制字符串。感谢@EgorSkriptunoff 的洞察力。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-07
    • 2016-05-24
    • 1970-01-01
    • 2011-05-29
    • 2011-12-11
    • 2012-07-22
    • 1970-01-01
    • 2012-03-18
    相关资源
    最近更新 更多