Module: Nelumba::Crypto

Defined in:
lib/nelumba/crypto.rb

Defined Under Namespace

Classes: KeyPair

Class Method Summary collapse

Class Method Details

.decrypt(private_key, data) ⇒ Object

Decrypts the given data with the given private key.



90
91
92
93
94
# File 'lib/nelumba/crypto.rb', line 90

def self.decrypt(private_key, data)
  private_key = generate_key(private_key) unless private_key.is_a? RSA::Key
  keypair = generate_keypair(nil, private_key)
  keypair.decrypt(data)
end

.emsa_sign(text, private_key) ⇒ Object

Creates an EMSA signature for the given plaintext and key.



59
60
61
62
63
# File 'lib/nelumba/crypto.rb', line 59

def self.emsa_sign(text, private_key)
  private_key = generate_key(private_key) unless private_key.is_a? RSA::Key
  signature = self.emsa_signature(text, private_key)
  self.decrypt(private_key, signature)
end

.emsa_verify(text, signature, public_key) ⇒ Object

Verifies an existing EMSA signature.



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/nelumba/crypto.rb', line 66

def self.emsa_verify(text, signature, public_key)
  # RSA encryption is needed to compare the signatures
  public_key = generate_key(public_key) unless public_key.is_a? RSA::Key

  # Get signature to check
  emsa = self.emsa_signature(text, public_key)

  # Get signature in payload
  emsa_signature = self.encrypt(public_key, signature)

  # RSA gem drops leading 0s since it does math upon an Integer
  # As a workaround, I check for what I expect the second byte to be (\x01)
  # This workaround will also handle seeing a \x00 first if the RSA gem is
  # fixed.
  if emsa_signature.getbyte(0) == 1
    emsa_signature = "\x00#{emsa_signature}"
  end

  # Does the signature match?
  # Return the result.
  emsa_signature == emsa
end

.encrypt(public_key, data) ⇒ Object

Encrypts the given data with the given public key.



97
98
99
100
101
# File 'lib/nelumba/crypto.rb', line 97

def self.encrypt(public_key, data)
  public_key = generate_key(public_key) unless public_key.is_a? RSA::Key
  keypair = generate_keypair(public_key, nil)
  keypair.encrypt(data)
end

.new_keypair(bits = 2048) ⇒ Object

Generate a new RSA keypair with the given bitlength.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/nelumba/crypto.rb', line 10

def self.new_keypair(bits = 2048)
  keypair = KeyPair.new

  key = RSA::KeyPair.generate(bits)

  public_key = key.public_key
  m = public_key.modulus
  e = public_key.exponent

  modulus = ""
  until m == 0 do
    modulus << [m % 256].pack("C")
    m >>= 8
  end
  modulus.reverse!

  exponent = ""
  until e == 0 do
    exponent << [e % 256].pack("C")
    e >>= 8
  end
  exponent.reverse!

  keypair.public_key = "RSA.#{Base64::urlsafe_encode64(modulus)}.#{Base64::urlsafe_encode64(exponent)}"

  tmp_private_key = key.private_key
  m = tmp_private_key.modulus
  e = tmp_private_key.exponent

  modulus = ""
  until m == 0 do
    modulus << [m % 256].pack("C")
    m >>= 8
  end
  modulus.reverse!

  exponent = ""
  until e == 0 do
    exponent << [e % 256].pack("C")
    e >>= 8
  end
  exponent.reverse!

  keypair.private_key = "RSA.#{Base64::urlsafe_encode64(modulus)}.#{Base64::urlsafe_encode64(exponent)}"

  keypair
end