Class: Jodid::Cryptor

Inherits:
Object
  • Object
show all
Includes:
Sodium::Utils
Defined in:
lib/jodid/cryptor.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(public_key, secret_key, keychain) ⇒ Cryptor

Returns a new instance of Cryptor.


7
8
9
10
11
12
13
14
15
16
17
# File 'lib/jodid/cryptor.rb', line 7

def initialize(public_key, secret_key, keychain)
  check_length(public_key, Crypto::Sign::PUBLICKEYBYTES, :PublicKey)
  check_length(secret_key, Crypto::Sign::SECRETKEYBYTES, :SecretKey)

  @public_key = public_key
  @secret_key = secret_key
  @curve25519_sk = Crypto::Sign::Ed25519.sk_to_curve25519(@secret_key)
  @keychain = keychain

  @shared_secrets = {}
end

Instance Attribute Details

#public_keyObject (readonly)

Returns the value of attribute public_key


5
6
7
# File 'lib/jodid/cryptor.rb', line 5

def public_key
  @public_key
end

Instance Method Details

#box(value, recipient) ⇒ Object


45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/jodid/cryptor.rb', line 45

def box(value, recipient)
  public_key = @keychain.fetch(recipient, :public_key)
  shared_secret = @shared_secrets.fetch(public_key) do
    @shared_secrets.store(public_key,
      Crypto::Box.beforenm(
        Crypto::Sign::Ed25519.pk_to_curve25519(public_key),
        @curve25519_sk))
  end
  nonce = Crypto::Box.nonce
  ciphertext = Crypto::SecretBox.secretbox(value, nonce,
    shared_secret)
  @public_key.dup << nonce << ciphertext
end

#box!(value, recipient) ⇒ Object


80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/jodid/cryptor.rb', line 80

def box!(value, recipient)
  public_key = @keychain.fetch(recipient, :public_key)
  shared_secret = @shared_secrets.fetch(public_key) do
    @shared_secrets.store(public_key,
      Crypto::Box.beforenm(
        Crypto::Sign::Ed25519.pk_to_curve25519(public_key),
        @curve25519_sk))
  end
  data = String(value)
  nonce = Crypto::Box.nonce
  Crypto::SecretBox.secretbox!(data, nonce,
    shared_secret).prepend(nonce).prepend(@public_key)
end

#box_open(ciphertext, encoding = Encoding.default_external) ⇒ Object


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/jodid/cryptor.rb', line 59

def box_open(ciphertext, encoding = Encoding.default_external)
  public_key = ciphertext[0...Crypto::Sign::PUBLICKEYBYTES]
  if (shared_secret = @shared_secrets[public_key])
    message = Crypto::SecretBox.open(
      ciphertext[Crypto::Sign::PUBLICKEYBYTES + Crypto::Box::NONCEBYTES..-1],
      ciphertext[Crypto::Sign::PUBLICKEYBYTES, Crypto::Box::NONCEBYTES],
      shared_secret, encoding)
  else
    pk = Crypto::Sign::Ed25519.pk_to_curve25519(public_key)
    message = Crypto::Box.open(
      ciphertext[Crypto::Sign::PUBLICKEYBYTES + Crypto::Box::NONCEBYTES..-1],
      ciphertext[Crypto::Sign::PUBLICKEYBYTES, Crypto::Box::NONCEBYTES],
      pk, @curve25519_sk, encoding)
    @shared_secrets.store(public_key,
      Crypto::Box.beforenm(
        pk, @curve25519_sk))
  end

  message
end

#box_open!(ciphertext, encoding = Encoding.default_external) ⇒ Object


94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/jodid/cryptor.rb', line 94

def box_open!(ciphertext, encoding = Encoding.default_external)
  public_key = ciphertext.slice!(0...Crypto::Sign::PUBLICKEYBYTES)
  nonce = ciphertext.slice!(0...Crypto::Box::NONCEBYTES)
  mac = ciphertext.slice!(0...Crypto::Box::MACBYTES)
  if (shared_secret = @shared_secrets[public_key])
    message = Crypto::SecretBox.open_detached!(ciphertext, mac, nonce,
      shared_secret, encoding)
  else
    pk = Crypto::Sign::Ed25519.pk_to_curve25519(public_key)
    message = Crypto::Box.open_detached!(ciphertext, mac, nonce,
      pk, @curve25519_sk, encoding)
    @shared_secrets.store(public_key,
      Crypto::Box.beforenm(pk, @curve25519_sk))
  end

  message
end

#secretbox(value) ⇒ Object


19
20
21
22
# File 'lib/jodid/cryptor.rb', line 19

def secretbox(value)
  nonce = Crypto::SecretBox.nonce
  nonce << Crypto::SecretBox.secretbox(value, nonce, @curve25519_sk)
end

#secretbox!(value) ⇒ Object


31
32
33
34
35
36
# File 'lib/jodid/cryptor.rb', line 31

def secretbox!(value)
  data = String(value)
  nonce = Crypto::SecretBox.nonce
  Crypto::SecretBox.secretbox!(data, nonce,
    @curve25519_sk).prepend(nonce)
end

#secretbox_open(ciphertext, encoding = Encoding.default_external) ⇒ Object


24
25
26
27
28
29
# File 'lib/jodid/cryptor.rb', line 24

def secretbox_open(ciphertext, encoding = Encoding.default_external)
  Crypto::SecretBox.open(
    ciphertext[Crypto::SecretBox::NONCEBYTES..-1],
    ciphertext[0...Crypto::SecretBox::NONCEBYTES],
    @curve25519_sk, encoding)
end

#secretbox_open!(ciphertext, encoding = Encoding.default_external) ⇒ Object


38
39
40
41
42
43
# File 'lib/jodid/cryptor.rb', line 38

def secretbox_open!(ciphertext, encoding = Encoding.default_external)
  nonce = ciphertext.slice!(0...Crypto::SecretBox::NONCEBYTES)
  mac = ciphertext.slice!(0...Crypto::SecretBox::MACBYTES)
  Crypto::SecretBox.open_detached!(ciphertext, mac, nonce,
                          @curve25519_sk, encoding)
end

#sign_detached(message) ⇒ Object


112
113
114
# File 'lib/jodid/cryptor.rb', line 112

def sign_detached(message)
  Crypto::Sign.detached(message, @secret_key).prepend(@public_key)
end

#sign_verify_detached(signature, message) ⇒ Object


116
117
118
119
120
121
# File 'lib/jodid/cryptor.rb', line 116

def sign_verify_detached(signature, message)
  public_key = signature[0...Crypto::Sign::PUBLICKEYBYTES]
  Crypto::Sign.verify_detached(
    signature[Crypto::Sign::PUBLICKEYBYTES..-1],
    message, public_key)
end