-module(utools). -export([b32_decode/1]). -export([b32_encode/1]). -export([hex_encode/1]). -export([hotp/2]). -export([rand_bytes/0, rand_bytes/1]). -export([rand_chars/1]). -export([rand_hash/0]). -export([sha256/1]). -export([totp/1, totp/2]). -export([totp_check/2]). -export([totp_generate/0]). b32_decode({<>, Bits}) -> <>; b32_decode({<>, Bits}) -> <>; b32_decode({<>, Bits}) -> <>; b32_decode({<>) -> binary:list_to_bin(lists:flatten(io_lib:format("~40.16.0b", [X]))); hex_encode(<>) -> binary:list_to_bin(lists:flatten(io_lib:format("~64.16.0b", [X]))). hotp(Token, Time) -> K = b32_decode(Token), M = <>, D = crypto:mac(hmac, sha, K, M), <<_:19/binary, _O:8>> = D, O = _O band 15, <<_TB:4/integer-unit:8>> = binary:part(D, O, 4), TB = _TB band 16#7fffffff, _T = TB rem trunc(math:pow(10, 6)), T = integer_to_binary(_T), P = << <<48:8>> || _ <- lists:seq(1, 6 - byte_size(T)) >>, {ok, <

>}. rand_bytes() -> rand_bytes(8). rand_bytes(N) when is_integer(N) -> {ok, crypto:strong_rand_bytes(N)}. rand_chars({0, Swap}) -> {ok, Swap}; rand_chars({Size, <>}) when Size > 0 -> Char = rand:uniform(26) + 96, rand_chars({Size - 1, <>}); rand_chars(Size) when Size > 0 -> rand_chars({Size, <<"">>}). rand_hash() -> {ok, R} = rand_chars(64), {ok, sha256(<<"utools:rand_hash(", R/binary, ")">>)}. sha256(<>) -> hex_encode(crypto:hash(sha256, Data)). totp(<>) -> totp(Secret, erlang:timestamp()). totp(<>, {M, S, _}) -> T = (M * 1000000 + S) / 30, Time = trunc(T), hotp(Secret, Time). totp_check(<>, <>) -> {M, S, _} = erlang:timestamp(), TL = [totp(Secret, {M, S - 30, 0}), totp(Secret, {M, S, 0}), totp(Secret, {M, S + 30, 0})], {ok, lists:member({ok, Token}, TL)}. totp_generate() -> rand_chars(16).