class Hcipher::Cipher

Constants

CHARS

define characters here below is default defined characters

Public Class Methods

decrypt(text, key) click to toggle source
# File lib/hcipher/cipher.rb, line 43
def self.decrypt(text, key)
  # Validation
  raise ArgumentError.new("Text and key can not be nil") unless text.present? && key.present?
  check_characters(text)
  check_characters(key)
  check_string(text)
  check_string(key)
  check_key(key)

  # get matrix for key and text
  matrix_key, matrix_text = get_matrix(text, key)
  matrix_key = decryption_key_matrix(matrix_key)

  # decrypt text
  decrypted_matrix = matrix_key * matrix_text
  decrypted_matrix = decrypted_matrix.map{|x| x % CHARS.size}
  decrypted_text = matrix_to_str(decrypted_matrix)
end
encrypt(text, key) click to toggle source
# File lib/hcipher/cipher.rb, line 25
def self.encrypt(text, key)
  # Validation
  raise ArgumentError.new("Text and key can not be nil") unless text.present? && key.present?
  check_characters(text)
  check_characters(key)
  check_string(text)
  check_string(key)
  check_key(key)

  # get matrix for key and text
  matrix_key, matrix_text = get_matrix(text, key)

  # encrypt text
  encrypted_matrix = matrix_key * matrix_text
  encrypted_matrix = encrypted_matrix.map{|x| x % CHARS.size}
  encrypted_text = matrix_to_str(encrypted_matrix)
end
generate_key(size) click to toggle source

generate key only integer is allowed as parameter sending n as parameter will create n*n matrix determinant from matrix created must not 0 matrix created will be converted to string

# File lib/hcipher/cipher.rb, line 12
def self.generate_key(size)
  raise ArgumentError.new("Only integer are allowed") unless size.is_a?(Integer)
  matrix_key = []
  loop do
    matrix_key = Matrix.build(size) { rand(1..(CHARS.size - 1)) }
    coprime = ((matrix_key.det).gcd(CHARS.size) == 1)

    # always break unless determinant matrix == 0 or determinant matrix and characters size not coprime
    break unless matrix_key.det == 0 || !coprime
  end
  matrix_to_str(matrix_key)
end

Private Class Methods

check_characters(string) click to toggle source

return error message if character not defined

# File lib/hcipher/cipher.rb, line 114
def self.check_characters(string)
  valid = string.to_s.split("").map{|char| CHARS.include?(char)}.uniq rescue false
  raise ArgumentError.new("Some characters are not defined, please define the character first") unless valid.size == 1 && valid.first == true
end
check_key(key) click to toggle source
# File lib/hcipher/cipher.rb, line 102
def self.check_key(key)
  # Math.sqrt() return float type. ex: 3.0
  # Set key as invalid if square root of key size is not an integer
  raise ArgumentError.new("Key not valid") unless Math.sqrt(key.size).to_s.split(".").last.to_f == 0
end
check_string(string) click to toggle source
# File lib/hcipher/cipher.rb, line 108
def self.check_string(string)
  # Allowed key and text type is string
  raise ArgumentError.new("Only string are allowed") unless string.is_a?(String)
end
decryption_key_matrix(matrix) click to toggle source
# File lib/hcipher/cipher.rb, line 81
def self.decryption_key_matrix(matrix)
  det_inv = 0
  det = matrix.det % CHARS.size
  loop do 
    det_inv += 1
    break if ((det * det_inv) % CHARS.size) == 1
  end
  
  matrix_inv = matrix.adjugate.map{|x| ((x % CHARS.size) * det_inv) % CHARS.size}
end
generate_matrix(string, rows, cols) click to toggle source
# File lib/hcipher/cipher.rb, line 74
def self.generate_matrix(string, rows, cols)
  # scenario: rows x cols == 2 x 2 but the string provided have 3 characters
  # If scenario similar to above happen, the index that can't be filled will be filled automatically with 0
  # ex: [[1, 2], [3, 0]]
  Matrix.build(rows, cols){|row, col| ((cols * row) + col) >= string.size ? 0 : CHARS.rindex(string[(cols * row) + col])}
end
get_matrix(text, key) click to toggle source
# File lib/hcipher/cipher.rb, line 63
def self.get_matrix(text, key)
  # create matrix key
  sqrt_key_size = Math.sqrt(key.size).to_i
  matrix_key = generate_matrix(key, sqrt_key_size, sqrt_key_size)

  # create matrix text
  column = (text.size/sqrt_key_size.to_f).ceil
  matrix_text = generate_matrix(text, sqrt_key_size, column)
  return matrix_key, matrix_text
end
matrix_to_str(matrix) click to toggle source

convert matrix to string

# File lib/hcipher/cipher.rb, line 93
def self.matrix_to_str(matrix)
  str = ""
  matrix.each do |num|
    # next if num == 0
    str << CHARS[num]
  end
  str
end