Class: Nova::Starbound::Encryptors::OpenSSL

Inherits:
Nova::Starbound::Encryptor show all
Defined in:
lib/nova/starbound/encryptors/openssl.rb

Overview

Handles encryption using the OpenSSL library. Shares the shared secret using RSA public key encryption, creates a HMAC digest of the body using the shared secret as a key, and encrypts the body using AES-256-CBC encryption.

Constant Summary collapse

RSA_KEY_SIZE =

The RSA key size for the key exchange.

4096
SECRET_SIZE =

The shared secret size, in bytes. If RSA_KEY_SIZE is 4096, this is 256.

RSA_KEY_SIZE / 16

Instance Attribute Summary

Attributes inherited from Nova::Starbound::Encryptor

#options

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Nova::Starbound::Encryptor

encryptor_name, encryptors, #initialize, plaintext?, register!, sorted_encryptors

Constructor Details

This class inherits a constructor from Nova::Starbound::Encryptor

Class Method Details

.available?Boolean

see Encryptor.available?

Returns:

  • (Boolean)


24
25
26
27
28
29
30
31
# File 'lib/nova/starbound/encryptors/openssl.rb', line 24

def self.available?
  @_available ||= begin
    require 'openssl'
    true
  rescue LoadError
    false
  end
end

Instance Method Details

#decrypt(packet) ⇒ Packet

Decrypts the given packet with the encryptor.

Parameters:

  • packet (Packet)

    the packet to decrypt.

Returns:

  • (Packet)

    the decrypted packet.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/nova/starbound/encryptors/openssl.rb', line 50

def decrypt(packet)
  packet = packet.clone
  decipher = ::OpenSSL::Cipher::AES256.new(:CBC)
  decipher.decrypt
  decipher.key = options[:shared_secret]
  decipher.iv  = packet[:nonce]

  digest = packet[:body][0..63]
  actual_body = packet[:body][64..-1]

  if hmac_digest(actual_body) != digest
    raise EncryptorError, "Digest doesn't match the body."
  end

  packet.body = decipher.update(actual_body) +
    decipher.final
  packet
end

#encrypt(packet) ⇒ Packet

Encrypts the given packet with the encryptor.

Parameters:

  • packet (Packet)

    the packet to encrypt.

Returns:

  • (Packet)

    the encrypted packet.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/nova/starbound/encryptors/openssl.rb', line 34

def encrypt(packet)
  packet = packet.clone
  cipher = ::OpenSSL::Cipher::AES256.new(:CBC)
  cipher.encrypt
  cipher.key = options[:shared_secret]

  # we have to fit the packet's nonce size.
  packet[:nonce] = cipher.iv = ::OpenSSL::Random.random_bytes(24)

  encrypted = cipher.update(packet[:body]) + cipher.final

  packet.body = hmac_digest(encrypted) + encrypted
  packet
end

#other_public_key=(public_key) ⇒ void

This method returns an undefined value.

If we already have a public key, that means that the value that’s passed to this method is the shared secret. Otherwise, it really is the public key of the other remote. If the passed value is a shared secret, it’s decrypted with our private key and stored. If it’s the other public key, it’s instantized to a openssl RSA key, and stored.



99
100
101
102
103
104
105
106
107
# File 'lib/nova/starbound/encryptors/openssl.rb', line 99

def other_public_key=(public_key)
  if options[:public]
    options[:shared_secret] =
      options[:private].private_decrypt(public_key)
  else
    options[:other_public] =
      ::OpenSSL::PKey::RSA.new(public_key)
  end
end

#private_key!void

This method returns an undefined value.

Generates the private key for this encryptor.



70
71
72
# File 'lib/nova/starbound/encryptors/openssl.rb', line 70

def private_key!
  options[:private] = ::OpenSSL::PKey::RSA.new(RSA_KEY_SIZE)
end

#public_keyString

If we have already recieved the other public key, we’ll generate the secret here, and return the encrypted version of that secret here. Otherwise, we’ll generate our private key and return that in DER format.

Returns:

  • (String)


80
81
82
83
84
85
86
87
88
89
# File 'lib/nova/starbound/encryptors/openssl.rb', line 80

def public_key
  if options[:other_public]
    options[:shared_secret] =
      ::OpenSSL::Random.random_bytes(SECRET_SIZE)
    options[:other_public].public_encrypt(
      options[:shared_secret])
  else
    options[:public] ||= options[:private].public_key.to_der
  end
end