167 lines
6.2 KiB
VimL
167 lines
6.2 KiB
VimL
" This is a port of rfc2104 hmac function.
|
|
" http://www.ietf.org/rfc/rfc2104.txt
|
|
" Last Change: 2010-02-13
|
|
" Maintainer: Yukihiro Nakadaira <yukihiro.nakadaira@gmail.com>
|
|
" License: This file is placed in the public domain.
|
|
|
|
" @param mixed key List or String
|
|
" @param mixed text List or String
|
|
" @param Funcref hash function digest_hex(key:List, text:List):String
|
|
" @param Number blocksize
|
|
function webapi#hmac#hmac(key, text, hash, blocksize)
|
|
let key = (type(a:key) == type("")) ? s:str2bytes(a:key) : a:key
|
|
let text = (type(a:text) == type("")) ? s:str2bytes(a:text) : a:text
|
|
return s:Hmac(key, text, a:hash, a:blocksize)
|
|
endfunction
|
|
|
|
function webapi#hmac#md5(key, text)
|
|
return webapi#hmac#hmac(a:key, a:text, 'webapi#md5#md5bin', 64)
|
|
endfunction
|
|
|
|
function webapi#hmac#sha1(key, text)
|
|
return webapi#hmac#hmac(a:key, a:text, 'webapi#sha1#sha1bin', 64)
|
|
endfunction
|
|
|
|
" http://www.ietf.org/rfc/rfc2202.txt
|
|
" Test Cases for HMAC-MD5 and HMAC-SHA-1
|
|
function webapi#hmac#test()
|
|
" Test Cases for HMAC-MD5
|
|
call s:test("md5: 1", "webapi#hmac#md5",
|
|
\ repeat("\x0b", 16),
|
|
\ "Hi There",
|
|
\ "9294727a3638bb1c13f48ef8158bfc9d")
|
|
call s:test("md5: 2", "webapi#hmac#md5",
|
|
\ "Jefe",
|
|
\ "what do ya want for nothing?",
|
|
\ "750c783e6ab0b503eaa86e310a5db738")
|
|
call s:test("md5: 3", "webapi#hmac#md5",
|
|
\ repeat("\xaa", 16),
|
|
\ repeat("\xdd", 50),
|
|
\ "56be34521d144c88dbb8c733f0e8b3f6")
|
|
call s:test("md5: 4", "webapi#hmac#md5",
|
|
\ s:hex2bytes("0102030405060708090a0b0c0d0e0f10111213141516171819"),
|
|
\ repeat([0xcd], 50),
|
|
\ "697eaf0aca3a3aea3a75164746ffaa79")
|
|
call s:test("md5: 5", "webapi#hmac#md5",
|
|
\ repeat("\x0c", 16),
|
|
\ "Test With Truncation",
|
|
\ "56461ef2342edc00f9bab995690efd4c")
|
|
call s:test("md5: 6", "webapi#hmac#md5",
|
|
\ repeat("\xaa", 80),
|
|
\ "Test Using Larger Than Block-Size Key - Hash Key First",
|
|
\ "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd")
|
|
call s:test("md5: 7", "webapi#hmac#md5",
|
|
\ repeat("\xaa", 80),
|
|
\ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
|
|
\ "6f630fad67cda0ee1fb1f562db3aa53e")
|
|
|
|
" Test Cases for HMAC-SHA1
|
|
call s:test("sha1: 1", "webapi#hmac#sha1",
|
|
\ repeat("\x0b", 20),
|
|
\ "Hi There",
|
|
\ "b617318655057264e28bc0b6fb378c8ef146be00")
|
|
call s:test("sha1: 2", "webapi#hmac#sha1",
|
|
\ "Jefe",
|
|
\ "what do ya want for nothing?",
|
|
\ "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79")
|
|
call s:test("sha1: 3", "webapi#hmac#sha1",
|
|
\ repeat("\xaa", 20),
|
|
\ repeat("\xdd", 50),
|
|
\ "125d7342b9ac11cd91a39af48aa17b4f63f175d3")
|
|
call s:test("sha1: 4", "webapi#hmac#sha1",
|
|
\ s:hex2bytes("0102030405060708090a0b0c0d0e0f10111213141516171819"),
|
|
\ repeat([0xcd], 50),
|
|
\ "4c9007f4026250c6bc8414f9bf50c86c2d7235da")
|
|
call s:test("sha1: 5", "webapi#hmac#sha1",
|
|
\ repeat("\x0c", 20),
|
|
\ "Test With Truncation",
|
|
\ "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04")
|
|
call s:test("sha1: 6", "webapi#hmac#sha1",
|
|
\ repeat("\xaa", 80),
|
|
\ "Test Using Larger Than Block-Size Key - Hash Key First",
|
|
\ "aa4ae5e15272d00e95705637ce8a3b55ed402112")
|
|
call s:test("sha1: 7", "webapi#hmac#sha1",
|
|
\ repeat("\xaa", 80),
|
|
\ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
|
|
\ "e8e99d0f45237d786d6bbaa7965c7808bbff1a91")
|
|
endfunction
|
|
|
|
function s:test(name, func, key, data, digest)
|
|
let result = call(a:func, [a:key, a:data])
|
|
echo "test_case:" a:name
|
|
echo "expect:" a:digest
|
|
echo "result:" result
|
|
if a:digest ==? result
|
|
echo "test: OK"
|
|
else
|
|
echohl Error
|
|
echo "test: NG"
|
|
echohl None
|
|
endif
|
|
endfunction
|
|
|
|
" @param List key
|
|
" @param List text
|
|
" @param Funcref hash
|
|
" @param Number blocksize
|
|
function! s:Hmac(key, text, hash, blocksize)
|
|
let key = a:key
|
|
if len(key) > a:blocksize
|
|
let key = s:hex2bytes(call(a:hash, [key]))
|
|
endif
|
|
let k_ipad = repeat([0], a:blocksize)
|
|
let k_opad = repeat([0], a:blocksize)
|
|
for i in range(a:blocksize)
|
|
let k_ipad[i] = s:bitwise_xor(get(key, i, 0), 0x36)
|
|
let k_opad[i] = s:bitwise_xor(get(key, i, 0), 0x5c)
|
|
endfor
|
|
let hash1 = s:hex2bytes(call(a:hash, [k_ipad + a:text]))
|
|
let hmac = call(a:hash, [k_opad + hash1])
|
|
return hmac
|
|
endfunction
|
|
|
|
function! s:str2bytes(str)
|
|
return map(range(len(a:str)), 'char2nr(a:str[v:val])')
|
|
endfunction
|
|
|
|
function! s:hex2bytes(str)
|
|
return map(split(a:str, '..\zs'), 'str2nr(v:val, 16)')
|
|
endfunction
|
|
|
|
let s:xor = [
|
|
\ [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF],
|
|
\ [0x1, 0x0, 0x3, 0x2, 0x5, 0x4, 0x7, 0x6, 0x9, 0x8, 0xB, 0xA, 0xD, 0xC, 0xF, 0xE],
|
|
\ [0x2, 0x3, 0x0, 0x1, 0x6, 0x7, 0x4, 0x5, 0xA, 0xB, 0x8, 0x9, 0xE, 0xF, 0xC, 0xD],
|
|
\ [0x3, 0x2, 0x1, 0x0, 0x7, 0x6, 0x5, 0x4, 0xB, 0xA, 0x9, 0x8, 0xF, 0xE, 0xD, 0xC],
|
|
\ [0x4, 0x5, 0x6, 0x7, 0x0, 0x1, 0x2, 0x3, 0xC, 0xD, 0xE, 0xF, 0x8, 0x9, 0xA, 0xB],
|
|
\ [0x5, 0x4, 0x7, 0x6, 0x1, 0x0, 0x3, 0x2, 0xD, 0xC, 0xF, 0xE, 0x9, 0x8, 0xB, 0xA],
|
|
\ [0x6, 0x7, 0x4, 0x5, 0x2, 0x3, 0x0, 0x1, 0xE, 0xF, 0xC, 0xD, 0xA, 0xB, 0x8, 0x9],
|
|
\ [0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, 0xF, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8],
|
|
\ [0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7],
|
|
\ [0x9, 0x8, 0xB, 0xA, 0xD, 0xC, 0xF, 0xE, 0x1, 0x0, 0x3, 0x2, 0x5, 0x4, 0x7, 0x6],
|
|
\ [0xA, 0xB, 0x8, 0x9, 0xE, 0xF, 0xC, 0xD, 0x2, 0x3, 0x0, 0x1, 0x6, 0x7, 0x4, 0x5],
|
|
\ [0xB, 0xA, 0x9, 0x8, 0xF, 0xE, 0xD, 0xC, 0x3, 0x2, 0x1, 0x0, 0x7, 0x6, 0x5, 0x4],
|
|
\ [0xC, 0xD, 0xE, 0xF, 0x8, 0x9, 0xA, 0xB, 0x4, 0x5, 0x6, 0x7, 0x0, 0x1, 0x2, 0x3],
|
|
\ [0xD, 0xC, 0xF, 0xE, 0x9, 0x8, 0xB, 0xA, 0x5, 0x4, 0x7, 0x6, 0x1, 0x0, 0x3, 0x2],
|
|
\ [0xE, 0xF, 0xC, 0xD, 0xA, 0xB, 0x8, 0x9, 0x6, 0x7, 0x4, 0x5, 0x2, 0x3, 0x0, 0x1],
|
|
\ [0xF, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0]
|
|
\ ]
|
|
|
|
function! s:bitwise_xor(a, b)
|
|
let a = a:a < 0 ? a:a - 0x80000000 : a:a
|
|
let b = a:b < 0 ? a:b - 0x80000000 : a:b
|
|
let r = 0
|
|
let n = 1
|
|
while a || b
|
|
let r += s:xor[a % 0x10][b % 0x10] * n
|
|
let a = a / 0x10
|
|
let b = b / 0x10
|
|
let n = n * 0x10
|
|
endwhile
|
|
if (a:a < 0) != (a:b < 0)
|
|
let r += 0x80000000
|
|
endif
|
|
return r
|
|
endfunction
|
|
|