module Wechat::Cipher

Constants

BLOCK_SIZE
CIPHER

Public Instance Methods

decrypt(msg, encoding_aes_key) click to toggle source
# File lib/wechat/cipher.rb, line 20
def decrypt(msg, encoding_aes_key)
  cipher = OpenSSL::Cipher.new(CIPHER)
  cipher.decrypt

  cipher.padding = 0
  key_data = Base64.decode64("#{encoding_aes_key}=")
  cipher.key = key_data
  cipher.iv = [key_data].pack('H*')

  plain = cipher.update(msg) + cipher.final
  decode_padding(plain)
end
encrypt(plain, encoding_aes_key) click to toggle source
# File lib/wechat/cipher.rb, line 8
def encrypt(plain, encoding_aes_key)
  cipher = OpenSSL::Cipher.new(CIPHER)
  cipher.encrypt

  cipher.padding = 0
  key_data = Base64.decode64("#{encoding_aes_key}=")
  cipher.key = key_data
  cipher.iv = [key_data].pack('H*')

  cipher.update(plain) + cipher.final
end
pack(content, app_id) click to toggle source

app_id or corp_id

# File lib/wechat/cipher.rb, line 34
def pack(content, app_id)
  random = SecureRandom.hex(8)
  text = content.dup.force_encoding('ASCII-8BIT')
  msg_len = [text.length].pack('N')

  encode_padding("#{random}#{msg_len}#{text}#{app_id}")
end
unpack(msg) click to toggle source
# File lib/wechat/cipher.rb, line 42
def unpack(msg)
  msg = decode_padding(msg)
  msg_len = msg[16, 4].reverse.unpack1('V')
  content = msg[20, msg_len]
  app_id = msg[(msg_len + 20)..-1]

  [content, app_id]
end

Private Instance Methods

decode_padding(plain) click to toggle source
# File lib/wechat/cipher.rb, line 61
def decode_padding(plain)
  pad = plain.bytes[-1]
  # no padding
  pad = 0 if pad < 1 || pad > BLOCK_SIZE
  plain[0...(plain.length - pad)]
end
encode_padding(data) click to toggle source
# File lib/wechat/cipher.rb, line 53
def encode_padding(data)
  length = data.bytes.length
  amount_to_pad = BLOCK_SIZE - (length % BLOCK_SIZE)
  amount_to_pad = BLOCK_SIZE if amount_to_pad.zero?
  padding = ([amount_to_pad].pack('c') * amount_to_pad)
  data + padding
end