174 lines
5.6 KiB
JavaScript
Executable file
174 lines
5.6 KiB
JavaScript
Executable file
/**
|
|
* Created by bmf on 11/2/13.
|
|
*
|
|
* Documentation of crypto http://nacl.cr.yp.to/box.html
|
|
*/
|
|
/* jslint node: true */
|
|
'use strict';
|
|
|
|
var binding = require('../build/Release/sodium');
|
|
var toBuffer = require('./toBuffer');
|
|
var BoxKey = require('./keys/box-key');
|
|
var Nonce = require('./nonces/box-nonce');
|
|
var assert = require('assert');
|
|
|
|
/**
|
|
* Public-key authenticated encryption: Box
|
|
*
|
|
* @param {String|Buffer|Array} secretKey sender's private key.
|
|
* @param {String|Buffer|Array} publicKey recipient's public key.
|
|
* @param {Boolean} easy Use regular or easy mode. Defaults to regular
|
|
*
|
|
* @see Keys
|
|
* @constructor
|
|
*/
|
|
module.exports = function Box(publicKey, secretKey, easy) {
|
|
var self = this;
|
|
|
|
/** default encoding to use in all string operations */
|
|
self.defaultEncoding = undefined;
|
|
|
|
/** Set of keys used to encrypt and decrypt messages */
|
|
self.boxKey = new BoxKey(publicKey, secretKey);
|
|
|
|
/** Set mode to regular or easy */
|
|
self.easy = easy || false;
|
|
|
|
/**
|
|
* Messages passed to low level API should be padded with zeroBytes at the beginning.
|
|
* This implementation automatically pads the message, so no need to do it on your own
|
|
*/
|
|
self.zeroBytes = function() {
|
|
return binding.crypto_box_ZEROBYTES;
|
|
};
|
|
|
|
/**
|
|
* Encrypted messages are padded with zeroBoxSize bytes of zeros. If the padding is not
|
|
* there the message will not decrypt successfully.
|
|
*/
|
|
self.boxZeroBytes = function() {
|
|
return binding.crypto_box_BOXZEROBYTES;
|
|
};
|
|
|
|
/**
|
|
* Padding used in beforenm method. Like zeroBytes this implementation automatically
|
|
* pads the message.
|
|
*
|
|
* @see Const.Box.zeroBytes
|
|
*/
|
|
self.beforenmBytes = function() {
|
|
return binding.crypto_box_BEFORENMBYTES;
|
|
};
|
|
|
|
/** String name of the default crypto primitive used in box operations */
|
|
self.primitive = function() {
|
|
return binding.crypto_box_PRIMITIVE;
|
|
};
|
|
|
|
/**
|
|
* Get the box-key secret keypair object
|
|
* @returns {BoxKey|*}
|
|
*/
|
|
self.key = function() {
|
|
return self.boxKey;
|
|
};
|
|
|
|
/**
|
|
* Set the default encoding to use in all string conversions
|
|
* @param {String} encoding encoding to use
|
|
*/
|
|
self.setEncoding = function(encoding) {
|
|
assert(!!encoding.match(/^(?:utf8|ascii|binary|hex|utf16le|ucs2|base64)$/), 'Encoding ' + encoding + ' is currently unsupported.');
|
|
self.defaultEncoding = encoding;
|
|
};
|
|
|
|
/**
|
|
* Get the current default encoding
|
|
* @returns {undefined|String}
|
|
*/
|
|
self.getEncoding = function() {
|
|
return self.defaultEncoding;
|
|
};
|
|
|
|
/**
|
|
* Encrypt a message
|
|
* The encrypt function encrypts and authenticates a message using the
|
|
* sender's secret key, the receiver's public key, and a nonce n.
|
|
*
|
|
* If no options are given a new random nonce will be generated automatically
|
|
* and both planText and cipherText must be buffers
|
|
*
|
|
* options.encoding is optional and specifies the encoding of the plainText
|
|
* nonce, and cipherText if they are passed as strings. If plainText and
|
|
* nonce are buffers, options.encoding will only affect the resulting
|
|
* cipherText.
|
|
* The basic API leaves it up to the
|
|
* caller to generate a unique nonce for every message, in the high level
|
|
* API a random nonce is generated automatically and you do no need to
|
|
* worry about it.
|
|
*
|
|
* @param {Buffer|String|Array} plainText message to encrypt
|
|
* @param {String} [encoding] encoding of message string
|
|
*
|
|
* @returns {Object} cipher box
|
|
*/
|
|
self.encrypt = function (plainText, encoding) {
|
|
encoding = encoding || self.defaultEncoding;
|
|
|
|
// generate a new random nonce
|
|
var nonce = new Nonce();
|
|
|
|
var buf = toBuffer(plainText, encoding);
|
|
var cipherText = (self.easy ? binding.crypto_box_easy : binding.crypto_box)(
|
|
buf,
|
|
nonce.get(),
|
|
self.boxKey.getPublicKey().get(),
|
|
self.boxKey.getSecretKey().get());
|
|
|
|
if( !cipherText ) {
|
|
return undefined;
|
|
}
|
|
|
|
return {
|
|
cipherText: cipherText,
|
|
nonce : nonce.get()
|
|
};
|
|
};
|
|
|
|
/**
|
|
* The decrypt function verifies and decrypts a cipherText using the
|
|
* receiver's secret key, the sender's public key, and a nonce.
|
|
* The function returns the resulting plaintext m.
|
|
*
|
|
* @param {Buffer|String|Array} cipherText the encrypted message
|
|
* @param {Buffer|String|Array} nonce the nonce used to encrypt
|
|
* @param {String} [encoding] the encoding to used in cipherText, nonce, plainText
|
|
*/
|
|
self.decrypt = function (cipherBox, encoding) {
|
|
encoding = String(encoding || self.defaultEncoding);
|
|
|
|
assert(typeof cipherBox == 'object' && cipherBox.hasOwnProperty('cipherText') && cipherBox.hasOwnProperty('nonce'), 'cipherBox is an object with properties `cipherText` and `nonce`.');
|
|
assert(cipherBox.cipherText instanceof Buffer, 'cipherBox should have a cipherText property that is a buffer') ;
|
|
|
|
var nonce = new Nonce(cipherBox.nonce);
|
|
|
|
var plainText = (self.easy ? binding.crypto_box_open_easy : binding.crypto_box_open)(
|
|
cipherBox.cipherText,
|
|
nonce.get(),
|
|
self.boxKey.getPublicKey().get(),
|
|
self.boxKey.getSecretKey().get()
|
|
);
|
|
|
|
if( encoding ) {
|
|
return plainText.toString(encoding);
|
|
}
|
|
|
|
return plainText;
|
|
};
|
|
|
|
// Aliases
|
|
self.close = self.encrypt;
|
|
self.open = self.decrypt;
|
|
};
|
|
|