Class: Encruby::Message

Inherits:
Object
  • Object
show all
Defined in:
lib/encruby/message.rb

Constant Summary collapse

AES_MODE =
:CBC

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key) ⇒ Message

Returns a new instance of Message.



7
8
9
10
# File 'lib/encruby/message.rb', line 7

def initialize(key)
  self.key = key
  @cipher = OpenSSL::Cipher::AES256.new(AES_MODE)
end

Instance Attribute Details

#keyObject

Returns the value of attribute key.



5
6
7
# File 'lib/encruby/message.rb', line 5

def key
  @key
end

Instance Method Details

#decrypt(message, hash: nil) ⇒ Object

  1. Base64 decode the encrypted message

  2. Split the string in to the AES key and the encrypted message

  3. Decrypt the AES key using the private key

  4. Decrypt the message using the AES key



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/encruby/message.rb', line 65

def decrypt(message, hash: nil)
  # 0
  message = Base64.decode64(message)
  hmac = message[0..63] # 64 bits of hmac signature

  case
  when hash && hmac != hash
    raise Error, "Provided hash mismatch for encrypted file!"
  when hmac != hmac_signature(message[64..-1])
    raise Error, "HMAC signature mismatch for encrypted file!"
  end

  # 1
  rsa_encrypted_aes_key = message[64..319]  # next 256 bits
  rsa_encrypted_aes_iv  = message[320..575] # next 256 bits
  aes_encrypted_message = message[576..-1]

  # 2
  aes_key = @rsa.private_decrypt rsa_encrypted_aes_key
  aes_iv  = @rsa.private_decrypt rsa_encrypted_aes_iv

  # 3
  @cipher.reset
  @cipher.decrypt
  @cipher.key = aes_key
  @cipher.iv  = aes_iv
  content = @cipher.update(aes_encrypted_message) + @cipher.final

  { signature: hmac, content: content }
rescue OpenSSL::OpenSSLError => e
  raise Error.new(e.message)
end

#encrypt(message) ⇒ Object

  1. Generate random AES key to encrypt message

  2. Use Public Key from the Private key to encrypt AES Key

  3. Prepend encrypted AES key to the encrypted message

Output message format will look like the following:

{RSA Encrypted AES Key}{RSA Encrypted IV}{AES Encrypted Message}


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/encruby/message.rb', line 36

def encrypt(message)
  raise Error, "data must not be empty" if message.to_s.strip.empty?
  # 1
  @cipher.reset
  @cipher.encrypt
  aes_key   = @cipher.random_key
  aes_iv    = @cipher.random_iv
  encrypted = @cipher.update(message) + @cipher.final

  # 2
  rsa_encrypted_aes_key = @rsa.public_encrypt(aes_key)
  rsa_encrypted_aes_iv  = @rsa.public_encrypt(aes_iv)

  # 3
  content = rsa_encrypted_aes_key + rsa_encrypted_aes_iv + encrypted

  # 4
  hmac = hmac_signature(content)
  content = Base64.encode64(hmac + content)

  { signature: hmac, content: content }
rescue OpenSSL::OpenSSLError => e
  raise Error.new(e.message)
end

#hmac_signature(content) ⇒ Object



25
26
27
# File 'lib/encruby/message.rb', line 25

def hmac_signature(content)
  OpenSSL::HMAC.hexdigest('sha256', @rsa.public_key.to_s, content)
end

#with_key(key) ⇒ Object



20
21
22
23
# File 'lib/encruby/message.rb', line 20

def with_key(key)
  self.key = key
  self
end