• 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测试时没有出现此问题,猜想其内部可能根据字节数做了追加处理,具体就不再深究了。

  • 相关阅读:
    如何提高MySQL Limit查询的性能
    asp.net cache 缓存
    a标签的target指向iframe
    Entity Framework实例详解
    MySql循环插入数据(定义了存储过程)
    mysql 定义function rand
    [转] Socket心跳包异常检测的C语言实现,服务器与客户端代码案例
    tinyhttpd ------ C 语言实现最简单的 HTTP 服务器
    http通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤
    http请求数据的格式
  • 原文地址:https://www.cnblogs.com/Jackie-Snow/p/9104396.html
Copyright © 2020-2023  润新知