ruby on rail 微信企业号回调模式 url初次验证时 echostr的解密

再进行初次url验证时,对于echostr的解密实在是头疼,跟同事一起折腾了半个下午,搜遍了百度和谷歌,就是找不到合适的解密代码,根据腾讯给的文档以及java  demo包往下做时,一直卡在echostr如何解密生成4个字段。最后在谷歌上根据echostr ruby 找到  https://ruby-china.org/topics/23982, 提供了可行的方案。

首先官方文档是这么描述echostr的:

加密的随机字符串,以msg_encrypt格式提供。需要解密并返回echostr明文,解密后有random、msg_len、msg、$CorpID四个字段,其中msg即为echostr明文

也就是说我们拿到的echostr是用   random、msg_len、msg、$CorpID四个字段加密后生成的字符串,初次验证url最后要返回的就是msg这个字段。

msg_encrypt = Base64_Encode( AES_Encrypt[random(16B) + msg_len(4B) + msg + $CorpID] )

反推也就是需要先64位解码,然后AES_Encrypt加密用decrypt解密,

首先我在tasks_helper里加了两个自定义模块PKCS7Encoder和Prpcrypt

module PKCS7Encoder
  extend self

  BLOCK_SIZE = 32

  def decode(text)
    pad = text[-1].ord
    pad = 0 if (pad < 1 || pad > BLOCK_SIZE)
    size = text.size - pad
    text[0...size]
  end

  # 对需要加密的明文进行填充补位
  # 返回补齐明文字符串
  def encode(text)
    # 计算需要填充的位数
    amount_to_pad = BLOCK_SIZE - (text.length % BLOCK_SIZE)
    amount_to_pad = BLOCK_SIZE if amount_to_pad == 0
    # 获得补位所用的字符
    pad_chr = amount_to_pad.chr
    "#{text}#{pad_chr * amount_to_pad}"
  end

end

module Prpcrypt
  extend self

  # 对密文进行解密.
  # text 需要解密的密文
  def decrypt(aes_key, text, corpid)
    status = 200
    text        = Base64.decode64(text)
    text        = handle_cipher(:decrypt, aes_key, text)
    result      = PKCS7Encoder.decode(text)
    content     = result[16...result.length]
    len_list    = content[0...4].unpack("N")
    xml_len     = len_list[0]
    xml_content = content[4...4 + xml_len]
    from_corpid = content[xml_len+4...content.size]
    # TODO: refactor
    if corpid != from_corpid
      Rails.logger.debug("#{__FILE__}:#{__LINE__} Failure because #{corpid} != #{from_corpid}")
      status = 401
    end
    [xml_content, status]
  end

  # 加密
  def encrypt(aes_key, text, corpid)
    text    = text.force_encoding("ASCII-8BIT")
    random  = SecureRandom.hex(8)
    msg_len = [text.length].pack("N")
    text    = "#{random}#{msg_len}#{text}#{corpid}"
    text    = PKCS7Encoder.encode(text)
    text    = handle_cipher(:encrypt, aes_key, text)
    Base64.encode64(text)
  end

#官方文档说明参考:AESKey=Base64_Decode(EncodingAESKey + “=”),是AES算法的密钥,长度为32字节。AES采用CBC模式,数据采用PKCS#7填充;IV初始向量大小为16字节,取AESKey前16字节
  private
    def handle_cipher(action, aes_key, text)
      cipher = OpenSSL::Cipher.new('AES-256-CBC')
      cipher.send(action)
      cipher.padding = 0
      cipher.key     = aes_key
      cipher.iv      = aes_key[0...16]
      cipher.update(text) + cipher.final
    end
end


然后taskscontroller端开始处理微信企业号的验证请求:

#@@ASEKEY为配置回调模式中验证url时填写的EncodingaASEKEY,yourCorpId  即企业号设置内的CorpId

  def auth_wechat
    if valid_msg_signature?(params)
      content, status = Prpcrypt.decrypt(@@ASEKEY, params[:echostr], yourCorpId '') 
      Rails.logger.info content
      Rails.logger.info status
      render text: content, status: status
    end
  end

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值