module Gpsoauth::Google

Public Class Methods

key_from_b64(key) click to toggle source
# File lib/gpsoauth/google.rb, line 3
def self.key_from_b64(key)
  binary_key = Base64.decode64(key)

  i = binary_key[0,4].sum
  mod = binary_key[4, i].unpack("H*")[0].to_i(16)

  j = binary_key[i + 4, 4].sum
  exponent = binary_key[i + 8, j].unpack("H*")[0].to_i(16)

  key = OpenSSL::PKey::RSA.new
  key.e = OpenSSL::BN.new(exponent)
  key.n = OpenSSL::BN.new(mod)

  key
end
signature(email, password, key) click to toggle source
# File lib/gpsoauth/google.rb, line 19
def self.signature(email, password, key)
  # Encryption scheme deconstructed here:
  # http://codedigging.com/blog/2014-06-09-about-encryptedpasswd/

  struct = key_to_struct(key).pack('c*')
  first_four_bytes_sha1 = OpenSSL::Digest::SHA1.digest(struct)[0...4]

  encrypted_login_password = key.public_encrypt(
    email + "\x00" + password,
    OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
  )

  signature = "\x00" + first_four_bytes_sha1 + encrypted_login_password
  Base64.urlsafe_encode64(signature)
end

Private Class Methods

key_to_struct(key) click to toggle source
# File lib/gpsoauth/google.rb, line 49
def self.key_to_struct(key)
  mod_buffer = "\x00\x00\x00\x80".unpack('C*')
  exponent_buffer = "\x00\x00\x00\x03".unpack('C*')

  mod = long_to_bytes(key.n.to_i)
  exponent = long_to_bytes(key.e.to_i)

  mod_buffer + mod + exponent_buffer + exponent
end
long_to_bytes(key) click to toggle source
# File lib/gpsoauth/google.rb, line 37
def self.long_to_bytes(key)
  arr = []
  key, mod = key.divmod(256)

  while mod > 0 || key > 0
    arr << mod
    key, mod = key.divmod(256)
  end

  arr = arr.reverse
end