From: Tim Fletcher <mail@tfletcher.com>
Date: Wed, 18 Sep 2013 17:57:06 +0100
Subject: [PATCH] Replace runtime switching with parse_transform rewriting of
crypto:hmac/3
diff --git a/Emakefile b/Emakefile
index a961122..9665af7 100644
--- a/Emakefile
+++ b/Emakefile
@@ -1 +1,3 @@
-{"src/*", [debug_info, warn_unused_vars, warn_unused_import, {outdir, "ebin"}]}.
\ No newline at end of file
+{"src/crypto_sha_mac.erl", []}.
+
+{"src/oauth.erl", [debug_info, warn_unused_vars, warn_unused_import, {outdir, "ebin"}, {parse_transform, crypto_sha_mac}]}.
diff --git a/Makefile b/Makefile
index e4b31b9..b9310b3 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
all: clean compile
clean:
- @rm -rf ebin/*.beam
+ @rm -rf ebin/*.beam *.beam
compile:
@test -d ebin || mkdir ebin
diff --git a/src/crypto_sha_mac.erl b/src/crypto_sha_mac.erl
new file mode 100644
index 0000000..1eb917f
--- /dev/null
+++ b/src/crypto_sha_mac.erl
@@ -0,0 +1,29 @@
+-module(crypto_sha_mac).
+
+-export([parse_transform/2]).
+
+parse_transform(Forms, _Options) ->
+ application:load(crypto),
+ crypto:start(),
+ case erlang:function_exported(crypto, hmac, 3) of
+ true ->
+ Forms;
+ false ->
+ io:format("Rewriting crypto:hmac/3 calls with crypto_sha_mac parse transform~n", []),
+ lists:map(fun rewrite/1, Forms)
+ end.
+
+rewrite(Function={function, _, _, _, Clauses}) ->
+ setelement(5, Function, recursive_rewrite(Clauses));
+rewrite(Form) ->
+ Form.
+
+recursive_rewrite(Terms) when is_list(Terms) ->
+ lists:map(fun recursive_rewrite/1, Terms);
+recursive_rewrite({call, L1, {remote, L2, {atom, L3, crypto}, {atom, L4, hmac}}, [{atom, _, sha} | Args]}) ->
+ {call, L1, {remote, L2, {atom, L3, crypto}, {atom, L4, sha_mac}}, Args};
+recursive_rewrite(Term) when is_tuple(Term) ->
+ [Type, Line | Elements] = tuple_to_list(Term),
+ list_to_tuple([Type, Line | lists:map(fun recursive_rewrite/1, Elements)]);
+recursive_rewrite(Term) ->
+ Term.
diff --git a/src/oauth.erl b/src/oauth.erl
index d9234f4..d5de04b 100644
--- a/src/oauth.erl
+++ b/src/oauth.erl
@@ -128,7 +128,7 @@ hmac_sha1_signature(HttpMethod, URL, Params, Consumer, TokenSecret) ->
hmac_sha1_signature(BaseString, Consumer, TokenSecret) ->
Key = uri_join([consumer_secret(Consumer), TokenSecret]),
- base64:encode_to_string(hmac_sha(Key, BaseString)).
+ base64:encode_to_string(crypto:hmac(sha, Key, BaseString)).
hmac_sha1_verify(Signature, HttpMethod, URL, Params, Consumer, TokenSecret) ->
verify_in_constant_time(Signature, hmac_sha1_signature(HttpMethod, URL, Params, Consumer, TokenSecret)).
@@ -136,14 +136,6 @@ hmac_sha1_verify(Signature, HttpMethod, URL, Params, Consumer, TokenSecret) ->
hmac_sha1_verify(Signature, BaseString, Consumer, TokenSecret) ->
verify_in_constant_time(Signature, hmac_sha1_signature(BaseString, Consumer, TokenSecret)).
-hmac_sha(Key, Data) ->
- case erlang:function_exported(crypto, hmac, 3) of
- true ->
- crypto:hmac(sha, Key, Data);
- false ->
- crypto:sha_mac(Key, Data)
- end.
-
rsa_sha1_signature(HttpMethod, URL, Params, Consumer) ->
BaseString = signature_base_string(HttpMethod, URL, Params),
rsa_sha1_signature(BaseString, Consumer).