Commit 55a7562f8a1819b60b61f9ee0d92e86362df97a1

Authored by Jeff Lai
1 parent 526b4bcc
Exists in master

Add encryption helpers

lib/dingtalk/pkcs7_encoder.rb 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +module Dingtalk
  2 + module PKCS7Encoder
  3 + extend self
  4 +
  5 + BLOCK_SIZE = 32
  6 +
  7 + def decode(text)
  8 + pad = text[-1].ord
  9 + pad = 0 if (pad < 1 || pad > BLOCK_SIZE)
  10 + size = text.size - pad
  11 + text[0...size]
  12 + end
  13 +
  14 + # 对需要加密的明文进行填充补位
  15 + # 返回补齐明文字符串
  16 + def encode(text)
  17 + # 计算需要填充的位数
  18 + amount_to_pad = BLOCK_SIZE - (text.length % BLOCK_SIZE)
  19 + amount_to_pad = BLOCK_SIZE if amount_to_pad == 0
  20 + # 获得补位所用的字符
  21 + pad_chr = amount_to_pad.chr
  22 + "#{text}#{pad_chr * amount_to_pad}"
  23 + end
  24 +
  25 + end
  26 +end
... ...
lib/dingtalk/prpcrypt.rb 0 → 100644
... ... @@ -0,0 +1,46 @@
  1 +module Dingtalk
  2 + module Prpcrypt
  3 + extend self
  4 +
  5 + # 对密文进行解密.
  6 + # text 需要解密的密文
  7 + def decrypt(aes_key, text, corpid)
  8 + status = 200
  9 + text = Base64.decode64(text)
  10 + text = handle_cipher(:decrypt, aes_key, text)
  11 + result = PKCS7Encoder.decode(text)
  12 + content = result[16...result.length]
  13 + len_list = content[0...4].unpack("N")
  14 + xml_len = len_list[0]
  15 + xml_content = content[4...4 + xml_len]
  16 + from_corpid = content[xml_len+4...content.size]
  17 + # TODO: refactor
  18 + if corpid != from_corpid
  19 + Rails.logger.debug("#{__FILE__}:#{__LINE__} Failure because #{corpid} != #{from_corpid}")
  20 + status = 401
  21 + end
  22 + [xml_content, status]
  23 + end
  24 +
  25 + # 加密
  26 + def encrypt(aes_key, text, corpid)
  27 + text = text.force_encoding("ASCII-8BIT")
  28 + random = SecureRandom.hex(8)
  29 + msg_len = [text.length].pack("N")
  30 + text = "#{random}#{msg_len}#{text}#{corpid}"
  31 + text = PKCS7Encoder.encode(text)
  32 + text = handle_cipher(:encrypt, aes_key, text)
  33 + Base64.encode64(text)
  34 + end
  35 +
  36 + private
  37 + def handle_cipher(action, aes_key, text)
  38 + cipher = OpenSSL::Cipher.new('AES-256-CBC')
  39 + cipher.send(action)
  40 + cipher.padding = 0
  41 + cipher.key = aes_key
  42 + cipher.iv = aes_key[0...16]
  43 + cipher.update(text) + cipher.final
  44 + end
  45 + end
  46 +end
... ...