lib,src: make pseudoRandomBytes alias randomBytes
[platform/upstream/nodejs.git] / lib / crypto.js
1 // Note: In 0.8 and before, crypto functions all defaulted to using
2 // binary-encoded strings rather than buffers.
3
4 'use strict';
5
6 exports.DEFAULT_ENCODING = 'buffer';
7
8 try {
9   var binding = process.binding('crypto');
10   var randomBytes = binding.randomBytes;
11   var getCiphers = binding.getCiphers;
12   var getHashes = binding.getHashes;
13 } catch (e) {
14   throw new Error('node.js not compiled with openssl crypto support.');
15 }
16
17 const constants = require('constants');
18 const stream = require('stream');
19 const util = require('util');
20
21 const DH_GENERATOR = 2;
22
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')
30       encoding = 'binary';
31     str = new Buffer(str, encoding);
32   }
33   return str;
34 }
35 exports._toBuf = toBuf;
36
37
38 const assert = require('assert');
39 const StringDecoder = require('string_decoder').StringDecoder;
40
41
42 function LazyTransform(options) {
43   this._options = options;
44 }
45 util.inherits(LazyTransform, stream.Transform);
46
47 [
48   '_readableState',
49   '_writableState',
50   '_transformState'
51 ].forEach(function(prop, i, props) {
52   Object.defineProperty(LazyTransform.prototype, prop, {
53     get: function() {
54       stream.Transform.call(this, this._options);
55       this._writableState.decodeStrings = false;
56       this._writableState.defaultEncoding = 'binary';
57       return this[prop];
58     },
59     set: function(val) {
60       Object.defineProperty(this, prop, {
61         value: val,
62         enumerable: true,
63         configurable: true,
64         writable: true
65       });
66     },
67     configurable: true,
68     enumerable: true
69   });
70 });
71
72
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);
79 }
80
81 util.inherits(Hash, LazyTransform);
82
83 Hash.prototype._transform = function(chunk, encoding, callback) {
84   this._handle.update(chunk, encoding);
85   callback();
86 };
87
88 Hash.prototype._flush = function(callback) {
89   var encoding = this._readableState.encoding || 'buffer';
90   this.push(this._handle.digest(encoding), encoding);
91   callback();
92 };
93
94 Hash.prototype.update = function(data, encoding) {
95   encoding = encoding || exports.DEFAULT_ENCODING;
96   if (encoding === 'buffer' && util.isString(data))
97     encoding = 'binary';
98   this._handle.update(data, encoding);
99   return this;
100 };
101
102
103 Hash.prototype.digest = function(outputEncoding) {
104   outputEncoding = outputEncoding || exports.DEFAULT_ENCODING;
105   return this._handle.digest(outputEncoding);
106 };
107
108
109 exports.createHmac = exports.Hmac = Hmac;
110
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);
117 }
118
119 util.inherits(Hmac, LazyTransform);
120
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;
125
126
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');
131   return decoder;
132 }
133
134
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);
140
141   this._handle.init(cipher, toBuf(password));
142   this._decoder = null;
143
144   LazyTransform.call(this, options);
145 }
146
147 util.inherits(Cipher, LazyTransform);
148
149 Cipher.prototype._transform = function(chunk, encoding, callback) {
150   this.push(this._handle.update(chunk, encoding));
151   callback();
152 };
153
154 Cipher.prototype._flush = function(callback) {
155   try {
156     this.push(this._handle.final());
157   } catch (e) {
158     callback(e);
159     return;
160   }
161   callback();
162 };
163
164 Cipher.prototype.update = function(data, inputEncoding, outputEncoding) {
165   inputEncoding = inputEncoding || exports.DEFAULT_ENCODING;
166   outputEncoding = outputEncoding || exports.DEFAULT_ENCODING;
167
168   var ret = this._handle.update(data, inputEncoding);
169
170   if (outputEncoding && outputEncoding !== 'buffer') {
171     this._decoder = getDecoder(this._decoder, outputEncoding);
172     ret = this._decoder.write(ret);
173   }
174
175   return ret;
176 };
177
178
179 Cipher.prototype.final = function(outputEncoding) {
180   outputEncoding = outputEncoding || exports.DEFAULT_ENCODING;
181   var ret = this._handle.final();
182
183   if (outputEncoding && outputEncoding !== 'buffer') {
184     this._decoder = getDecoder(this._decoder, outputEncoding);
185     ret = this._decoder.end(ret);
186   }
187
188   return ret;
189 };
190
191
192 Cipher.prototype.setAutoPadding = function(ap) {
193   this._handle.setAutoPadding(ap);
194   return this;
195 };
196
197 Cipher.prototype.getAuthTag = function() {
198   return this._handle.getAuthTag();
199 };
200
201
202 Cipher.prototype.setAuthTag = function(tagbuf) {
203   this._handle.setAuthTag(tagbuf);
204 };
205
206 Cipher.prototype.setAAD = function(aadbuf) {
207   this._handle.setAAD(aadbuf);
208 };
209
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;
217
218   LazyTransform.call(this, options);
219 }
220
221 util.inherits(Cipheriv, LazyTransform);
222
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;
231
232 exports.createDecipher = exports.Decipher = Decipher;
233 function Decipher(cipher, password, options) {
234   if (!(this instanceof Decipher))
235     return new Decipher(cipher, password, options);
236
237   this._handle = new binding.CipherBase(false);
238   this._handle.init(cipher, toBuf(password));
239   this._decoder = null;
240
241   LazyTransform.call(this, options);
242 }
243
244 util.inherits(Decipher, LazyTransform);
245
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;
255
256
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);
261
262   this._handle = new binding.CipherBase(false);
263   this._handle.initiv(cipher, toBuf(key), toBuf(iv));
264   this._decoder = null;
265
266   LazyTransform.call(this, options);
267 }
268
269 util.inherits(Decipheriv, LazyTransform);
270
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;
280
281
282
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);
289
290   stream.Writable.call(this, options);
291 }
292
293 util.inherits(Sign, stream.Writable);
294
295 Sign.prototype._write = function(chunk, encoding, callback) {
296   this._handle.update(chunk, encoding);
297   callback();
298 };
299
300 Sign.prototype.update = Hash.prototype.update;
301
302 Sign.prototype.sign = function(options, encoding) {
303   if (!options)
304     throw new Error('No key provided to sign');
305
306   var key = options.key || options;
307   var passphrase = options.passphrase || null;
308   var ret = this._handle.sign(toBuf(key), null, passphrase);
309
310   encoding = encoding || exports.DEFAULT_ENCODING;
311   if (encoding && encoding !== 'buffer')
312     ret = ret.toString(encoding);
313
314   return ret;
315 };
316
317
318
319 exports.createVerify = exports.Verify = Verify;
320 function Verify(algorithm, options) {
321   if (!(this instanceof Verify))
322     return new Verify(algorithm, options);
323
324   this._handle = new binding.Verify;
325   this._handle.init(algorithm);
326
327   stream.Writable.call(this, options);
328 }
329
330 util.inherits(Verify, stream.Writable);
331
332 Verify.prototype._write = Sign.prototype._write;
333 Verify.prototype.update = Sign.prototype.update;
334
335 Verify.prototype.verify = function(object, signature, sigEncoding) {
336   sigEncoding = sigEncoding || exports.DEFAULT_ENCODING;
337   return this._handle.verify(toBuf(object), toBuf(signature, sigEncoding));
338 };
339
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);
344 };
345
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);
351 };
352
353
354
355 exports.createDiffieHellman = exports.DiffieHellman = DiffieHellman;
356
357 function DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding) {
358   if (!(this instanceof DiffieHellman))
359     return new DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding);
360
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');
365
366   if (keyEncoding) {
367     if (typeof keyEncoding !== 'string' ||
368         (!Buffer.isEncoding(keyEncoding) && keyEncoding !== 'buffer')) {
369       genEncoding = generator;
370       generator = keyEncoding;
371       keyEncoding = false;
372     }
373   }
374
375   keyEncoding = keyEncoding || exports.DEFAULT_ENCODING;
376   genEncoding = genEncoding || exports.DEFAULT_ENCODING;
377
378   if (typeof sizeOrKey !== 'number')
379     sizeOrKey = toBuf(sizeOrKey, keyEncoding);
380
381   if (!generator)
382     generator = DH_GENERATOR;
383   else if (typeof generator !== 'number')
384     generator = toBuf(generator, genEncoding);
385
386   this._handle = new binding.DiffieHellman(sizeOrKey, generator);
387   Object.defineProperty(this, 'verifyError', {
388     enumerable: true,
389     value: this._handle.verifyError,
390     writable: false
391   });
392 }
393
394
395 exports.DiffieHellmanGroup =
396     exports.createDiffieHellmanGroup =
397     exports.getDiffieHellman = DiffieHellmanGroup;
398
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', {
404     enumerable: true,
405     value: this._handle.verifyError,
406     writable: false
407   });
408 }
409
410
411 DiffieHellmanGroup.prototype.generateKeys =
412     DiffieHellman.prototype.generateKeys =
413     dhGenerateKeys;
414
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);
420   return keys;
421 }
422
423
424 DiffieHellmanGroup.prototype.computeSecret =
425     DiffieHellman.prototype.computeSecret =
426     dhComputeSecret;
427
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);
434   return ret;
435 }
436
437
438 DiffieHellmanGroup.prototype.getPrime =
439     DiffieHellman.prototype.getPrime =
440     dhGetPrime;
441
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);
447   return prime;
448 }
449
450
451 DiffieHellmanGroup.prototype.getGenerator =
452     DiffieHellman.prototype.getGenerator =
453     dhGetGenerator;
454
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);
460   return generator;
461 }
462
463
464 DiffieHellmanGroup.prototype.getPublicKey =
465     DiffieHellman.prototype.getPublicKey =
466     dhGetPublicKey;
467
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);
473   return key;
474 }
475
476
477 DiffieHellmanGroup.prototype.getPrivateKey =
478     DiffieHellman.prototype.getPrivateKey =
479     dhGetPrivateKey;
480
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);
486   return key;
487 }
488
489
490 DiffieHellman.prototype.setPublicKey = function(key, encoding) {
491   encoding = encoding || exports.DEFAULT_ENCODING;
492   this._handle.setPublicKey(toBuf(key, encoding));
493   return this;
494 };
495
496
497 DiffieHellman.prototype.setPrivateKey = function(key, encoding) {
498   encoding = encoding || exports.DEFAULT_ENCODING;
499   this._handle.setPrivateKey(toBuf(key, encoding));
500   return this;
501 };
502
503
504 function ECDH(curve) {
505   if (!util.isString(curve))
506     throw new TypeError('curve should be a string');
507
508   this._handle = new binding.ECDH(curve);
509 }
510
511 exports.createECDH = function createECDH(curve) {
512   return new ECDH(curve);
513 };
514
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;
519
520 ECDH.prototype.generateKeys = function generateKeys(encoding, format) {
521   this._handle.generateKeys();
522
523   return this.getPublicKey(encoding, format);
524 };
525
526 ECDH.prototype.getPublicKey = function getPublicKey(encoding, format) {
527   var f;
528   if (format) {
529     if (typeof format === 'number')
530       f = format;
531     if (format === 'compressed')
532       f = constants.POINT_CONVERSION_COMPRESSED;
533     else if (format === 'hybrid')
534       f = constants.POINT_CONVERSION_HYBRID;
535     // Default
536     else if (format === 'uncompressed')
537       f = constants.POINT_CONVERSION_UNCOMPRESSED;
538     else
539       throw TypeError('Bad format: ' + format);
540   } else {
541     f = constants.POINT_CONVERSION_UNCOMPRESSED;
542   }
543   var key = this._handle.getPublicKey(f);
544   encoding = encoding || exports.DEFAULT_ENCODING;
545   if (encoding && encoding !== 'buffer')
546     key = key.toString(encoding);
547   return key;
548 };
549
550
551
552 exports.pbkdf2 = function(password,
553                           salt,
554                           iterations,
555                           keylen,
556                           digest,
557                           callback) {
558   if (util.isFunction(digest)) {
559     callback = digest;
560     digest = undefined;
561   }
562
563   if (!util.isFunction(callback))
564     throw new Error('No callback provided to pbkdf2');
565
566   return pbkdf2(password, salt, iterations, keylen, digest, callback);
567 };
568
569
570 exports.pbkdf2Sync = function(password, salt, iterations, keylen, digest) {
571   return pbkdf2(password, salt, iterations, keylen, digest);
572 };
573
574
575 function pbkdf2(password, salt, iterations, keylen, digest, callback) {
576   password = toBuf(password);
577   salt = toBuf(salt);
578
579   if (exports.DEFAULT_ENCODING === 'buffer')
580     return binding.PBKDF2(password, salt, iterations, keylen, digest, callback);
581
582   // at this point, we need to handle encodings.
583   var encoding = exports.DEFAULT_ENCODING;
584   if (callback) {
585     var next = function(er, ret) {
586       if (ret)
587         ret = ret.toString(encoding);
588       callback(er, ret);
589     };
590     binding.PBKDF2(password, salt, iterations, keylen, digest, next);
591   } else {
592     var ret = binding.PBKDF2(password, salt, iterations, keylen, digest);
593     return ret.toString(encoding);
594   }
595 }
596
597
598 exports.Certificate = Certificate;
599
600 function Certificate() {
601   if (!(this instanceof Certificate))
602     return new Certificate();
603
604   this._handle = new binding.Certificate();
605 }
606
607
608 Certificate.prototype.verifySpkac = function(object) {
609   return this._handle.verifySpkac(object);
610 };
611
612
613 Certificate.prototype.exportPublicKey = function(object, encoding) {
614   return this._handle.exportPublicKey(toBuf(object, encoding));
615 };
616
617
618 Certificate.prototype.exportChallenge = function(object, encoding) {
619   return this._handle.exportChallenge(toBuf(object, encoding));
620 };
621
622
623 exports.setEngine = function setEngine(id, flags) {
624   if (!util.isString(id))
625     throw new TypeError('id should be a string');
626
627   if (flags && !util.isNumber(flags))
628     throw new TypeError('flags should be a number, if present');
629   flags = flags >>> 0;
630
631   // Use provided engine for everything by default
632   if (flags === 0)
633     flags = constants.ENGINE_METHOD_ALL;
634
635   return binding.setEngine(id, flags);
636 };
637
638 exports.randomBytes = exports.pseudoRandomBytes = randomBytes;
639
640 exports.rng = exports.prng = randomBytes;
641
642 exports.getCiphers = function() {
643   return filterDuplicates(getCiphers.call(null, arguments));
644 };
645
646
647 exports.getHashes = function() {
648   return filterDuplicates(getHashes.call(null, arguments));
649
650 };
651
652
653 function filterDuplicates(names) {
654   // Drop all-caps names in favor of their lowercase aliases,
655   // for example, 'sha1' instead of 'SHA1'.
656   var ctx = {};
657   names.forEach(function(name) {
658     var key = name;
659     if (/^[0-9A-Z\-]+$/.test(key)) key = key.toLowerCase();
660     if (!ctx.hasOwnProperty(key) || ctx[key] < name)
661       ctx[key] = name;
662   });
663
664   return Object.getOwnPropertyNames(ctx).map(function(key) {
665     return ctx[key];
666   }).sort();
667 }
668
669 // Legacy API
670 exports.__defineGetter__('createCredentials', util.deprecate(function() {
671   return require('tls').createSecureContext;
672 }, 'createCredentials() is deprecated, use tls.createSecureContext instead'));
673
674 exports.__defineGetter__('Credentials', util.deprecate(function() {
675   return require('tls').SecureContext;
676 }, 'Credentials is deprecated, use tls.createSecureContext instead'));