Blob Blame History Raw
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).