module CivicSIPSdk::Crypto

Constants

CIPHER_ALGO
ECDSA_CURVE

“prime256v1” is another name for “secp256r1”

HMAC_DIGEST
IV_STRING_LENGTH
JWT_ALGO

Public Class Methods

civic_extension(secret:, body:) click to toggle source
# File lib/civic_sip_sdk/crypto.rb, line 74
def self.civic_extension(secret:, body:)
  hmac = OpenSSL::HMAC.digest(HMAC_DIGEST, secret, body)
  Base64.encode64(hmac)
end
decode_jwt_token(token:, public_hex_key:, should_verify:) click to toggle source
# File lib/civic_sip_sdk/crypto.rb, line 67
def self.decode_jwt_token(token:, public_hex_key:, should_verify:)
  public_key = public_signing_key(public_hex_key: public_hex_key)
  data, = JWT.decode(token, public_key, should_verify, algorithm: JWT_ALGO)

  data
end
decrypt(text:, secret:) click to toggle source

Decrypt the encrypted text using AES-128-CBC with a IV of 32 bytes

@param text [String] the encrypted text to be decrypted @param secret [String] the Civic application secret in HEX format

# File lib/civic_sip_sdk/crypto.rb, line 36
def self.decrypt(text:, secret:)
  cipher = OpenSSL::Cipher.new(CIPHER_ALGO)
  cipher.decrypt
  cipher.key = hex_to_string(hex: secret)
  iv_hex = text[0..(IV_STRING_LENGTH - 1)]
  cipher.iv = hex_to_string(hex: iv_hex)
  encrypted_text = Base64.decode64(text[IV_STRING_LENGTH..-1])

  "#{cipher.update(encrypted_text)}#{cipher.final}"
end
encrypt(text:, secret:) click to toggle source

Create encrypted text using AES-128-CBC with a IV of 16 bytes

@param text [String] the plain text to be encrypted @param secret [String] the Civic application secret in HEX format

# File lib/civic_sip_sdk/crypto.rb, line 21
def self.encrypt(text:, secret:)
  cipher = OpenSSL::Cipher.new(CIPHER_ALGO)
  cipher.encrypt
  cipher.key = hex_to_string(hex: secret)
  iv = cipher.random_iv
  cipher.iv = iv

  encrypted_text = "#{cipher.update(text)}#{cipher.final}"
  "#{string_to_hex(str: iv)}#{Base64.encode64(encrypted_text)}"
end
jwt_token(app_id:, sip_base_url:, data:, private_key:) click to toggle source
# File lib/civic_sip_sdk/crypto.rb, line 47
def self.jwt_token(app_id:, sip_base_url:, data:, private_key:)
  now = Time.now.to_i

  payload = {
    iat: now,
    exp: now + 60 * 3,
    iss: app_id,
    aud: sip_base_url,
    sub: app_id,
    jti: SecureRandom.uuid,
    data: data
  }

  JWT.encode(
    payload,
    private_signing_key(private_hex_key: private_key),
    JWT_ALGO
  )
end

Private Class Methods

hex_to_string(hex:) click to toggle source
# File lib/civic_sip_sdk/crypto.rb, line 105
def hex_to_string(hex:)
  hex.scan(/../).map(&:hex).pack('c*')
end
private_signing_key(private_hex_key:) click to toggle source
# File lib/civic_sip_sdk/crypto.rb, line 82
def private_signing_key(private_hex_key:)
  key = OpenSSL::PKey::EC.new(ECDSA_CURVE)
  key.private_key = OpenSSL::BN.new(private_hex_key.to_i(16))

  key
end
public_signing_key(public_hex_key:) click to toggle source
# File lib/civic_sip_sdk/crypto.rb, line 89
def public_signing_key(public_hex_key:)
  group = OpenSSL::PKey::EC::Group.new(ECDSA_CURVE)
  point = OpenSSL::PKey::EC::Point.new(
    group,
    OpenSSL::BN.new(public_hex_key.to_i(16))
  )
  key = OpenSSL::PKey::EC.new(ECDSA_CURVE)
  key.public_key = point

  key
end
string_to_hex(str:) click to toggle source
# File lib/civic_sip_sdk/crypto.rb, line 101
def string_to_hex(str:)
  str.unpack1('H*')
end