Merge branch 'v0.10'
[platform/upstream/nodejs.git] / lib / crypto.js
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 // Note: In 0.8 and before, crypto functions all defaulted to using
23 // binary-encoded strings rather than buffers.
24
25 exports.DEFAULT_ENCODING = 'buffer';
26
27 try {
28   var binding = process.binding('crypto');
29   var SecureContext = binding.SecureContext;
30   var randomBytes = binding.randomBytes;
31   var pseudoRandomBytes = binding.pseudoRandomBytes;
32   var getCiphers = binding.getCiphers;
33   var getHashes = binding.getHashes;
34   var crypto = true;
35 } catch (e) {
36
37   var crypto = false;
38 }
39
40 var stream = require('stream');
41 var util = require('util');
42
43 // This is here because many functions accepted binary strings without
44 // any explicit encoding in older versions of node, and we don't want
45 // to break them unnecessarily.
46 function toBuf(str, encoding) {
47   encoding = encoding || 'binary';
48   if (typeof str === 'string') {
49     if (encoding === 'buffer')
50       encoding = 'binary';
51     str = new Buffer(str, encoding);
52   }
53   return str;
54 }
55
56
57 var assert = require('assert');
58 var StringDecoder = require('string_decoder').StringDecoder;
59
60 function Credentials(secureProtocol, flags, context) {
61   if (!(this instanceof Credentials)) {
62     return new Credentials(secureProtocol, flags, context);
63   }
64
65   if (!crypto) {
66     throw new Error('node.js not compiled with openssl crypto support.');
67   }
68
69   if (context) {
70     this.context = context;
71   } else {
72     this.context = new SecureContext();
73
74     if (secureProtocol) {
75       this.context.init(secureProtocol);
76     } else {
77       this.context.init();
78     }
79   }
80
81   if (flags) this.context.setOptions(flags);
82 }
83
84 exports.Credentials = Credentials;
85
86
87 exports.createCredentials = function(options, context) {
88   if (!options) options = {};
89
90   var c = new Credentials(options.secureProtocol,
91                           options.secureOptions,
92                           context);
93
94   if (context) return c;
95
96   if (options.key) {
97     if (options.passphrase) {
98       c.context.setKey(options.key, options.passphrase);
99     } else {
100       c.context.setKey(options.key);
101     }
102   }
103
104   if (options.cert) c.context.setCert(options.cert);
105
106   if (options.ciphers) c.context.setCiphers(options.ciphers);
107
108   if (options.ca) {
109     if (Array.isArray(options.ca)) {
110       for (var i = 0, len = options.ca.length; i < len; i++) {
111         c.context.addCACert(options.ca[i]);
112       }
113     } else {
114       c.context.addCACert(options.ca);
115     }
116   } else {
117     c.context.addRootCerts();
118   }
119
120   if (options.crl) {
121     if (Array.isArray(options.crl)) {
122       for (var i = 0, len = options.crl.length; i < len; i++) {
123         c.context.addCRL(options.crl[i]);
124       }
125     } else {
126       c.context.addCRL(options.crl);
127     }
128   }
129
130   if (options.sessionIdContext) {
131     c.context.setSessionIdContext(options.sessionIdContext);
132   }
133
134   if (options.pfx) {
135     var pfx = options.pfx;
136     var passphrase = options.passphrase;
137
138     pfx = toBuf(pfx);
139     if (passphrase)
140       passphrase = toBuf(passphrase);
141
142     if (passphrase) {
143       c.context.loadPKCS12(pfx, passphrase);
144     } else {
145       c.context.loadPKCS12(pfx);
146     }
147   }
148
149   return c;
150 };
151
152
153 function LazyTransform(options) {
154   this._options = options;
155 }
156 util.inherits(LazyTransform, stream.Transform);
157
158 var transformMethods = ['read', 'write', 'end', 'pipe', 'unpipe',
159   'setEncoding', 'pause', 'resume'];
160
161 transformMethods.forEach(function(action, i, actions) {
162   LazyTransform.prototype[action] = function() {
163     stream.Transform.call(this, this._options);
164
165     actions.forEach(function(action) {
166       this[action] = stream.Transform.prototype[action];
167     }, this);
168
169     return this[action].apply(this, arguments);
170   };
171 });
172
173
174 exports.createHash = exports.Hash = Hash;
175 function Hash(algorithm, options) {
176   if (!(this instanceof Hash))
177     return new Hash(algorithm, options);
178   this._binding = new binding.Hash(algorithm);
179   LazyTransform.call(this, options);
180 }
181
182 util.inherits(Hash, LazyTransform);
183
184 Hash.prototype._transform = function(chunk, encoding, callback) {
185   this._binding.update(chunk, encoding);
186   callback();
187 };
188
189 Hash.prototype._flush = function(callback) {
190   this.push(this._binding.digest());
191   callback();
192 };
193
194 Hash.prototype.update = function(data, encoding) {
195   encoding = encoding || exports.DEFAULT_ENCODING;
196   data = toBuf(data, encoding);
197   this._binding.update(data);
198   return this;
199 };
200
201
202 Hash.prototype.digest = function(outputEncoding) {
203   outputEncoding = outputEncoding || exports.DEFAULT_ENCODING;
204   var result = this._binding.digest();
205   if (outputEncoding && outputEncoding !== 'buffer')
206     result = result.toString(outputEncoding);
207   return result;
208 };
209
210
211 exports.createHmac = exports.Hmac = Hmac;
212
213 function Hmac(hmac, key, options) {
214   if (!(this instanceof Hmac))
215     return new Hmac(hmac, key, options);
216   this._binding = new binding.Hmac();
217   this._binding.init(hmac, toBuf(key));
218   LazyTransform.call(this, options);
219 }
220
221 util.inherits(Hmac, LazyTransform);
222
223 Hmac.prototype.update = Hash.prototype.update;
224 Hmac.prototype.digest = Hash.prototype.digest;
225 Hmac.prototype._flush = Hash.prototype._flush;
226 Hmac.prototype._transform = Hash.prototype._transform;
227
228
229 function getDecoder(decoder, encoding) {
230   decoder = decoder || new StringDecoder(encoding);
231   assert(decoder.encoding === encoding, 'Cannot change encoding');
232   return decoder;
233 }
234
235
236 exports.createCipher = exports.Cipher = Cipher;
237 function Cipher(cipher, password, options) {
238   if (!(this instanceof Cipher))
239     return new Cipher(cipher, password, options);
240   this._binding = new binding.CipherBase(true);
241
242   this._binding.init(cipher, toBuf(password));
243   this._decoder = null;
244
245   LazyTransform.call(this, options);
246 }
247
248 util.inherits(Cipher, LazyTransform);
249
250 Cipher.prototype._transform = function(chunk, encoding, callback) {
251   this.push(this._binding.update(chunk, encoding));
252   callback();
253 };
254
255 Cipher.prototype._flush = function(callback) {
256   this.push(this._binding.final());
257   callback();
258 };
259
260 Cipher.prototype.update = function(data, inputEncoding, outputEncoding) {
261   inputEncoding = inputEncoding || exports.DEFAULT_ENCODING;
262   outputEncoding = outputEncoding || exports.DEFAULT_ENCODING;
263   data = toBuf(data, inputEncoding);
264
265   var ret = this._binding.update(data);
266
267   if (outputEncoding && outputEncoding !== 'buffer') {
268     this._decoder = getDecoder(this._decoder, outputEncoding);
269     ret = this._decoder.write(ret);
270   }
271
272   return ret;
273 };
274
275
276 Cipher.prototype.final = function(outputEncoding) {
277   outputEncoding = outputEncoding || exports.DEFAULT_ENCODING;
278   var ret = this._binding.final();
279
280   if (outputEncoding && outputEncoding !== 'buffer') {
281     this._decoder = getDecoder(this._decoder, outputEncoding);
282     ret = this._decoder.end(ret);
283   }
284
285   return ret;
286 };
287
288
289 Cipher.prototype.setAutoPadding = function(ap) {
290   this._binding.setAutoPadding(ap);
291   return this;
292 };
293
294
295
296 exports.createCipheriv = exports.Cipheriv = Cipheriv;
297 function Cipheriv(cipher, key, iv, options) {
298   if (!(this instanceof Cipheriv))
299     return new Cipheriv(cipher, key, iv, options);
300   this._binding = new binding.CipherBase(true);
301   this._binding.initiv(cipher, toBuf(key), toBuf(iv));
302   this._decoder = null;
303
304   LazyTransform.call(this, options);
305 }
306
307 util.inherits(Cipheriv, LazyTransform);
308
309 Cipheriv.prototype._transform = Cipher.prototype._transform;
310 Cipheriv.prototype._flush = Cipher.prototype._flush;
311 Cipheriv.prototype.update = Cipher.prototype.update;
312 Cipheriv.prototype.final = Cipher.prototype.final;
313 Cipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
314
315
316
317 exports.createDecipher = exports.Decipher = Decipher;
318 function Decipher(cipher, password, options) {
319   if (!(this instanceof Decipher))
320     return new Decipher(cipher, password, options);
321
322   this._binding = new binding.CipherBase(false);
323   this._binding.init(cipher, toBuf(password));
324   this._decoder = null;
325
326   LazyTransform.call(this, options);
327 }
328
329 util.inherits(Decipher, LazyTransform);
330
331 Decipher.prototype._transform = Cipher.prototype._transform;
332 Decipher.prototype._flush = Cipher.prototype._flush;
333 Decipher.prototype.update = Cipher.prototype.update;
334 Decipher.prototype.final = Cipher.prototype.final;
335 Decipher.prototype.finaltol = Cipher.prototype.final;
336 Decipher.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
337
338
339
340 exports.createDecipheriv = exports.Decipheriv = Decipheriv;
341 function Decipheriv(cipher, key, iv, options) {
342   if (!(this instanceof Decipheriv))
343     return new Decipheriv(cipher, key, iv, options);
344
345   this._binding = new binding.CipherBase(false);
346   this._binding.initiv(cipher, toBuf(key), toBuf(iv));
347   this._decoder = null;
348
349   LazyTransform.call(this, options);
350 }
351
352 util.inherits(Decipheriv, LazyTransform);
353
354 Decipheriv.prototype._transform = Cipher.prototype._transform;
355 Decipheriv.prototype._flush = Cipher.prototype._flush;
356 Decipheriv.prototype.update = Cipher.prototype.update;
357 Decipheriv.prototype.final = Cipher.prototype.final;
358 Decipheriv.prototype.finaltol = Cipher.prototype.final;
359 Decipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
360
361
362
363 exports.createSign = exports.Sign = Sign;
364 function Sign(algorithm, options) {
365   if (!(this instanceof Sign))
366     return new Sign(algorithm, options);
367   this._binding = new binding.Sign();
368   this._binding.init(algorithm);
369
370   stream.Writable.call(this, options);
371 }
372
373 util.inherits(Sign, stream.Writable);
374
375 Sign.prototype._write = function(chunk, encoding, callback) {
376   this._binding.update(chunk, encoding);
377   callback();
378 };
379
380 Sign.prototype.update = Hash.prototype.update;
381
382 Sign.prototype.sign = function(key, encoding) {
383   encoding = encoding || exports.DEFAULT_ENCODING;
384   var ret = this._binding.sign(toBuf(key));
385
386   if (encoding && encoding !== 'buffer')
387     ret = ret.toString(encoding);
388
389   return ret;
390 };
391
392
393
394 exports.createVerify = exports.Verify = Verify;
395 function Verify(algorithm, options) {
396   if (!(this instanceof Verify))
397     return new Verify(algorithm, options);
398
399   this._binding = new binding.Verify;
400   this._binding.init(algorithm);
401
402   stream.Writable.call(this, options);
403 }
404
405 util.inherits(Verify, stream.Writable);
406
407 Verify.prototype._write = Sign.prototype._write;
408 Verify.prototype.update = Sign.prototype.update;
409
410 Verify.prototype.verify = function(object, signature, sigEncoding) {
411   sigEncoding = sigEncoding || exports.DEFAULT_ENCODING;
412   return this._binding.verify(toBuf(object), toBuf(signature, sigEncoding));
413 };
414
415
416
417 exports.createDiffieHellman = exports.DiffieHellman = DiffieHellman;
418
419 function DiffieHellman(sizeOrKey, encoding) {
420   if (!(this instanceof DiffieHellman))
421     return new DiffieHellman(sizeOrKey, encoding);
422
423   if (!sizeOrKey)
424     this._binding = new binding.DiffieHellman();
425   else {
426     encoding = encoding || exports.DEFAULT_ENCODING;
427     sizeOrKey = toBuf(sizeOrKey, encoding);
428     this._binding = new binding.DiffieHellman(sizeOrKey);
429   }
430 }
431
432
433 exports.DiffieHellmanGroup =
434     exports.createDiffieHellmanGroup =
435     exports.getDiffieHellman = DiffieHellmanGroup;
436
437 function DiffieHellmanGroup(name) {
438   if (!(this instanceof DiffieHellmanGroup))
439     return new DiffieHellmanGroup(name);
440   this._binding = new binding.DiffieHellmanGroup(name);
441 }
442
443
444 DiffieHellmanGroup.prototype.generateKeys =
445     DiffieHellman.prototype.generateKeys =
446     dhGenerateKeys;
447
448 function dhGenerateKeys(encoding) {
449   var keys = this._binding.generateKeys();
450   encoding = encoding || exports.DEFAULT_ENCODING;
451   if (encoding && encoding !== 'buffer')
452     keys = keys.toString(encoding);
453   return keys;
454 }
455
456
457 DiffieHellmanGroup.prototype.computeSecret =
458     DiffieHellman.prototype.computeSecret =
459     dhComputeSecret;
460
461 function dhComputeSecret(key, inEnc, outEnc) {
462   inEnc = inEnc || exports.DEFAULT_ENCODING;
463   outEnc = outEnc || exports.DEFAULT_ENCODING;
464   var ret = this._binding.computeSecret(toBuf(key, inEnc));
465   if (outEnc && outEnc !== 'buffer')
466     ret = ret.toString(outEnc);
467   return ret;
468 }
469
470
471 DiffieHellmanGroup.prototype.getPrime =
472     DiffieHellman.prototype.getPrime =
473     dhGetPrime;
474
475 function dhGetPrime(encoding) {
476   var prime = this._binding.getPrime();
477   encoding = encoding || exports.DEFAULT_ENCODING;
478   if (encoding && encoding !== 'buffer')
479     prime = prime.toString(encoding);
480   return prime;
481 }
482
483
484 DiffieHellmanGroup.prototype.getGenerator =
485     DiffieHellman.prototype.getGenerator =
486     dhGetGenerator;
487
488 function dhGetGenerator(encoding) {
489   var generator = this._binding.getGenerator();
490   encoding = encoding || exports.DEFAULT_ENCODING;
491   if (encoding && encoding !== 'buffer')
492     generator = generator.toString(encoding);
493   return generator;
494 }
495
496
497 DiffieHellmanGroup.prototype.getPublicKey =
498     DiffieHellman.prototype.getPublicKey =
499     dhGetPublicKey;
500
501 function dhGetPublicKey(encoding) {
502   var key = this._binding.getPublicKey();
503   encoding = encoding || exports.DEFAULT_ENCODING;
504   if (encoding && encoding !== 'buffer')
505     key = key.toString(encoding);
506   return key;
507 }
508
509
510 DiffieHellmanGroup.prototype.getPrivateKey =
511     DiffieHellman.prototype.getPrivateKey =
512     dhGetPrivateKey;
513
514 function dhGetPrivateKey(encoding) {
515   var key = this._binding.getPrivateKey();
516   encoding = encoding || exports.DEFAULT_ENCODING;
517   if (encoding && encoding !== 'buffer')
518     key = key.toString(encoding);
519   return key;
520 }
521
522
523 DiffieHellman.prototype.setPublicKey = function(key, encoding) {
524   encoding = encoding || exports.DEFAULT_ENCODING;
525   this._binding.setPublicKey(toBuf(key, encoding));
526   return this;
527 };
528
529
530 DiffieHellman.prototype.setPrivateKey = function(key, encoding) {
531   encoding = encoding || exports.DEFAULT_ENCODING;
532   this._binding.setPrivateKey(toBuf(key, encoding));
533   return this;
534 };
535
536
537
538 exports.pbkdf2 = function(password, salt, iterations, keylen, callback) {
539   if (typeof callback !== 'function')
540     throw new Error('No callback provided to pbkdf2');
541
542   return pbkdf2(password, salt, iterations, keylen, callback);
543 };
544
545
546 exports.pbkdf2Sync = function(password, salt, iterations, keylen) {
547   return pbkdf2(password, salt, iterations, keylen);
548 };
549
550
551 function pbkdf2(password, salt, iterations, keylen, callback) {
552   password = toBuf(password);
553   salt = toBuf(salt);
554
555   if (exports.DEFAULT_ENCODING === 'buffer')
556     return binding.PBKDF2(password, salt, iterations, keylen, callback);
557
558   // at this point, we need to handle encodings.
559   var encoding = exports.DEFAULT_ENCODING;
560   if (callback) {
561     binding.PBKDF2(password, salt, iterations, keylen, function(er, ret) {
562       if (ret)
563         ret = ret.toString(encoding);
564       callback(er, ret);
565     });
566   } else {
567     var ret = binding.PBKDF2(password, salt, iterations, keylen);
568     return ret.toString(encoding);
569   }
570 }
571
572
573
574 exports.randomBytes = randomBytes;
575 exports.pseudoRandomBytes = pseudoRandomBytes;
576
577 exports.rng = randomBytes;
578 exports.prng = pseudoRandomBytes;
579
580
581 exports.getCiphers = function() {
582   return filterDuplicates(getCiphers.call(null, arguments));
583 };
584
585
586 exports.getHashes = function() {
587   return filterDuplicates(getHashes.call(null, arguments));
588
589 };
590
591
592 function filterDuplicates(names) {
593   // Drop all-caps names in favor of their lowercase aliases,
594   // for example, 'sha1' instead of 'SHA1'.
595   var ctx = {};
596   names.forEach(function(name) {
597     if (/^[0-9A-Z\-]+$/.test(name)) name = name.toLowerCase();
598     ctx[name] = true;
599   });
600   return Object.getOwnPropertyNames(ctx).sort();
601 }