box.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /**
  2. * Created by bmf on 11/2/13.
  3. *
  4. * Documentation of crypto http://nacl.cr.yp.to/box.html
  5. */
  6. /* jslint node: true */
  7. 'use strict';
  8. var binding = require('../build/Release/sodium');
  9. var toBuffer = require('./toBuffer');
  10. var BoxKey = require('./keys/box-key');
  11. var Nonce = require('./nonces/box-nonce');
  12. var assert = require('assert');
  13. /**
  14. * Public-key authenticated encryption: Box
  15. *
  16. * @param {String|Buffer|Array} secretKey sender's private key.
  17. * @param {String|Buffer|Array} publicKey recipient's public key.
  18. * @param {Boolean} easy Use regular or easy mode. Defaults to regular
  19. *
  20. * @see Keys
  21. * @constructor
  22. */
  23. module.exports = function Box(publicKey, secretKey, easy) {
  24. var self = this;
  25. /** default encoding to use in all string operations */
  26. self.defaultEncoding = undefined;
  27. /** Set of keys used to encrypt and decrypt messages */
  28. self.boxKey = new BoxKey(publicKey, secretKey);
  29. /** Set mode to regular or easy */
  30. self.easy = easy || false;
  31. /**
  32. * Messages passed to low level API should be padded with zeroBytes at the beginning.
  33. * This implementation automatically pads the message, so no need to do it on your own
  34. */
  35. self.zeroBytes = function() {
  36. return binding.crypto_box_ZEROBYTES;
  37. };
  38. /**
  39. * Encrypted messages are padded with zeroBoxSize bytes of zeros. If the padding is not
  40. * there the message will not decrypt successfully.
  41. */
  42. self.boxZeroBytes = function() {
  43. return binding.crypto_box_BOXZEROBYTES;
  44. };
  45. /**
  46. * Padding used in beforenm method. Like zeroBytes this implementation automatically
  47. * pads the message.
  48. *
  49. * @see Const.Box.zeroBytes
  50. */
  51. self.beforenmBytes = function() {
  52. return binding.crypto_box_BEFORENMBYTES;
  53. };
  54. /** String name of the default crypto primitive used in box operations */
  55. self.primitive = function() {
  56. return binding.crypto_box_PRIMITIVE;
  57. };
  58. /**
  59. * Get the box-key secret keypair object
  60. * @returns {BoxKey|*}
  61. */
  62. self.key = function() {
  63. return self.boxKey;
  64. };
  65. /**
  66. * Set the default encoding to use in all string conversions
  67. * @param {String} encoding encoding to use
  68. */
  69. self.setEncoding = function(encoding) {
  70. assert(!!encoding.match(/^(?:utf8|ascii|binary|hex|utf16le|ucs2|base64)$/), 'Encoding ' + encoding + ' is currently unsupported.');
  71. self.defaultEncoding = encoding;
  72. };
  73. /**
  74. * Get the current default encoding
  75. * @returns {undefined|String}
  76. */
  77. self.getEncoding = function() {
  78. return self.defaultEncoding;
  79. };
  80. /**
  81. * Encrypt a message
  82. * The encrypt function encrypts and authenticates a message using the
  83. * sender's secret key, the receiver's public key, and a nonce n.
  84. *
  85. * If no options are given a new random nonce will be generated automatically
  86. * and both planText and cipherText must be buffers
  87. *
  88. * options.encoding is optional and specifies the encoding of the plainText
  89. * nonce, and cipherText if they are passed as strings. If plainText and
  90. * nonce are buffers, options.encoding will only affect the resulting
  91. * cipherText.
  92. * The basic API leaves it up to the
  93. * caller to generate a unique nonce for every message, in the high level
  94. * API a random nonce is generated automatically and you do no need to
  95. * worry about it.
  96. *
  97. * @param {Buffer|String|Array} plainText message to encrypt
  98. * @param {String} [encoding] encoding of message string
  99. *
  100. * @returns {Object} cipher box
  101. */
  102. self.encrypt = function (plainText, encoding) {
  103. encoding = encoding || self.defaultEncoding;
  104. // generate a new random nonce
  105. var nonce = new Nonce();
  106. var buf = toBuffer(plainText, encoding);
  107. var cipherText = (self.easy ? binding.crypto_box_easy : binding.crypto_box)(
  108. buf,
  109. nonce.get(),
  110. self.boxKey.getPublicKey().get(),
  111. self.boxKey.getSecretKey().get());
  112. if( !cipherText ) {
  113. return undefined;
  114. }
  115. return {
  116. cipherText: cipherText,
  117. nonce : nonce.get()
  118. };
  119. };
  120. /**
  121. * The decrypt function verifies and decrypts a cipherText using the
  122. * receiver's secret key, the sender's public key, and a nonce.
  123. * The function returns the resulting plaintext m.
  124. *
  125. * @param {Buffer|String|Array} cipherText the encrypted message
  126. * @param {Buffer|String|Array} nonce the nonce used to encrypt
  127. * @param {String} [encoding] the encoding to used in cipherText, nonce, plainText
  128. */
  129. self.decrypt = function (cipherBox, encoding) {
  130. encoding = String(encoding || self.defaultEncoding);
  131. assert(typeof cipherBox == 'object' && cipherBox.hasOwnProperty('cipherText') && cipherBox.hasOwnProperty('nonce'), 'cipherBox is an object with properties `cipherText` and `nonce`.');
  132. assert(cipherBox.cipherText instanceof Buffer, 'cipherBox should have a cipherText property that is a buffer') ;
  133. var nonce = new Nonce(cipherBox.nonce);
  134. var plainText = (self.easy ? binding.crypto_box_open_easy : binding.crypto_box_open)(
  135. cipherBox.cipherText,
  136. nonce.get(),
  137. self.boxKey.getPublicKey().get(),
  138. self.boxKey.getSecretKey().get()
  139. );
  140. if( encoding ) {
  141. return plainText.toString(encoding);
  142. }
  143. return plainText;
  144. };
  145. // Aliases
  146. self.close = self.encrypt;
  147. self.open = self.decrypt;
  148. };