Я пытаюсь написать реализацию PBKDF2 на чистом языке lua.Я пишу это, потому что я хочу использовать его в изолированной среде 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
Этот код не дает правильных ответов.Тестирование этого кода с помощью тестовых векторов, предоставленных здесь , при условии, что базовым 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: Я снова прочитал стандарт, чтобы реализовать решениебыл у меня в лицо все время (стандарт говорит, чтобы закодировать меня как 32-разрядное целое число с прямым порядком байтов).