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