You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2014/12/04 21:09:46 UTC
[15/22] couch commit: updated
refs/heads/2491-refactor-couch-httpd-auth to 3e8286d
TOTP secrets are stored in Base32
Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/bfbf8ebe
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/bfbf8ebe
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/bfbf8ebe
Branch: refs/heads/2491-refactor-couch-httpd-auth
Commit: bfbf8ebed19ba511fc50f916f3fd41cea84e815f
Parents: 6125862
Author: Robert Newson <rn...@apache.org>
Authored: Sun Nov 2 17:15:49 2014 +0000
Committer: Robert Newson <rn...@apache.org>
Committed: Sun Nov 2 18:09:18 2014 +0000
----------------------------------------------------------------------
src/couch_base32.erl | 127 +++++++++++++++++++++++++++++++++++++++
src/couch_httpd_auth.erl | 2 +-
test/couch_base32_tests.erl | 28 +++++++++
3 files changed, 156 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/bfbf8ebe/src/couch_base32.erl
----------------------------------------------------------------------
diff --git a/src/couch_base32.erl b/src/couch_base32.erl
new file mode 100644
index 0000000..d8d754f
--- /dev/null
+++ b/src/couch_base32.erl
@@ -0,0 +1,127 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+% http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couch_base32).
+
+-export([encode/1, decode/1]).
+
+-define(SET, <<"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567">>).
+
+
+-spec encode(binary()) -> binary().
+encode(Plain) when is_binary(Plain) ->
+ IoList = encode(Plain, 0, byte_size(Plain) * 8, []),
+ iolist_to_binary(lists:reverse(IoList)).
+
+encode(_Plain, _ByteOffset, 0, Acc) ->
+ Acc;
+
+encode(Plain, ByteOffset, BitsRemaining, Acc) when BitsRemaining == 8 ->
+ <<A:5, B:3>> = binary:part(Plain, ByteOffset, 1),
+ [<<(binary:at(?SET, A)),
+ (binary:at(?SET, B bsl 2)),
+ "======">> | Acc];
+
+encode(Plain, ByteOffset, BitsRemaining, Acc) when BitsRemaining == 16 ->
+ <<A:5, B:5, C:5, D:1>> = binary:part(Plain, ByteOffset, 2),
+ [<<(binary:at(?SET, A)),
+ (binary:at(?SET, B)),
+ (binary:at(?SET, C)),
+ (binary:at(?SET, D bsl 4)),
+ "====">> | Acc];
+
+encode(Plain, ByteOffset, BitsRemaining, Acc) when BitsRemaining == 24 ->
+ <<A:5, B:5, C:5, D:5, E:4>> = binary:part(Plain, ByteOffset, 3),
+ [<<(binary:at(?SET, A)),
+ (binary:at(?SET, B)),
+ (binary:at(?SET, C)),
+ (binary:at(?SET, D)),
+ (binary:at(?SET, E bsl 1)),
+ "===">> | Acc];
+
+encode(Plain, ByteOffset, BitsRemaining, Acc) when BitsRemaining == 32 ->
+ <<A:5, B:5, C:5, D:5, E:5, F:5, G:2>> = binary:part(Plain, ByteOffset, 4),
+ [<<(binary:at(?SET, A)),
+ (binary:at(?SET, B)),
+ (binary:at(?SET, C)),
+ (binary:at(?SET, D)),
+ (binary:at(?SET, E)),
+ (binary:at(?SET, F)),
+ (binary:at(?SET, G bsl 3)),
+ "=">> | Acc];
+
+encode(Plain, ByteOffset, BitsRemaining, Acc) when BitsRemaining >= 40 ->
+ <<A:5, B:5, C:5, D:5, E:5, F:5, G:5, H:5>> =
+ binary:part(Plain, ByteOffset, 5),
+ Output = <<(binary:at(?SET, A)),
+ (binary:at(?SET, B)),
+ (binary:at(?SET, C)),
+ (binary:at(?SET, D)),
+ (binary:at(?SET, E)),
+ (binary:at(?SET, F)),
+ (binary:at(?SET, G)),
+ (binary:at(?SET, H))>>,
+ encode(Plain, ByteOffset + 5, BitsRemaining - 40, [Output | Acc]).
+
+
+-spec decode(binary()) -> binary().
+decode(Encoded) when is_binary(Encoded) ->
+ IoList = decode(Encoded, 0, []),
+ iolist_to_binary(lists:reverse(IoList)).
+
+decode(Encoded, ByteOffset, Acc) when ByteOffset == byte_size(Encoded) ->
+ Acc;
+decode(Encoded, ByteOffset, Acc) ->
+ case binary:part(Encoded, ByteOffset, 8) of
+ <<A:1/binary, B:1/binary, "======">> ->
+ [<<(find_in_set(A)):5,
+ (find_in_set(B) bsr 2):3>> | Acc];
+ <<A:1/binary, B:1/binary, C:1/binary, D:1/binary, "====">> ->
+ [<<(find_in_set(A)):5,
+ (find_in_set(B)):5,
+ (find_in_set(C)):5,
+ (find_in_set(D) bsr 4):1>> | Acc];
+ <<A:1/binary, B:1/binary, C:1/binary, D:1/binary, E:1/binary, "===">> ->
+ [<<(find_in_set(A)):5,
+ (find_in_set(B)):5,
+ (find_in_set(C)):5,
+ (find_in_set(D)):5,
+ (find_in_set(E) bsr 1):4>> | Acc];
+ <<A:1/binary, B:1/binary, C:1/binary, D:1/binary,
+ E:1/binary, F:1/binary, G:1/binary, "=">> ->
+ [<<(find_in_set(A)):5,
+ (find_in_set(B)):5,
+ (find_in_set(C)):5,
+ (find_in_set(D)):5,
+ (find_in_set(E)):5,
+ (find_in_set(F)):5,
+ (find_in_set(G) bsr 3):2>> | Acc];
+ <<A:1/binary, B:1/binary, C:1/binary, D:1/binary,
+ E:1/binary, F:1/binary, G:1/binary, H:1/binary>> ->
+ decode(Encoded, ByteOffset + 8,
+ [<<(find_in_set(A)):5,
+ (find_in_set(B)):5,
+ (find_in_set(C)):5,
+ (find_in_set(D)):5,
+ (find_in_set(E)):5,
+ (find_in_set(F)):5,
+ (find_in_set(G)):5,
+ (find_in_set(H)):5>> | Acc])
+ end.
+
+find_in_set(Char) ->
+ case binary:match(?SET, Char) of
+ nomatch ->
+ erlang:error(not_base32);
+ {Offset, _} ->
+ Offset
+ end.
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/bfbf8ebe/src/couch_httpd_auth.erl
----------------------------------------------------------------------
diff --git a/src/couch_httpd_auth.erl b/src/couch_httpd_auth.erl
index cda51c5..5e528d9 100644
--- a/src/couch_httpd_auth.erl
+++ b/src/couch_httpd_auth.erl
@@ -448,7 +448,7 @@ verify_totp(User, Form) ->
undefined ->
ok;
{Props} ->
- Key = couch_util:get_value(<<"key">>, Props),
+ Key = couch_base32:decode(couch_util:get_value(<<"key">>, Props)),
Alg = couch_util:to_existing_atom(
couch_util:get_value(<<"algorithm">>, Props, <<"sha">>)),
Len = couch_util:get_value(<<"length">>, Props, 6),
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/bfbf8ebe/test/couch_base32_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_base32_tests.erl b/test/couch_base32_tests.erl
new file mode 100644
index 0000000..7e4d59a
--- /dev/null
+++ b/test/couch_base32_tests.erl
@@ -0,0 +1,28 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+% http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couch_base32_tests).
+
+-include_lib("eunit/include/eunit.hrl").
+
+base32_test() ->
+ roundtrip(<<"">>, <<"">>),
+ roundtrip(<<"f">>, <<"MY======">>),
+ roundtrip(<<"fo">>, <<"MZXQ====">>),
+ roundtrip(<<"foo">>, <<"MZXW6===">>),
+ roundtrip(<<"foob">>, <<"MZXW6YQ=">>),
+ roundtrip(<<"fooba">>, <<"MZXW6YTB">>),
+ roundtrip(<<"foobar">>, <<"MZXW6YTBOI======">>).
+
+roundtrip(Plain, Encoded) ->
+ ?assertEqual(Plain, couch_base32:decode(Encoded)),
+ ?assertEqual(Encoded, couch_base32:encode(Plain)).