# -*- coding: binary -*-

module Rex
module Proto
module IPMI
class Utils

  def self.checksum(data)
    sum = 0
    data.unpack("C*").each {|c| sum += c }
    sum = ~sum + 1
    sum & 0xff
  end

  def self.create_ipmi_getchannel_probe
    [   # Get Channel Authentication Capabilities
      0x06, 0x00, 0xff, 0x07, # RMCP Header
      0x00, 0x00, 0x00, 0x00, 
      0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x20, 0x18, 
      0xc8, 0x81, 0x00, 0x38, 0x8e, 0x04, 0xb5
    ].pack("C*")
  end

  # open rmcpplus_request
  def self.create_ipmi_session_open_request(console_session_id)
    head = [
      0x06, 0x00, 0xff, 0x07,   # RMCP Header
      0x06,                     # RMCP+ Authentication Type
      PAYLOAD_RMCPPLUSOPEN_REQ, # Payload Type
      0x00, 0x00, 0x00, 0x00,   # Session ID
      0x00, 0x00, 0x00, 0x00    # Sequence Number
    ].pack("C*")

    data =
    [   # Maximum access
      0x00, 0x00,
      # Reserved
      0x00, 0x00
    ].pack("C*") + 
    console_session_id +
    [
      0x00, 0x00, 0x00, 0x08, 
      0x01, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x08, 
      # HMAC-SHA1
      0x01, 0x00, 0x00, 0x00, 
      0x02, 0x00, 0x00, 0x08, 
      # AES Encryption
      0x01, 0x00, 0x00, 0x00
    ].pack("C*")

    head + [data.length].pack('v') + data 
  end


  # open rmcpplus_request with cipherzero
  def self.create_ipmi_session_open_cipher_zero_request(console_session_id)
    head = [
      0x06, 0x00, 0xff, 0x07,   # RMCP Header
      0x06,                     # RMCP+ Authentication Type
      PAYLOAD_RMCPPLUSOPEN_REQ, # Payload Type
      0x00, 0x00, 0x00, 0x00,   # Session ID
      0x00, 0x00, 0x00, 0x00    # Sequence Number
    ].pack("C*")

    data =
    [   # Maximum access
      0x00, 0x00,
      # Reserved
      0x00, 0x00
    ].pack("C*") + 
    console_session_id +
    [
      0x00, 0x00, 0x00, 0x08, 
      # Cipher 0
      0x00, 0x00, 0x00, 0x00,
      0x01, 0x00, 0x00, 0x08,
      # Cipher 0
      0x00, 0x00, 0x00, 0x00,
      0x02, 0x00, 0x00, 0x08,
      # No Encryption 
      0x00, 0x00, 0x00, 0x00
    ].pack("C*")

    head + [data.length].pack('v') + data 
  end

  def self.create_ipmi_rakp_1(bmc_session_id, console_random_id, username)
    [
      0x06, 0x00, 0xff, 0x07,  # RMCP Header
      0x06,                    # RMCP+ Authentication Type
      PAYLOAD_RAKP1,           # Payload Type
      0x00, 0x00, 
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 
      0x00, 0x00, 0x00, 0x00
    ].pack("C*") +
    bmc_session_id +
    console_random_id +
    [
      0x14, 0x00, 0x00, 
      username.length
    ].pack("C*") + 
    username
  end


  def self.create_rakp_hmac_sha1_salt(con_sid, bmc_sid, con_rid, bmc_rid, bmc_gid, auth_level, username)
    con_sid +
    bmc_sid +
    con_rid +
    bmc_rid +
    bmc_gid + 
    [ auth_level ].pack("C") +
    [ username.length ].pack("C") +
    username
  end

  def self.verify_rakp_hmac_sha1(salt, hash, password)
    OpenSSL::HMAC.digest('sha1', password, salt) == hash
  end

end
end
end
end