Skip to content

Instantly share code, notes, and snippets.

@hungryblank
Created June 14, 2011 06:59
Show Gist options
  • Save hungryblank/1024451 to your computer and use it in GitHub Desktop.
Save hungryblank/1024451 to your computer and use it in GitHub Desktop.
hmac 256 implementation
%%%-------------------------------------------------------------------
%%% 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.
@sebastian
Copy link

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment