/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
  2. module 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. sodium_type :box
  67. sodium_primitive :curve25519xsalsa20poly1305
  68. sodium_constant :NONCEBYTES
  69. sodium_constant :ZEROBYTES
  70. sodium_constant :BOXZEROBYTES
  71. sodium_constant :BEFORENMBYTES
  72. sodium_constant :PUBLICKEYBYTES
  73. sodium_constant :SECRETKEYBYTES, :PRIVATEKEYBYTES
  74. sodium_function :box_curve25519xsalsa20poly1305_beforenm,
  75. :crypto_box_curve25519xsalsa20poly1305_beforenm,
  76. [:pointer, :pointer, :pointer]
  77. sodium_function :box_curve25519xsalsa20poly1305_open_afternm,
  78. :crypto_box_curve25519xsalsa20poly1305_open_afternm,
  79. [:pointer, :pointer, :ulong_long, :pointer, :pointer]
  80. sodium_function :box_curve25519xsalsa20poly1305_afternm,
  81. :crypto_box_curve25519xsalsa20poly1305_afternm,
  82. [:pointer, :pointer, :ulong_long, :pointer, :pointer]
  83. # Create a new Box
  84. #
  85. # Sets up the Box for deriving the shared key and encrypting and
  86. # decrypting messages.
  87. #
  88. # @param public_key [String,RbNaCl::PublicKey] The public key to encrypt to
  89. # @param private_key [String,RbNaCl::PrivateKey] The private key to encrypt with
  90. #
  91. # @raise [RbNaCl::LengthError] on invalid keys
  92. #
  93. # @return [RbNaCl::Box] The new Box, ready to use
  94. def initialize(public_key, private_key)
  95. @public_key = PublicKey === public_key ? public_key : PublicKey.new(public_key)
  96. @private_key = PrivateKey === private_key ? private_key : PrivateKey.new(private_key)
  97. raise IncorrectPrimitiveError unless @public_key.primitive == primitive && @private_key.primitive == primitive
  98. end
  99. # Encrypts a message
  100. #
  101. # Encrypts the message with the given nonce to the keypair set up when
  102. # initializing the class. Make sure the nonce is unique for any given
  103. # keypair, or you might as well just send plain text.
  104. #
  105. # This function takes care of the padding required by the NaCL C API.
  106. #
  107. # @param nonce [String] A 24-byte string containing the nonce.
  108. # @param message [String] The message to be encrypted.
  109. #
  110. # @raise [RbNaCl::LengthError] If the nonce is not valid
  111. #
  112. # @return [String] The ciphertext without the nonce prepended (BINARY encoded)
  113. def box(nonce, message)
  114. Util.check_length(nonce, nonce_bytes, "Nonce")
  115. msg = Util.prepend_zeros(ZEROBYTES, message)
  116. ct = Util.zeros(msg.bytesize)
  117. self.class.box_curve25519xsalsa20poly1305_afternm(ct, msg, msg.bytesize, nonce, beforenm) || raise(CryptoError, "Encryption failed")
  118. Util.remove_zeros(BOXZEROBYTES, ct)
  119. end
  120. alias encrypt box
  121. # Decrypts a ciphertext
  122. #
  123. # Decrypts the ciphertext with the given nonce using the keypair setup when
  124. # initializing the class.
  125. #
  126. # This function takes care of the padding required by the NaCL C API.
  127. #
  128. # @param nonce [String] A 24-byte string containing the nonce.
  129. # @param ciphertext [String] The message to be decrypted.
  130. #
  131. # @raise [RbNaCl::LengthError] If the nonce is not valid
  132. # @raise [RbNaCl::CryptoError] If the ciphertext cannot be authenticated.
  133. #
  134. # @return [String] The decrypted message (BINARY encoded)
  135. def open(nonce, ciphertext)
  136. Util.check_length(nonce, nonce_bytes, "Nonce")
  137. ct = Util.prepend_zeros(BOXZEROBYTES, ciphertext)
  138. message = Util.zeros(ct.bytesize)
  139. self.class.box_curve25519xsalsa20poly1305_open_afternm(message, ct, ct.bytesize, nonce, beforenm) || raise(CryptoError, "Decryption failed. Ciphertext failed verification.")
  140. Util.remove_zeros(ZEROBYTES, message)
  141. end
  142. alias decrypt open
  143. # The crypto primitive for the box class
  144. #
  145. # @return [Symbol] The primitive used
  146. def primitive
  147. self.class.primitive
  148. end
  149. # The nonce bytes for the box class
  150. #
  151. # @return [Integer] The number of bytes in a valid nonce
  152. def self.nonce_bytes
  153. NONCEBYTES
  154. end
  155. # The nonce bytes for the box instance
  156. #
  157. # @return [Integer] The number of bytes in a valid nonce
  158. def nonce_bytes
  159. NONCEBYTES
  160. end
  161. private
  162. def beforenm
  163. @k ||= begin
  164. k = Util.zeros(BEFORENMBYTES)
  165. self.class.box_curve25519xsalsa20poly1305_beforenm(k, @public_key.to_s, @private_key.to_s) || raise(CryptoError, "Failed to derive shared key")
  166. k
  167. end
  168. end
  169. end
  170. end
  171. end