PageRenderTime 18ms CodeModel.GetById 1ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/bundle/jruby/2.1/gems/rbnacl-3.0.1/lib/rbnacl/boxes/curve25519xsalsa20poly1305.rb

https://github.com/delowong/logstash
Ruby | 184 lines | 62 code | 13 blank | 109 comment | 6 complexity | 365b40199c5a5707c8c8b4804730fe25 MD5 | raw file
  1# encoding: binary
  2module RbNaCl
  3  module Boxes
  4    # The Box class boxes and unboxes messages between a pair of keys
  5    #
  6    # This class uses the given public and secret keys to derive a shared key,
  7    # which is used with the nonce given to encrypt the given messages and
  8    # decrypt the given ciphertexts.  The same shared key will generated from
  9    # both pairing of keys, so given two keypairs belonging to alice (pkalice,
 10    # skalice) and bob(pkbob, skbob), the key derived from (pkalice, skbob) with
 11    # equal that from (pkbob, skalice).  This is how the system works:
 12    #
 13    # @example
 14    #   # On bob's system
 15    #   bobkey = RbNaCl::PrivateKey.generate
 16    #   #=> #<RbNaCl::PrivateKey ...>
 17    #
 18    #   # send bobkey.public_key to alice
 19    #   # recieve alice's public key, alicepk
 20    #   # NB: This is actually the hard part of the system.  How to do it securely
 21    #   # is left as an exercise to for the reader.
 22    #   alice_pubkey = "..."
 23    #
 24    #   # make a box
 25    #   alicebob_box = RbNaCl::Box.new(alice_pubkey, bobkey)
 26    #   #=> #<RbNaCl::Box ...>
 27    #
 28    #   # encrypt a message to alice
 29    #   cipher_text = alicebob_box.box("A bad example of a nonce", "Hello, Alice!")
 30    #   #=> "..." # a string of bytes, 29 bytes long
 31    #
 32    #   # send ["A bad example of a nonce", cipher_text] to alice
 33    #   # note that nonces don't have to be secret
 34    #   # receive [nonce, cipher_text_to_bob] from alice
 35    #
 36    #   # decrypt the reply
 37    #   # Alice has been a little more sensible than bob, and has a random nonce
 38    #   # that is too fiddly to type here.  But there are other choices than just
 39    #   # random
 40    #   plain_text = alicebob_box.open(nonce, cipher_text_to_bob)
 41    #   #=> "Hey there, Bob!"
 42    #
 43    #   # we have a new message!
 44    #   # But Eve has tampered with this message, by flipping some bytes around!
 45    #   # [nonce2, cipher_text_to_bob_honest_love_eve]
 46    #   alicebob_box.open(nonce2, cipher_text_to_bob_honest_love_eve)
 47    #
 48    #   # BOOM!
 49    #   # Bob gets a RbNaCl::CryptoError to deal with!
 50    #
 51    # It is VITALLY important that the nonce is a nonce, i.e. it is a number used
 52    # only once for any given pair of keys.  If you fail to do this, you
 53    # compromise the privacy of the the messages encrypted.  Also, bear in mind
 54    # the property mentioned just above. Give your nonces a different prefix, or
 55    # have one side use an odd counter and one an even counter.  Just make sure
 56    # they are different.
 57    #
 58    # The ciphertexts generated by this class include a 16-byte authenticator which
 59    # is checked as part of the decryption.  An invalid authenticator will cause
 60    # the unbox function to raise.  The authenticator is not a signature.  Once
 61    # you've looked in the box, you've demonstrated the ability to create
 62    # arbitrary valid messages, so messages you send are repudiable.  For
 63    # non-repudiable messages, sign them before or after encryption.
 64    class Curve25519XSalsa20Poly1305
 65      extend Sodium
 66
 67      sodium_type      :box
 68      sodium_primitive :curve25519xsalsa20poly1305
 69      sodium_constant  :NONCEBYTES
 70      sodium_constant  :ZEROBYTES
 71      sodium_constant  :BOXZEROBYTES
 72      sodium_constant  :BEFORENMBYTES
 73      sodium_constant  :PUBLICKEYBYTES
 74      sodium_constant  :SECRETKEYBYTES, :PRIVATEKEYBYTES
 75
 76      sodium_function :box_curve25519xsalsa20poly1305_beforenm,
 77                      :crypto_box_curve25519xsalsa20poly1305_beforenm,
 78                      [:pointer, :pointer, :pointer]
 79
 80      sodium_function :box_curve25519xsalsa20poly1305_open_afternm,
 81                      :crypto_box_curve25519xsalsa20poly1305_open_afternm,
 82                      [:pointer, :pointer, :ulong_long, :pointer, :pointer]
 83      
 84      sodium_function :box_curve25519xsalsa20poly1305_afternm,
 85                      :crypto_box_curve25519xsalsa20poly1305_afternm,
 86                      [:pointer, :pointer, :ulong_long, :pointer, :pointer]
 87
 88      # Create a new Box
 89      #
 90      # Sets up the Box for deriving the shared key and encrypting and
 91      # decrypting messages.
 92      #
 93      # @param public_key [String,RbNaCl::PublicKey] The public key to encrypt to
 94      # @param private_key [String,RbNaCl::PrivateKey] The private key to encrypt with
 95      #
 96      # @raise [RbNaCl::LengthError] on invalid keys
 97      #
 98      # @return [RbNaCl::Box] The new Box, ready to use
 99      def initialize(public_key, private_key)
100        @public_key   = PublicKey  === public_key  ? public_key  : PublicKey.new(public_key)
101        @private_key  = PrivateKey === private_key ? private_key : PrivateKey.new(private_key)
102        raise IncorrectPrimitiveError unless @public_key.primitive == primitive && @private_key.primitive == primitive
103      end
104
105      # Encrypts a message
106      #
107      # Encrypts the message with the given nonce to the keypair set up when
108      # initializing the class.  Make sure the nonce is unique for any given
109      # keypair, or you might as well just send plain text.
110      #
111      # This function takes care of the padding required by the NaCL C API.
112      #
113      # @param nonce [String] A 24-byte string containing the nonce.
114      # @param message [String] The message to be encrypted.
115      #
116      # @raise [RbNaCl::LengthError] If the nonce is not valid
117      #
118      # @return [String] The ciphertext without the nonce prepended (BINARY encoded)
119      def box(nonce, message)
120        Util.check_length(nonce, nonce_bytes, "Nonce")
121        msg = Util.prepend_zeros(ZEROBYTES, message)
122        ct  = Util.zeros(msg.bytesize)
123
124        self.class.box_curve25519xsalsa20poly1305_afternm(ct, msg, msg.bytesize, nonce, beforenm) || raise(CryptoError, "Encryption failed")
125        Util.remove_zeros(BOXZEROBYTES, ct)
126      end
127      alias encrypt box
128
129      # Decrypts a ciphertext
130      #
131      # Decrypts the ciphertext with the given nonce using the keypair setup when
132      # initializing the class.
133      #
134      # This function takes care of the padding required by the NaCL C API.
135      #
136      # @param nonce [String] A 24-byte string containing the nonce.
137      # @param ciphertext [String] The message to be decrypted.
138      #
139      # @raise [RbNaCl::LengthError] If the nonce is not valid
140      # @raise [RbNaCl::CryptoError] If the ciphertext cannot be authenticated.
141      #
142      # @return [String] The decrypted message (BINARY encoded)
143      def open(nonce, ciphertext)
144        Util.check_length(nonce, nonce_bytes, "Nonce")
145        ct = Util.prepend_zeros(BOXZEROBYTES, ciphertext)
146        message  = Util.zeros(ct.bytesize)
147
148        self.class.box_curve25519xsalsa20poly1305_open_afternm(message, ct, ct.bytesize, nonce, beforenm) || raise(CryptoError, "Decryption failed. Ciphertext failed verification.")
149        Util.remove_zeros(ZEROBYTES, message)
150      end
151      alias decrypt open
152
153      # The crypto primitive for the box class
154      #
155      # @return [Symbol] The primitive used
156      def primitive
157        self.class.primitive
158      end
159
160      # The nonce bytes for the box class
161      #
162      # @return [Integer] The number of bytes in a valid nonce
163      def self.nonce_bytes
164        NONCEBYTES
165      end
166
167      # The nonce bytes for the box instance
168      #
169      # @return [Integer] The number of bytes in a valid nonce
170      def nonce_bytes
171        NONCEBYTES
172      end
173
174      private
175      def beforenm
176        @k ||= begin
177                 k = Util.zeros(BEFORENMBYTES)
178                 self.class.box_curve25519xsalsa20poly1305_beforenm(k, @public_key.to_s, @private_key.to_s) || raise(CryptoError, "Failed to derive shared key")
179                 k
180               end
181      end
182    end
183  end
184end