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 getCiphers = binding.getCiphers;
12 var getHashes = binding.getHashes;
14 throw new Error('node.js not compiled with openssl crypto support.');
17 const constants = require('constants');
18 const stream = require('stream');
19 const util = require('util');
21 const DH_GENERATOR = 2;
23 // This is here because many functions accepted binary strings without
24 // any explicit encoding in older versions of node, and we don't want
25 // to break them unnecessarily.
26 function toBuf(str, encoding) {
27 encoding = encoding || 'binary';
28 if (util.isString(str)) {
29 if (encoding === 'buffer')
31 str = new Buffer(str, encoding);
35 exports._toBuf = toBuf;
38 const assert = require('assert');
39 const StringDecoder = require('string_decoder').StringDecoder;
42 function LazyTransform(options) {
43 this._options = options;
45 util.inherits(LazyTransform, stream.Transform);
51 ].forEach(function(prop, i, props) {
52 Object.defineProperty(LazyTransform.prototype, prop, {
54 stream.Transform.call(this, this._options);
55 this._writableState.decodeStrings = false;
56 this._writableState.defaultEncoding = 'binary';
60 Object.defineProperty(this, prop, {
73 exports.createHash = exports.Hash = Hash;
74 function Hash(algorithm, options) {
75 if (!(this instanceof Hash))
76 return new Hash(algorithm, options);
77 this._handle = new binding.Hash(algorithm);
78 LazyTransform.call(this, options);
81 util.inherits(Hash, LazyTransform);
83 Hash.prototype._transform = function(chunk, encoding, callback) {
84 this._handle.update(chunk, encoding);
88 Hash.prototype._flush = function(callback) {
89 var encoding = this._readableState.encoding || 'buffer';
90 this.push(this._handle.digest(encoding), encoding);
94 Hash.prototype.update = function(data, encoding) {
95 encoding = encoding || exports.DEFAULT_ENCODING;
96 if (encoding === 'buffer' && util.isString(data))
98 this._handle.update(data, encoding);
103 Hash.prototype.digest = function(outputEncoding) {
104 outputEncoding = outputEncoding || exports.DEFAULT_ENCODING;
105 return this._handle.digest(outputEncoding);
109 exports.createHmac = exports.Hmac = Hmac;
111 function Hmac(hmac, key, options) {
112 if (!(this instanceof Hmac))
113 return new Hmac(hmac, key, options);
114 this._handle = new binding.Hmac();
115 this._handle.init(hmac, toBuf(key));
116 LazyTransform.call(this, options);
119 util.inherits(Hmac, LazyTransform);
121 Hmac.prototype.update = Hash.prototype.update;
122 Hmac.prototype.digest = Hash.prototype.digest;
123 Hmac.prototype._flush = Hash.prototype._flush;
124 Hmac.prototype._transform = Hash.prototype._transform;
127 function getDecoder(decoder, encoding) {
128 if (encoding === 'utf-8') encoding = 'utf8'; // Normalize encoding.
129 decoder = decoder || new StringDecoder(encoding);
130 assert(decoder.encoding === encoding, 'Cannot change encoding');
135 exports.createCipher = exports.Cipher = Cipher;
136 function Cipher(cipher, password, options) {
137 if (!(this instanceof Cipher))
138 return new Cipher(cipher, password, options);
139 this._handle = new binding.CipherBase(true);
141 this._handle.init(cipher, toBuf(password));
142 this._decoder = null;
144 LazyTransform.call(this, options);
147 util.inherits(Cipher, LazyTransform);
149 Cipher.prototype._transform = function(chunk, encoding, callback) {
150 this.push(this._handle.update(chunk, encoding));
154 Cipher.prototype._flush = function(callback) {
156 this.push(this._handle.final());
164 Cipher.prototype.update = function(data, inputEncoding, outputEncoding) {
165 inputEncoding = inputEncoding || exports.DEFAULT_ENCODING;
166 outputEncoding = outputEncoding || exports.DEFAULT_ENCODING;
168 var ret = this._handle.update(data, inputEncoding);
170 if (outputEncoding && outputEncoding !== 'buffer') {
171 this._decoder = getDecoder(this._decoder, outputEncoding);
172 ret = this._decoder.write(ret);
179 Cipher.prototype.final = function(outputEncoding) {
180 outputEncoding = outputEncoding || exports.DEFAULT_ENCODING;
181 var ret = this._handle.final();
183 if (outputEncoding && outputEncoding !== 'buffer') {
184 this._decoder = getDecoder(this._decoder, outputEncoding);
185 ret = this._decoder.end(ret);
192 Cipher.prototype.setAutoPadding = function(ap) {
193 this._handle.setAutoPadding(ap);
197 Cipher.prototype.getAuthTag = function() {
198 return this._handle.getAuthTag();
202 Cipher.prototype.setAuthTag = function(tagbuf) {
203 this._handle.setAuthTag(tagbuf);
206 Cipher.prototype.setAAD = function(aadbuf) {
207 this._handle.setAAD(aadbuf);
210 exports.createCipheriv = exports.Cipheriv = Cipheriv;
211 function Cipheriv(cipher, key, iv, options) {
212 if (!(this instanceof Cipheriv))
213 return new Cipheriv(cipher, key, iv, options);
214 this._handle = new binding.CipherBase(true);
215 this._handle.initiv(cipher, toBuf(key), toBuf(iv));
216 this._decoder = null;
218 LazyTransform.call(this, options);
221 util.inherits(Cipheriv, LazyTransform);
223 Cipheriv.prototype._transform = Cipher.prototype._transform;
224 Cipheriv.prototype._flush = Cipher.prototype._flush;
225 Cipheriv.prototype.update = Cipher.prototype.update;
226 Cipheriv.prototype.final = Cipher.prototype.final;
227 Cipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
228 Cipheriv.prototype.getAuthTag = Cipher.prototype.getAuthTag;
229 Cipheriv.prototype.setAuthTag = Cipher.prototype.setAuthTag;
230 Cipheriv.prototype.setAAD = Cipher.prototype.setAAD;
232 exports.createDecipher = exports.Decipher = Decipher;
233 function Decipher(cipher, password, options) {
234 if (!(this instanceof Decipher))
235 return new Decipher(cipher, password, options);
237 this._handle = new binding.CipherBase(false);
238 this._handle.init(cipher, toBuf(password));
239 this._decoder = null;
241 LazyTransform.call(this, options);
244 util.inherits(Decipher, LazyTransform);
246 Decipher.prototype._transform = Cipher.prototype._transform;
247 Decipher.prototype._flush = Cipher.prototype._flush;
248 Decipher.prototype.update = Cipher.prototype.update;
249 Decipher.prototype.final = Cipher.prototype.final;
250 Decipher.prototype.finaltol = Cipher.prototype.final;
251 Decipher.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
252 Decipher.prototype.getAuthTag = Cipher.prototype.getAuthTag;
253 Decipher.prototype.setAuthTag = Cipher.prototype.setAuthTag;
254 Decipher.prototype.setAAD = Cipher.prototype.setAAD;
257 exports.createDecipheriv = exports.Decipheriv = Decipheriv;
258 function Decipheriv(cipher, key, iv, options) {
259 if (!(this instanceof Decipheriv))
260 return new Decipheriv(cipher, key, iv, options);
262 this._handle = new binding.CipherBase(false);
263 this._handle.initiv(cipher, toBuf(key), toBuf(iv));
264 this._decoder = null;
266 LazyTransform.call(this, options);
269 util.inherits(Decipheriv, LazyTransform);
271 Decipheriv.prototype._transform = Cipher.prototype._transform;
272 Decipheriv.prototype._flush = Cipher.prototype._flush;
273 Decipheriv.prototype.update = Cipher.prototype.update;
274 Decipheriv.prototype.final = Cipher.prototype.final;
275 Decipheriv.prototype.finaltol = Cipher.prototype.final;
276 Decipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
277 Decipheriv.prototype.getAuthTag = Cipher.prototype.getAuthTag;
278 Decipheriv.prototype.setAuthTag = Cipher.prototype.setAuthTag;
279 Decipheriv.prototype.setAAD = Cipher.prototype.setAAD;
283 exports.createSign = exports.Sign = Sign;
284 function Sign(algorithm, options) {
285 if (!(this instanceof Sign))
286 return new Sign(algorithm, options);
287 this._handle = new binding.Sign();
288 this._handle.init(algorithm);
290 stream.Writable.call(this, options);
293 util.inherits(Sign, stream.Writable);
295 Sign.prototype._write = function(chunk, encoding, callback) {
296 this._handle.update(chunk, encoding);
300 Sign.prototype.update = Hash.prototype.update;
302 Sign.prototype.sign = function(options, encoding) {
304 throw new Error('No key provided to sign');
306 var key = options.key || options;
307 var passphrase = options.passphrase || null;
308 var ret = this._handle.sign(toBuf(key), null, passphrase);
310 encoding = encoding || exports.DEFAULT_ENCODING;
311 if (encoding && encoding !== 'buffer')
312 ret = ret.toString(encoding);
319 exports.createVerify = exports.Verify = Verify;
320 function Verify(algorithm, options) {
321 if (!(this instanceof Verify))
322 return new Verify(algorithm, options);
324 this._handle = new binding.Verify;
325 this._handle.init(algorithm);
327 stream.Writable.call(this, options);
330 util.inherits(Verify, stream.Writable);
332 Verify.prototype._write = Sign.prototype._write;
333 Verify.prototype.update = Sign.prototype.update;
335 Verify.prototype.verify = function(object, signature, sigEncoding) {
336 sigEncoding = sigEncoding || exports.DEFAULT_ENCODING;
337 return this._handle.verify(toBuf(object), toBuf(signature, sigEncoding));
340 exports.publicEncrypt = function(options, buffer) {
341 var key = options.key || options;
342 var padding = options.padding || constants.RSA_PKCS1_OAEP_PADDING;
343 return binding.publicEncrypt(toBuf(key), buffer, padding);
346 exports.privateDecrypt = function(options, buffer) {
347 var key = options.key || options;
348 var passphrase = options.passphrase || null;
349 var padding = options.padding || constants.RSA_PKCS1_OAEP_PADDING;
350 return binding.privateDecrypt(toBuf(key), buffer, padding, passphrase);
355 exports.createDiffieHellman = exports.DiffieHellman = DiffieHellman;
357 function DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding) {
358 if (!(this instanceof DiffieHellman))
359 return new DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding);
361 if (!util.isBuffer(sizeOrKey) &&
362 typeof sizeOrKey !== 'number' &&
363 typeof sizeOrKey !== 'string')
364 throw new TypeError('First argument should be number, string or Buffer');
367 if (typeof keyEncoding !== 'string' ||
368 (!Buffer.isEncoding(keyEncoding) && keyEncoding !== 'buffer')) {
369 genEncoding = generator;
370 generator = keyEncoding;
375 keyEncoding = keyEncoding || exports.DEFAULT_ENCODING;
376 genEncoding = genEncoding || exports.DEFAULT_ENCODING;
378 if (typeof sizeOrKey !== 'number')
379 sizeOrKey = toBuf(sizeOrKey, keyEncoding);
382 generator = DH_GENERATOR;
383 else if (typeof generator !== 'number')
384 generator = toBuf(generator, genEncoding);
386 this._handle = new binding.DiffieHellman(sizeOrKey, generator);
387 Object.defineProperty(this, 'verifyError', {
389 value: this._handle.verifyError,
395 exports.DiffieHellmanGroup =
396 exports.createDiffieHellmanGroup =
397 exports.getDiffieHellman = DiffieHellmanGroup;
399 function DiffieHellmanGroup(name) {
400 if (!(this instanceof DiffieHellmanGroup))
401 return new DiffieHellmanGroup(name);
402 this._handle = new binding.DiffieHellmanGroup(name);
403 Object.defineProperty(this, 'verifyError', {
405 value: this._handle.verifyError,
411 DiffieHellmanGroup.prototype.generateKeys =
412 DiffieHellman.prototype.generateKeys =
415 function dhGenerateKeys(encoding) {
416 var keys = this._handle.generateKeys();
417 encoding = encoding || exports.DEFAULT_ENCODING;
418 if (encoding && encoding !== 'buffer')
419 keys = keys.toString(encoding);
424 DiffieHellmanGroup.prototype.computeSecret =
425 DiffieHellman.prototype.computeSecret =
428 function dhComputeSecret(key, inEnc, outEnc) {
429 inEnc = inEnc || exports.DEFAULT_ENCODING;
430 outEnc = outEnc || exports.DEFAULT_ENCODING;
431 var ret = this._handle.computeSecret(toBuf(key, inEnc));
432 if (outEnc && outEnc !== 'buffer')
433 ret = ret.toString(outEnc);
438 DiffieHellmanGroup.prototype.getPrime =
439 DiffieHellman.prototype.getPrime =
442 function dhGetPrime(encoding) {
443 var prime = this._handle.getPrime();
444 encoding = encoding || exports.DEFAULT_ENCODING;
445 if (encoding && encoding !== 'buffer')
446 prime = prime.toString(encoding);
451 DiffieHellmanGroup.prototype.getGenerator =
452 DiffieHellman.prototype.getGenerator =
455 function dhGetGenerator(encoding) {
456 var generator = this._handle.getGenerator();
457 encoding = encoding || exports.DEFAULT_ENCODING;
458 if (encoding && encoding !== 'buffer')
459 generator = generator.toString(encoding);
464 DiffieHellmanGroup.prototype.getPublicKey =
465 DiffieHellman.prototype.getPublicKey =
468 function dhGetPublicKey(encoding) {
469 var key = this._handle.getPublicKey();
470 encoding = encoding || exports.DEFAULT_ENCODING;
471 if (encoding && encoding !== 'buffer')
472 key = key.toString(encoding);
477 DiffieHellmanGroup.prototype.getPrivateKey =
478 DiffieHellman.prototype.getPrivateKey =
481 function dhGetPrivateKey(encoding) {
482 var key = this._handle.getPrivateKey();
483 encoding = encoding || exports.DEFAULT_ENCODING;
484 if (encoding && encoding !== 'buffer')
485 key = key.toString(encoding);
490 DiffieHellman.prototype.setPublicKey = function(key, encoding) {
491 encoding = encoding || exports.DEFAULT_ENCODING;
492 this._handle.setPublicKey(toBuf(key, encoding));
497 DiffieHellman.prototype.setPrivateKey = function(key, encoding) {
498 encoding = encoding || exports.DEFAULT_ENCODING;
499 this._handle.setPrivateKey(toBuf(key, encoding));
504 function ECDH(curve) {
505 if (!util.isString(curve))
506 throw new TypeError('curve should be a string');
508 this._handle = new binding.ECDH(curve);
511 exports.createECDH = function createECDH(curve) {
512 return new ECDH(curve);
515 ECDH.prototype.computeSecret = DiffieHellman.prototype.computeSecret;
516 ECDH.prototype.setPrivateKey = DiffieHellman.prototype.setPrivateKey;
517 ECDH.prototype.setPublicKey = DiffieHellman.prototype.setPublicKey;
518 ECDH.prototype.getPrivateKey = DiffieHellman.prototype.getPrivateKey;
520 ECDH.prototype.generateKeys = function generateKeys(encoding, format) {
521 this._handle.generateKeys();
523 return this.getPublicKey(encoding, format);
526 ECDH.prototype.getPublicKey = function getPublicKey(encoding, format) {
529 if (typeof format === 'number')
531 if (format === 'compressed')
532 f = constants.POINT_CONVERSION_COMPRESSED;
533 else if (format === 'hybrid')
534 f = constants.POINT_CONVERSION_HYBRID;
536 else if (format === 'uncompressed')
537 f = constants.POINT_CONVERSION_UNCOMPRESSED;
539 throw TypeError('Bad format: ' + format);
541 f = constants.POINT_CONVERSION_UNCOMPRESSED;
543 var key = this._handle.getPublicKey(f);
544 encoding = encoding || exports.DEFAULT_ENCODING;
545 if (encoding && encoding !== 'buffer')
546 key = key.toString(encoding);
552 exports.pbkdf2 = function(password,
558 if (util.isFunction(digest)) {
563 if (!util.isFunction(callback))
564 throw new Error('No callback provided to pbkdf2');
566 return pbkdf2(password, salt, iterations, keylen, digest, callback);
570 exports.pbkdf2Sync = function(password, salt, iterations, keylen, digest) {
571 return pbkdf2(password, salt, iterations, keylen, digest);
575 function pbkdf2(password, salt, iterations, keylen, digest, callback) {
576 password = toBuf(password);
579 if (exports.DEFAULT_ENCODING === 'buffer')
580 return binding.PBKDF2(password, salt, iterations, keylen, digest, callback);
582 // at this point, we need to handle encodings.
583 var encoding = exports.DEFAULT_ENCODING;
585 var next = function(er, ret) {
587 ret = ret.toString(encoding);
590 binding.PBKDF2(password, salt, iterations, keylen, digest, next);
592 var ret = binding.PBKDF2(password, salt, iterations, keylen, digest);
593 return ret.toString(encoding);
598 exports.Certificate = Certificate;
600 function Certificate() {
601 if (!(this instanceof Certificate))
602 return new Certificate();
604 this._handle = new binding.Certificate();
608 Certificate.prototype.verifySpkac = function(object) {
609 return this._handle.verifySpkac(object);
613 Certificate.prototype.exportPublicKey = function(object, encoding) {
614 return this._handle.exportPublicKey(toBuf(object, encoding));
618 Certificate.prototype.exportChallenge = function(object, encoding) {
619 return this._handle.exportChallenge(toBuf(object, encoding));
623 exports.setEngine = function setEngine(id, flags) {
624 if (!util.isString(id))
625 throw new TypeError('id should be a string');
627 if (flags && !util.isNumber(flags))
628 throw new TypeError('flags should be a number, if present');
631 // Use provided engine for everything by default
633 flags = constants.ENGINE_METHOD_ALL;
635 return binding.setEngine(id, flags);
638 exports.randomBytes = exports.pseudoRandomBytes = randomBytes;
640 exports.rng = exports.prng = randomBytes;
642 exports.getCiphers = function() {
643 return filterDuplicates(getCiphers.call(null, arguments));
647 exports.getHashes = function() {
648 return filterDuplicates(getHashes.call(null, arguments));
653 function filterDuplicates(names) {
654 // Drop all-caps names in favor of their lowercase aliases,
655 // for example, 'sha1' instead of 'SHA1'.
657 names.forEach(function(name) {
659 if (/^[0-9A-Z\-]+$/.test(key)) key = key.toLowerCase();
660 if (!ctx.hasOwnProperty(key) || ctx[key] < name)
664 return Object.getOwnPropertyNames(ctx).map(function(key) {
670 exports.__defineGetter__('createCredentials', util.deprecate(function() {
671 return require('tls').createSecureContext;
672 }, 'createCredentials() is deprecated, use tls.createSecureContext instead'));
674 exports.__defineGetter__('Credentials', util.deprecate(function() {
675 return require('tls').SecureContext;
676 }, 'Credentials is deprecated, use tls.createSecureContext instead'));