erlang的base64解码问题
Posted 莫行
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了erlang的base64解码问题相关的知识,希望对你有一定的参考价值。
在收到客户端的数字签名signature后,需要对signature做base64的解码。代码如下所示:
1 validate(SignedRequest) ->
2 RequestParts = string:split(SignedRequest, "."),%% 数字签名+‘.‘+algorithm, player_id等信息
3 Part1Original = lists:nth(1, RequestParts),
4
5 Rem = byte_size(Part1Original) rem 4,
6 Suffix = case Rem of
7 2 -> "==";
8 3 -> "="
9 end,
10 Part1AppendSuffix = unicode:characters_to_binary([Part1Original, Suffix]), %% 填充‘=‘
11 Part1Replaced1 = unicode:characters_to_binary(string:replace((Part1AppendSuffix), <<"-">>, <<"+">>, all), utf8), %% 替换‘-‘为‘+‘
12 Part1Replaced2 = unicode:characters_to_binary(string:replace(Part1Replaced1, <<"_">>, <<"/">>, all), utf8), %% 替换‘_‘为‘/‘
13 Signature = base64:decode(Part1Replaced2),
14
15 DataHash = crypto:hmac(sha256, <<YOUR_APP_SECERT>>, lists:nth(2, RequestParts)),
16 case Signature =:= DataHash of
17 true -> success;
18 false -> failure
19 end.
向signature尾部追加‘=‘的操作是Facebook官方示例中所没有的,Facebook示例在javascript的环境中测试时也是正常的,但是在erlang中调用base64:decode()时,若不做此追加处理,总是在最后的环节无法匹配前三个字节。无奈,根据报错提示找来base64.erl的对应代码,如下:
1 decode([], A) -> A;
2 decode([$=,$=,C2,C1|Cs], A) ->
3 Bits2x6 = (b64d(C1) bsl 18) bor (b64d(C2) bsl 12),
4 Octet1 = Bits2x6 bsr 16,
5 decode(Cs, [Octet1|A]);
6 decode([$=,C3,C2,C1|Cs], A) ->
7 Bits3x6 = (b64d(C1) bsl 18) bor (b64d(C2) bsl 12)
8 bor (b64d(C3) bsl 6),
9 Octet1 = Bits3x6 bsr 16,
10 Octet2 = (Bits3x6 bsr 8) band 16#ff,
11 decode(Cs, [Octet1,Octet2|A]);
12 decode([C4,C3,C2,C1| Cs], A) ->
13 Bits4x6 = (b64d(C1) bsl 18) bor (b64d(C2) bsl 12)
14 bor (b64d(C3) bsl 6) bor b64d(C4),
15 Octet1 = Bits4x6 bsr 16,
16 Octet2 = (Bits4x6 bsr 8) band 16#ff,
17 Octet3 = Bits4x6 band 16#ff,
18 decode(Cs, [Octet1,Octet2,Octet3|A]).
可以看到,它只匹配4种情形,而报错时剩余前3个字节无法匹配(注意是逆序处理的),可以推定被解码的字节数不足。这里一篇博客对Base64有很清晰的讲解:
http://www.ruanyifeng.com/blog/2008/06/base64.html
在加密前,字节数组是每3个字节为一组被编码为4个字节的。当剩余字节数不足3时,有剩余1个字节和2个字节两种情形,前者被编码为2个字节,需要向尾部追加"==",后者被编码为3个字节,需要向尾部追加"="。而erlang这里报错时,我统计了签名的字节数,是不能被4整除的。因此先判断字节数,并据字节数追加相应的‘=‘,并测试成功。
使用JavaScript的库crypto-js测试时没有出现此问题,猜想其内部可能根据字节数做了追加处理,具体就不再深究了。
以上是关于erlang的base64解码问题的主要内容,如果未能解决你的问题,请参考以下文章