1 // Note: In 0.8 and before, crypto functions all defaulted to using
2 // binary-encoded strings rather than buffers.
6 exports.DEFAULT_ENCODING = 'buffer';
9 var binding = process.binding('crypto');
10 var randomBytes = binding.randomBytes;
11 var pseudoRandomBytes = binding.pseudoRandomBytes;
12 var getCiphers = binding.getCiphers;
13 var getHashes = binding.getHashes;
15 throw new Error('node.js not compiled with openssl crypto support.');
18 const constants = require('constants');
19 const stream = require('stream');
20 const util = require('util');
22 const DH_GENERATOR = 2;
24 // This is here because many functions accepted binary strings without
25 // any explicit encoding in older versions of node, and we don't want
26 // to break them unnecessarily.
27 function toBuf(str, encoding) {
28 encoding = encoding || 'binary';
29 if (util.isString(str)) {
30 if (encoding === 'buffer')
32 str = new Buffer(str, encoding);
36 exports._toBuf = toBuf;
39 const assert = require('assert');
40 const StringDecoder = require('string_decoder').StringDecoder;
43 function LazyTransform(options) {
44 this._options = options;
46 util.inherits(LazyTransform, stream.Transform);
52 ].forEach(function(prop, i, props) {
53 Object.defineProperty(LazyTransform.prototype, prop, {
55 stream.Transform.call(this, this._options);
56 this._writableState.decodeStrings = false;
57 this._writableState.defaultEncoding = 'binary';
61 Object.defineProperty(this, prop, {
74 exports.createHash = exports.Hash = Hash;
75 function Hash(algorithm, options) {
76 if (!(this instanceof Hash))
77 return new Hash(algorithm, options);
78 this._handle = new binding.Hash(algorithm);
79 LazyTransform.call(this, options);
82 util.inherits(Hash, LazyTransform);
84 Hash.prototype._transform = function(chunk, encoding, callback) {
85 this._handle.update(chunk, encoding);
89 Hash.prototype._flush = function(callback) {
90 var encoding = this._readableState.encoding || 'buffer';
91 this.push(this._handle.digest(encoding), encoding);
95 Hash.prototype.update = function(data, encoding) {
96 encoding = encoding || exports.DEFAULT_ENCODING;
97 if (encoding === 'buffer' && util.isString(data))
99 this._handle.update(data, encoding);
104 Hash.prototype.digest = function(outputEncoding) {
105 outputEncoding = outputEncoding || exports.DEFAULT_ENCODING;
106 return this._handle.digest(outputEncoding);
110 exports.createHmac = exports.Hmac = Hmac;
112 function Hmac(hmac, key, options) {
113 if (!(this instanceof Hmac))
114 return new Hmac(hmac, key, options);
115 this._handle = new binding.Hmac();
116 this._handle.init(hmac, toBuf(key));
117 LazyTransform.call(this, options);
120 util.inherits(Hmac, LazyTransform);
122 Hmac.prototype.update = Hash.prototype.update;
123 Hmac.prototype.digest = Hash.prototype.digest;
124 Hmac.prototype._flush = Hash.prototype._flush;
125 Hmac.prototype._transform = Hash.prototype._transform;
128 function getDecoder(decoder, encoding) {
129 if (encoding === 'utf-8') encoding = 'utf8'; // Normalize encoding.
130 decoder = decoder || new StringDecoder(encoding);
131 assert(decoder.encoding === encoding, 'Cannot change encoding');
136 exports.createCipher = exports.Cipher = Cipher;
137 function Cipher(cipher, password, options) {
138 if (!(this instanceof Cipher))
139 return new Cipher(cipher, password, options);
140 this._handle = new binding.CipherBase(true);
142 this._handle.init(cipher, toBuf(password));
143 this._decoder = null;
145 LazyTransform.call(this, options);
148 util.inherits(Cipher, LazyTransform);
150 Cipher.prototype._transform = function(chunk, encoding, callback) {
151 this.push(this._handle.update(chunk, encoding));
155 Cipher.prototype._flush = function(callback) {
157 this.push(this._handle.final());
165 Cipher.prototype.update = function(data, inputEncoding, outputEncoding) {
166 inputEncoding = inputEncoding || exports.DEFAULT_ENCODING;
167 outputEncoding = outputEncoding || exports.DEFAULT_ENCODING;
169 var ret = this._handle.update(data, inputEncoding);
171 if (outputEncoding && outputEncoding !== 'buffer') {
172 this._decoder = getDecoder(this._decoder, outputEncoding);
173 ret = this._decoder.write(ret);
180 Cipher.prototype.final = function(outputEncoding) {
181 outputEncoding = outputEncoding || exports.DEFAULT_ENCODING;
182 var ret = this._handle.final();
184 if (outputEncoding && outputEncoding !== 'buffer') {
185 this._decoder = getDecoder(this._decoder, outputEncoding);
186 ret = this._decoder.end(ret);
193 Cipher.prototype.setAutoPadding = function(ap) {
194 this._handle.setAutoPadding(ap);
198 Cipher.prototype.getAuthTag = function() {
199 return this._handle.getAuthTag();
203 Cipher.prototype.setAuthTag = function(tagbuf) {
204 this._handle.setAuthTag(tagbuf);
207 Cipher.prototype.setAAD = function(aadbuf) {
208 this._handle.setAAD(aadbuf);
211 exports.createCipheriv = exports.Cipheriv = Cipheriv;
212 function Cipheriv(cipher, key, iv, options) {
213 if (!(this instanceof Cipheriv))
214 return new Cipheriv(cipher, key, iv, options);
215 this._handle = new binding.CipherBase(true);
216 this._handle.initiv(cipher, toBuf(key), toBuf(iv));
217 this._decoder = null;
219 LazyTransform.call(this, options);
222 util.inherits(Cipheriv, LazyTransform);
224 Cipheriv.prototype._transform = Cipher.prototype._transform;
225 Cipheriv.prototype._flush = Cipher.prototype._flush;
226 Cipheriv.prototype.update = Cipher.prototype.update;
227 Cipheriv.prototype.final = Cipher.prototype.final;
228 Cipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
229 Cipheriv.prototype.getAuthTag = Cipher.prototype.getAuthTag;
230 Cipheriv.prototype.setAuthTag = Cipher.prototype.setAuthTag;
231 Cipheriv.prototype.setAAD = Cipher.prototype.setAAD;
233 exports.createDecipher = exports.Decipher = Decipher;
234 function Decipher(cipher, password, options) {
235 if (!(this instanceof Decipher))
236 return new Decipher(cipher, password, options);
238 this._handle = new binding.CipherBase(false);
239 this._handle.init(cipher, toBuf(password));
240 this._decoder = null;
242 LazyTransform.call(this, options);
245 util.inherits(Decipher, LazyTransform);
247 Decipher.prototype._transform = Cipher.prototype._transform;
248 Decipher.prototype._flush = Cipher.prototype._flush;
249 Decipher.prototype.update = Cipher.prototype.update;
250 Decipher.prototype.final = Cipher.prototype.final;
251 Decipher.prototype.finaltol = Cipher.prototype.final;
252 Decipher.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
253 Decipher.prototype.getAuthTag = Cipher.prototype.getAuthTag;
254 Decipher.prototype.setAuthTag = Cipher.prototype.setAuthTag;
255 Decipher.prototype.setAAD = Cipher.prototype.setAAD;
258 exports.createDecipheriv = exports.Decipheriv = Decipheriv;
259 function Decipheriv(cipher, key, iv, options) {
260 if (!(this instanceof Decipheriv))
261 return new Decipheriv(cipher, key, iv, options);
263 this._handle = new binding.CipherBase(false);
264 this._handle.initiv(cipher, toBuf(key), toBuf(iv));
265 this._decoder = null;
267 LazyTransform.call(this, options);
270 util.inherits(Decipheriv, LazyTransform);
272 Decipheriv.prototype._transform = Cipher.prototype._transform;
273 Decipheriv.prototype._flush = Cipher.prototype._flush;
274 Decipheriv.prototype.update = Cipher.prototype.update;
275 Decipheriv.prototype.final = Cipher.prototype.final;
276 Decipheriv.prototype.finaltol = Cipher.prototype.final;
277 Decipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
278 Decipheriv.prototype.getAuthTag = Cipher.prototype.getAuthTag;
279 Decipheriv.prototype.setAuthTag = Cipher.prototype.setAuthTag;
280 Decipheriv.prototype.setAAD = Cipher.prototype.setAAD;
284 exports.createSign = exports.Sign = Sign;
285 function Sign(algorithm, options) {
286 if (!(this instanceof Sign))
287 return new Sign(algorithm, options);
288 this._handle = new binding.Sign();
289 this._handle.init(algorithm);
291 stream.Writable.call(this, options);
294 util.inherits(Sign, stream.Writable);
296 Sign.prototype._write = function(chunk, encoding, callback) {
297 this._handle.update(chunk, encoding);
301 Sign.prototype.update = Hash.prototype.update;
303 Sign.prototype.sign = function(options, encoding) {
305 throw new Error('No key provided to sign');
307 var key = options.key || options;
308 var passphrase = options.passphrase || null;
309 var ret = this._handle.sign(toBuf(key), null, passphrase);
311 encoding = encoding || exports.DEFAULT_ENCODING;
312 if (encoding && encoding !== 'buffer')
313 ret = ret.toString(encoding);
320 exports.createVerify = exports.Verify = Verify;
321 function Verify(algorithm, options) {
322 if (!(this instanceof Verify))
323 return new Verify(algorithm, options);
325 this._handle = new binding.Verify;
326 this._handle.init(algorithm);
328 stream.Writable.call(this, options);
331 util.inherits(Verify, stream.Writable);
333 Verify.prototype._write = Sign.prototype._write;
334 Verify.prototype.update = Sign.prototype.update;
336 Verify.prototype.verify = function(object, signature, sigEncoding) {
337 sigEncoding = sigEncoding || exports.DEFAULT_ENCODING;
338 return this._handle.verify(toBuf(object), toBuf(signature, sigEncoding));
341 exports.publicEncrypt = function(options, buffer) {
342 var key = options.key || options;
343 var padding = options.padding || constants.RSA_PKCS1_OAEP_PADDING;
344 return binding.publicEncrypt(toBuf(key), buffer, padding);
347 exports.privateDecrypt = function(options, buffer) {
348 var key = options.key || options;
349 var passphrase = options.passphrase || null;
350 var padding = options.padding || constants.RSA_PKCS1_OAEP_PADDING;
351 return binding.privateDecrypt(toBuf(key), buffer, padding, passphrase);
356 exports.createDiffieHellman = exports.DiffieHellman = DiffieHellman;
358 function DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding) {
359 if (!(this instanceof DiffieHellman))
360 return new DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding);
362 if (!util.isBuffer(sizeOrKey) &&
363 typeof sizeOrKey !== 'number' &&
364 typeof sizeOrKey !== 'string')
365 throw new TypeError('First argument should be number, string or Buffer');
368 if (typeof keyEncoding !== 'string' ||
369 (!Buffer.isEncoding(keyEncoding) && keyEncoding !== 'buffer')) {
370 genEncoding = generator;
371 generator = keyEncoding;
376 keyEncoding = keyEncoding || exports.DEFAULT_ENCODING;
377 genEncoding = genEncoding || exports.DEFAULT_ENCODING;
379 if (typeof sizeOrKey !== 'number')
380 sizeOrKey = toBuf(sizeOrKey, keyEncoding);
383 generator = DH_GENERATOR;
384 else if (typeof generator !== 'number')
385 generator = toBuf(generator, genEncoding);
387 this._handle = new binding.DiffieHellman(sizeOrKey, generator);
388 Object.defineProperty(this, 'verifyError', {
390 value: this._handle.verifyError,
396 exports.DiffieHellmanGroup =
397 exports.createDiffieHellmanGroup =
398 exports.getDiffieHellman = DiffieHellmanGroup;
400 function DiffieHellmanGroup(name) {
401 if (!(this instanceof DiffieHellmanGroup))
402 return new DiffieHellmanGroup(name);
403 this._handle = new binding.DiffieHellmanGroup(name);
404 Object.defineProperty(this, 'verifyError', {
406 value: this._handle.verifyError,
412 DiffieHellmanGroup.prototype.generateKeys =
413 DiffieHellman.prototype.generateKeys =
416 function dhGenerateKeys(encoding) {
417 var keys = this._handle.generateKeys();
418 encoding = encoding || exports.DEFAULT_ENCODING;
419 if (encoding && encoding !== 'buffer')
420 keys = keys.toString(encoding);
425 DiffieHellmanGroup.prototype.computeSecret =
426 DiffieHellman.prototype.computeSecret =
429 function dhComputeSecret(key, inEnc, outEnc) {
430 inEnc = inEnc || exports.DEFAULT_ENCODING;
431 outEnc = outEnc || exports.DEFAULT_ENCODING;
432 var ret = this._handle.computeSecret(toBuf(key, inEnc));
433 if (outEnc && outEnc !== 'buffer')
434 ret = ret.toString(outEnc);
439 DiffieHellmanGroup.prototype.getPrime =
440 DiffieHellman.prototype.getPrime =
443 function dhGetPrime(encoding) {
444 var prime = this._handle.getPrime();
445 encoding = encoding || exports.DEFAULT_ENCODING;
446 if (encoding && encoding !== 'buffer')
447 prime = prime.toString(encoding);
452 DiffieHellmanGroup.prototype.getGenerator =
453 DiffieHellman.prototype.getGenerator =
456 function dhGetGenerator(encoding) {
457 var generator = this._handle.getGenerator();
458 encoding = encoding || exports.DEFAULT_ENCODING;
459 if (encoding && encoding !== 'buffer')
460 generator = generator.toString(encoding);
465 DiffieHellmanGroup.prototype.getPublicKey =
466 DiffieHellman.prototype.getPublicKey =
469 function dhGetPublicKey(encoding) {
470 var key = this._handle.getPublicKey();
471 encoding = encoding || exports.DEFAULT_ENCODING;
472 if (encoding && encoding !== 'buffer')
473 key = key.toString(encoding);
478 DiffieHellmanGroup.prototype.getPrivateKey =
479 DiffieHellman.prototype.getPrivateKey =
482 function dhGetPrivateKey(encoding) {
483 var key = this._handle.getPrivateKey();
484 encoding = encoding || exports.DEFAULT_ENCODING;
485 if (encoding && encoding !== 'buffer')
486 key = key.toString(encoding);
491 DiffieHellman.prototype.setPublicKey = function(key, encoding) {
492 encoding = encoding || exports.DEFAULT_ENCODING;
493 this._handle.setPublicKey(toBuf(key, encoding));
498 DiffieHellman.prototype.setPrivateKey = function(key, encoding) {
499 encoding = encoding || exports.DEFAULT_ENCODING;
500 this._handle.setPrivateKey(toBuf(key, encoding));
505 function ECDH(curve) {
506 if (!util.isString(curve))
507 throw new TypeError('curve should be a string');
509 this._handle = new binding.ECDH(curve);
512 exports.createECDH = function createECDH(curve) {
513 return new ECDH(curve);
516 ECDH.prototype.computeSecret = DiffieHellman.prototype.computeSecret;
517 ECDH.prototype.setPrivateKey = DiffieHellman.prototype.setPrivateKey;
518 ECDH.prototype.setPublicKey = DiffieHellman.prototype.setPublicKey;
519 ECDH.prototype.getPrivateKey = DiffieHellman.prototype.getPrivateKey;
521 ECDH.prototype.generateKeys = function generateKeys(encoding, format) {
522 this._handle.generateKeys();
524 return this.getPublicKey(encoding, format);
527 ECDH.prototype.getPublicKey = function getPublicKey(encoding, format) {
530 if (typeof format === 'number')
532 if (format === 'compressed')
533 f = constants.POINT_CONVERSION_COMPRESSED;
534 else if (format === 'hybrid')
535 f = constants.POINT_CONVERSION_HYBRID;
537 else if (format === 'uncompressed')
538 f = constants.POINT_CONVERSION_UNCOMPRESSED;
540 throw TypeError('Bad format: ' + format);
542 f = constants.POINT_CONVERSION_UNCOMPRESSED;
544 var key = this._handle.getPublicKey(f);
545 encoding = encoding || exports.DEFAULT_ENCODING;
546 if (encoding && encoding !== 'buffer')
547 key = key.toString(encoding);
553 exports.pbkdf2 = function(password,
559 if (util.isFunction(digest)) {
564 if (!util.isFunction(callback))
565 throw new Error('No callback provided to pbkdf2');
567 return pbkdf2(password, salt, iterations, keylen, digest, callback);
571 exports.pbkdf2Sync = function(password, salt, iterations, keylen, digest) {
572 return pbkdf2(password, salt, iterations, keylen, digest);
576 function pbkdf2(password, salt, iterations, keylen, digest, callback) {
577 password = toBuf(password);
580 if (exports.DEFAULT_ENCODING === 'buffer')
581 return binding.PBKDF2(password, salt, iterations, keylen, digest, callback);
583 // at this point, we need to handle encodings.
584 var encoding = exports.DEFAULT_ENCODING;
586 var next = function(er, ret) {
588 ret = ret.toString(encoding);
591 binding.PBKDF2(password, salt, iterations, keylen, digest, next);
593 var ret = binding.PBKDF2(password, salt, iterations, keylen, digest);
594 return ret.toString(encoding);
599 exports.Certificate = Certificate;
601 function Certificate() {
602 if (!(this instanceof Certificate))
603 return new Certificate();
605 this._handle = new binding.Certificate();
609 Certificate.prototype.verifySpkac = function(object) {
610 return this._handle.verifySpkac(object);
614 Certificate.prototype.exportPublicKey = function(object, encoding) {
615 return this._handle.exportPublicKey(toBuf(object, encoding));
619 Certificate.prototype.exportChallenge = function(object, encoding) {
620 return this._handle.exportChallenge(toBuf(object, encoding));
624 exports.setEngine = function setEngine(id, flags) {
625 if (!util.isString(id))
626 throw new TypeError('id should be a string');
628 if (flags && !util.isNumber(flags))
629 throw new TypeError('flags should be a number, if present');
632 // Use provided engine for everything by default
634 flags = constants.ENGINE_METHOD_ALL;
636 return binding.setEngine(id, flags);
639 exports.randomBytes = randomBytes;
640 exports.pseudoRandomBytes = pseudoRandomBytes;
642 exports.rng = randomBytes;
643 exports.prng = pseudoRandomBytes;
646 exports.getCiphers = function() {
647 return filterDuplicates(getCiphers.call(null, arguments));
651 exports.getHashes = function() {
652 return filterDuplicates(getHashes.call(null, arguments));
657 function filterDuplicates(names) {
658 // Drop all-caps names in favor of their lowercase aliases,
659 // for example, 'sha1' instead of 'SHA1'.
661 names.forEach(function(name) {
663 if (/^[0-9A-Z\-]+$/.test(key)) key = key.toLowerCase();
664 if (!ctx.hasOwnProperty(key) || ctx[key] < name)
668 return Object.getOwnPropertyNames(ctx).map(function(key) {
674 exports.__defineGetter__('createCredentials', util.deprecate(function() {
675 return require('tls').createSecureContext;
676 }, 'createCredentials() is deprecated, use tls.createSecureContext instead'));
678 exports.__defineGetter__('Credentials', util.deprecate(function() {
679 return require('tls').SecureContext;
680 }, 'Credentials is deprecated, use tls.createSecureContext instead'));