Created
June 14, 2011 06:59
-
-
Save hungryblank/1024451 to your computer and use it in GitHub Desktop.
hmac 256 implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%%%------------------------------------------------------------------- | |
%%% File : hmac256.erl | |
%%% Author : Sriram Krishnan<mail@sriramkrishnan.com> | |
%%% Description : HMAC-SHA256 implementation. Implementation based on Wikipedia's | |
%% pseudocode description of HMAC. Relies on Steve Vinoski's SHA256 implementation | |
%%% from http://steve.vinoski.net/code/sha2.erl | |
%%% | |
%%% Created : 30 Dec 2008 | |
%%%------------------------------------------------------------------- | |
%% @private | |
-module(hmac256). | |
-export([hexdigest/2,digest/2,digest_bin/2]). | |
-export([unhex/1]). | |
-version(1.0). | |
-spec hexdigest(string()|binary(),string()|binary()) -> string(). | |
hexdigest(Key, Data)-> | |
digest(Key, Data, true). | |
sha256_str(Payload) -> | |
[ hd(integer_to_list(I, 16)) || << I:4 >> <= erlsha2:sha256(Payload) ]. | |
-spec digest(string()|binary(),string()|binary()) -> string(). | |
digest(Key, Data) -> | |
digest(Key, Data, false). | |
digest_bin(Key, Data) -> | |
list_to_binary(digest(Key,Data)). | |
digest(Key, Data, Hex) when is_binary(Key) -> | |
digest(binary_to_list(Key), Data, Hex); | |
digest(Key, Data, Hex) when is_binary(Data) -> | |
digest(Key, binary_to_list(Data), Hex); | |
digest(Key, Data, Hex) when is_list(Key) and is_list(Data) -> | |
BlockSize = 64, | |
%% Initialize OPad and IPad arrays filled with magic 0x5c and 0x36 values | |
%% respectively. The arrays need to be of the same size as the block length | |
OPad = array:new( [{size,BlockSize},{fixed,true},{default,92}]), | |
IPad = array:new ( [{size,BlockSize},{fixed,true},{default,54}]), | |
%% If key is longer than block size, hash it to bring it below block size | |
if | |
length(Key)>BlockSize -> ShortHashKey = array:from_list(unhex(sha256_str(Key),[])); | |
true-> ShortHashKey = array:from_list(Key) | |
end, | |
HashKey = array:resize(BlockSize, ShortHashKey), %% Zero-pad array | |
PadUpdateFunc = fun (Index, Term) -> | |
KeyTerm = array:get(Index, HashKey), | |
if | |
KeyTerm=:= undefined -> Term bxor 0; | |
true -> Term bxor KeyTerm | |
end | |
end, | |
OPadUpdated = array:map(PadUpdateFunc, OPad), | |
IPadUpdated = array:map(PadUpdateFunc, IPad), | |
FinalTransform = OPadUpdated:to_list() ++ unhex(sha256_str( IPadUpdated:to_list() ++ Data),[]), | |
if | |
Hex =:= true -> sha256_str(FinalTransform); | |
Hex=:= false -> unhex(sha256_str( FinalTransform),[]) | |
end. | |
%% | |
%% Unhex functions adapted from ssl_debug and covered by the Erlang public license | |
%% | |
is_hex_digit(C) when C >= $0, C =< $9 -> true; | |
is_hex_digit(C) when C >= $A, C =< $F -> true; | |
is_hex_digit(C) when C >= $a, C =< $f -> true; | |
is_hex_digit(_) -> false. | |
-spec unhex(string()) -> string(). | |
unhex(S) -> unhex(S, []). | |
unhex([], Acc) -> | |
lists:reverse(Acc); | |
unhex([_], Acc) -> | |
unhex([], Acc); | |
unhex([$ | Tl], Acc) -> | |
unhex(Tl, Acc); | |
unhex([D1, D2 | Tl], Acc) -> | |
case {is_hex_digit(D1), is_hex_digit(D2)} of | |
{true, true} -> | |
unhex(Tl, [erlang:list_to_integer([D1, D2], 16) | Acc]); | |
_ -> | |
unhex([], Acc) | |
end. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks!