UNPKG

55.5 kBMarkdownView Raw
1# Forge
2
3[![npm package](https://nodei.co/npm/node-forge.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/node-forge/)
4
5[![Build status](https://img.shields.io/travis/digitalbazaar/forge.svg?branch=master)](https://travis-ci.org/digitalbazaar/forge)
6
7A native implementation of [TLS][] (and various other cryptographic tools) in
8[JavaScript][].
9
10Introduction
11------------
12
13The Forge software is a fully native implementation of the [TLS][] protocol
14in JavaScript, a set of cryptography utilities, and a set of tools for
15developing Web Apps that utilize many network resources.
16
17Performance
18------------
19
20Forge is fast. Benchmarks against other popular JavaScript cryptography
21libraries can be found here:
22
23* http://dominictarr.github.io/crypto-bench/
24* http://cryptojs.altervista.org/test/simulate-threading-speed_test.html
25
26Documentation
27-------------
28
29* [Introduction](#introduction)
30* [Performance](#performance)
31* [Installation](#installation)
32* [Testing](#testing)
33* [Contributing](#contributing)
34
35### API
36
37* [Options](#options)
38
39### Transports
40
41* [TLS](#tls)
42* [HTTP](#http)
43* [SSH](#ssh)
44* [XHR](#xhr)
45* [Sockets](#socket)
46
47### Ciphers
48
49* [CIPHER](#cipher)
50* [AES](#aes)
51* [DES](#des)
52* [RC2](#rc2)
53
54### PKI
55
56* [RSA](#rsa)
57* [RSA-KEM](#rsakem)
58* [X.509](#x509)
59* [PKCS#5](#pkcs5)
60* [PKCS#7](#pkcs7)
61* [PKCS#8](#pkcs8)
62* [PKCS#10](#pkcs10)
63* [PKCS#12](#pkcs12)
64* [ASN.1](#asn)
65
66### Message Digests
67
68* [SHA1](#sha1)
69* [SHA256](#sha256)
70* [SHA384](#sha384)
71* [SHA512](#sha512)
72* [MD5](#md5)
73* [HMAC](#hmac)
74
75### Utilities
76
77* [Prime](#prime)
78* [PRNG](#prng)
79* [Tasks](#task)
80* [Utilities](#util)
81* [Logging](#log)
82* [Debugging](#debug)
83* [Flash Networking Support](#flash)
84
85### Other
86
87* [Security Considerations](#security-considerations)
88* [Library Background](#library-background)
89* [Contact](#contact)
90* [Donations](#donations)
91
92---------------------------------------
93
94Installation
95------------
96
97Please see the [Security Considerations][] section before using packaging
98systems and pre-built files.
99
100Forge uses a [CommonJS][] module structure with a build process for browser
101bundles. The older [0.6.x][] branch with standalone files is available but will
102not be regularly updated.
103
104### Node.js
105
106If you want to use forge with [Node.js][], it is available through `npm`:
107
108https://npmjs.org/package/node-forge
109
110Installation:
111
112 npm install node-forge
113
114You can then use forge as a regular module:
115
116```js
117var forge = require('node-forge');
118```
119
120The npm package includes pre-built `forge.min.js`, `forge.all.min.js`, and
121`prime.worker.min.js` using the [UMD][] format.
122
123### Bundle / Bower
124
125Each release is published in a separate repository as pre-built and minimized
126basic forge bundles using the [UMD][] format.
127
128https://github.com/digitalbazaar/forge-dist
129
130This bundle can be used in many environments. In particular it can be installed
131with [Bower][]:
132
133 bower install forge
134
135### Development Requirements
136
137The core JavaScript has the following requirements to build and test:
138
139* Building a browser bundle:
140 * Node.js
141 * npm
142* Testing
143 * Node.js
144 * npm
145 * Chrome, Firefox, Safari (optional)
146
147Some special networking features can optionally use a Flash component. See the
148[Flash README](./flash/README.md) for details.
149
150### Building for a web browser
151
152To create single file bundles for use with browsers run the following:
153
154 npm install
155 npm run build
156
157This will create single non-minimized and minimized files that can be
158included in the browser:
159
160 dist/forge.js
161 dist/forge.min.js
162
163A bundle that adds some utilities and networking support is also available:
164
165 dist/forge.all.js
166 dist/forge.all.min.js
167
168Include the file via:
169
170```html
171<script src="YOUR_SCRIPT_PATH/forge.js"></script>
172```
173or
174```html
175<script src="YOUR_SCRIPT_PATH/forge.min.js"></script>
176```
177
178The above bundles will synchronously create a global 'forge' object.
179
180**Note**: These bundles will not include any WebWorker scripts (eg:
181`dist/prime.worker.js`), so these will need to be accessible from the browser
182if any WebWorkers are used.
183
184### Building a custom browser bundle
185
186The build process uses [webpack][] and the [config](./webpack.config.js) file
187can be modified to generate a file or files that only contain the parts of
188forge you need.
189
190[Browserify][] override support is also present in `package.json`.
191
192Testing
193-------
194
195See the [testing README](./tests/README.md) for full details.
196
197### Prepare to run tests
198
199 npm install
200
201### Running automated tests with Node.js
202
203Forge natively runs in a [Node.js][] environment:
204
205 npm test
206
207### Running automated tests with PhantomJS
208
209Automated testing is done via [Karma][]. By default it will run the tests in a
210headless manner with PhantomJS.
211
212 npm run test-karma
213
214Is 'mocha' reporter output too verbose? Other reporters are available. Try
215'dots', 'progress', or 'tap'.
216
217 npm run test-karma -- --reporters progress
218
219By default [webpack][] is used. [Browserify][] can also be used.
220
221 BUNDLER=browserify npm run test-karma
222
223### Running automated tests with one or more browsers
224
225You can also specify one or more browsers to use.
226
227 npm run test-karma -- --browsers Chrome,Firefox,Safari,PhantomJS
228
229The reporter option and `BUNDLER` environment variable can also be used.
230
231### Running manual tests in a browser
232
233Testing in a browser uses [webpack][] to combine forge and all tests and then
234loading the result in a browser. A simple web server is provided that will
235output the HTTP or HTTPS URLs to load. It also will start a simple Flash Policy
236Server. Unit tests and older legacy tests are provided. Custom ports can be
237used by running `node tests/server.js` manually.
238
239To run the unit tests in a browser a special forge build is required:
240
241 npm run test-build
242
243To run legacy browser based tests the main forge build is required:
244
245 npm run build
246
247The tests are run with a custom server that prints out the URLs to use:
248
249 npm run test-server
250
251### Running other tests
252
253There are some other random tests and benchmarks available in the tests
254directory.
255
256### Coverage testing
257
258To perform coverage testing of the unit tests, run the following. The results
259will be put in the `coverage/` directory. Note that coverage testing can slow
260down some tests considerably.
261
262 npm install
263 npm run coverage
264
265Contributing
266------------
267
268Any contributions (eg: PRs) that are accepted will be brought under the same
269license used by the rest of the Forge project. This license allows Forge to
270be used under the terms of either the BSD License or the GNU General Public
271License (GPL) Version 2.
272
273See: [LICENSE](https://github.com/digitalbazaar/forge/blob/cbebca3780658703d925b61b2caffb1d263a6c1d/LICENSE)
274
275If a contribution contains 3rd party source code with its own license, it
276may retain it, so long as that license is compatible with the Forge license.
277
278API
279---
280
281<a name="options" />
282### Options
283
284If at any time you wish to disable the use of native code, where available,
285for particular forge features like its secure random number generator, you
286may set the ```forge.options.usePureJavaScript``` flag to ```true```. It is
287not recommended that you set this flag as native code is typically more
288performant and may have stronger security properties. It may be useful to
289set this flag to test certain features that you plan to run in environments
290that are different from your testing environment.
291
292To disable native code when including forge in the browser:
293
294```js
295// run this *after* including the forge script
296forge.options.usePureJavaScript = true;
297```
298
299To disable native code when using Node.js:
300
301```js
302var forge = require('node-forge');
303forge.options.usePureJavaScript = true;
304```
305
306Transports
307----------
308
309<a name="tls" />
310### TLS
311
312Provides a native javascript client and server-side [TLS][] implementation.
313
314__Examples__
315
316```js
317// create TLS client
318var client = forge.tls.createConnection({
319 server: false,
320 caStore: /* Array of PEM-formatted certs or a CA store object */,
321 sessionCache: {},
322 // supported cipher suites in order of preference
323 cipherSuites: [
324 forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA,
325 forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA],
326 virtualHost: 'example.com',
327 verify: function(connection, verified, depth, certs) {
328 if(depth === 0) {
329 var cn = certs[0].subject.getField('CN').value;
330 if(cn !== 'example.com') {
331 verified = {
332 alert: forge.tls.Alert.Description.bad_certificate,
333 message: 'Certificate common name does not match hostname.'
334 };
335 }
336 }
337 return verified;
338 },
339 connected: function(connection) {
340 console.log('connected');
341 // send message to server
342 connection.prepare(forge.util.encodeUtf8('Hi server!'));
343 /* NOTE: experimental, start heartbeat retransmission timer
344 myHeartbeatTimer = setInterval(function() {
345 connection.prepareHeartbeatRequest(forge.util.createBuffer('1234'));
346 }, 5*60*1000);*/
347 },
348 /* provide a client-side cert if you want
349 getCertificate: function(connection, hint) {
350 return myClientCertificate;
351 },
352 /* the private key for the client-side cert if provided */
353 getPrivateKey: function(connection, cert) {
354 return myClientPrivateKey;
355 },
356 tlsDataReady: function(connection) {
357 // TLS data (encrypted) is ready to be sent to the server
358 sendToServerSomehow(connection.tlsData.getBytes());
359 // if you were communicating with the server below, you'd do:
360 // server.process(connection.tlsData.getBytes());
361 },
362 dataReady: function(connection) {
363 // clear data from the server is ready
364 console.log('the server sent: ' +
365 forge.util.decodeUtf8(connection.data.getBytes()));
366 // close connection
367 connection.close();
368 },
369 /* NOTE: experimental
370 heartbeatReceived: function(connection, payload) {
371 // restart retransmission timer, look at payload
372 clearInterval(myHeartbeatTimer);
373 myHeartbeatTimer = setInterval(function() {
374 connection.prepareHeartbeatRequest(forge.util.createBuffer('1234'));
375 }, 5*60*1000);
376 payload.getBytes();
377 },*/
378 closed: function(connection) {
379 console.log('disconnected');
380 },
381 error: function(connection, error) {
382 console.log('uh oh', error);
383 }
384});
385
386// start the handshake process
387client.handshake();
388
389// when encrypted TLS data is received from the server, process it
390client.process(encryptedBytesFromServer);
391
392// create TLS server
393var server = forge.tls.createConnection({
394 server: true,
395 caStore: /* Array of PEM-formatted certs or a CA store object */,
396 sessionCache: {},
397 // supported cipher suites in order of preference
398 cipherSuites: [
399 forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA,
400 forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA],
401 // require a client-side certificate if you want
402 verifyClient: true,
403 verify: function(connection, verified, depth, certs) {
404 if(depth === 0) {
405 var cn = certs[0].subject.getField('CN').value;
406 if(cn !== 'the-client') {
407 verified = {
408 alert: forge.tls.Alert.Description.bad_certificate,
409 message: 'Certificate common name does not match expected client.'
410 };
411 }
412 }
413 return verified;
414 },
415 connected: function(connection) {
416 console.log('connected');
417 // send message to client
418 connection.prepare(forge.util.encodeUtf8('Hi client!'));
419 /* NOTE: experimental, start heartbeat retransmission timer
420 myHeartbeatTimer = setInterval(function() {
421 connection.prepareHeartbeatRequest(forge.util.createBuffer('1234'));
422 }, 5*60*1000);*/
423 },
424 getCertificate: function(connection, hint) {
425 return myServerCertificate;
426 },
427 getPrivateKey: function(connection, cert) {
428 return myServerPrivateKey;
429 },
430 tlsDataReady: function(connection) {
431 // TLS data (encrypted) is ready to be sent to the client
432 sendToClientSomehow(connection.tlsData.getBytes());
433 // if you were communicating with the client above you'd do:
434 // client.process(connection.tlsData.getBytes());
435 },
436 dataReady: function(connection) {
437 // clear data from the client is ready
438 console.log('the client sent: ' +
439 forge.util.decodeUtf8(connection.data.getBytes()));
440 // close connection
441 connection.close();
442 },
443 /* NOTE: experimental
444 heartbeatReceived: function(connection, payload) {
445 // restart retransmission timer, look at payload
446 clearInterval(myHeartbeatTimer);
447 myHeartbeatTimer = setInterval(function() {
448 connection.prepareHeartbeatRequest(forge.util.createBuffer('1234'));
449 }, 5*60*1000);
450 payload.getBytes();
451 },*/
452 closed: function(connection) {
453 console.log('disconnected');
454 },
455 error: function(connection, error) {
456 console.log('uh oh', error);
457 }
458});
459
460// when encrypted TLS data is received from the client, process it
461server.process(encryptedBytesFromClient);
462```
463
464Connect to a TLS server using node's net.Socket:
465
466```js
467var socket = new net.Socket();
468
469var client = forge.tls.createConnection({
470 server: false,
471 verify: function(connection, verified, depth, certs) {
472 // skip verification for testing
473 console.log('[tls] server certificate verified');
474 return true;
475 },
476 connected: function(connection) {
477 console.log('[tls] connected');
478 // prepare some data to send (note that the string is interpreted as
479 // 'binary' encoded, which works for HTTP which only uses ASCII, use
480 // forge.util.encodeUtf8(str) otherwise
481 client.prepare('GET / HTTP/1.0\r\n\r\n');
482 },
483 tlsDataReady: function(connection) {
484 // encrypted data is ready to be sent to the server
485 var data = connection.tlsData.getBytes();
486 socket.write(data, 'binary'); // encoding should be 'binary'
487 },
488 dataReady: function(connection) {
489 // clear data from the server is ready
490 var data = connection.data.getBytes();
491 console.log('[tls] data received from the server: ' + data);
492 },
493 closed: function() {
494 console.log('[tls] disconnected');
495 },
496 error: function(connection, error) {
497 console.log('[tls] error', error);
498 }
499});
500
501socket.on('connect', function() {
502 console.log('[socket] connected');
503 client.handshake();
504});
505socket.on('data', function(data) {
506 client.process(data.toString('binary')); // encoding should be 'binary'
507});
508socket.on('end', function() {
509 console.log('[socket] disconnected');
510});
511
512// connect to google.com
513socket.connect(443, 'google.com');
514
515// or connect to gmail's imap server (but don't send the HTTP header above)
516//socket.connect(993, 'imap.gmail.com');
517```
518
519<a name="http" />
520### HTTP
521
522Provides a native [JavaScript][] mini-implementation of an http client that
523uses pooled sockets.
524
525__Examples__
526
527```js
528// create an HTTP GET request
529var request = forge.http.createRequest({method: 'GET', path: url.path});
530
531// send the request somewhere
532sendSomehow(request.toString());
533
534// receive response
535var buffer = forge.util.createBuffer();
536var response = forge.http.createResponse();
537var someAsyncDataHandler = function(bytes) {
538 if(!response.bodyReceived) {
539 buffer.putBytes(bytes);
540 if(!response.headerReceived) {
541 if(response.readHeader(buffer)) {
542 console.log('HTTP response header: ' + response.toString());
543 }
544 }
545 if(response.headerReceived && !response.bodyReceived) {
546 if(response.readBody(buffer)) {
547 console.log('HTTP response body: ' + response.body);
548 }
549 }
550 }
551};
552```
553
554<a name="ssh" />
555### SSH
556
557Provides some SSH utility functions.
558
559__Examples__
560
561```js
562// encodes (and optionally encrypts) a private RSA key as a Putty PPK file
563forge.ssh.privateKeyToPutty(privateKey, passphrase, comment);
564
565// encodes a public RSA key as an OpenSSH file
566forge.ssh.publicKeyToOpenSSH(key, comment);
567
568// encodes a private RSA key as an OpenSSH file
569forge.ssh.privateKeyToOpenSSH(privateKey, passphrase);
570
571// gets the SSH public key fingerprint in a byte buffer
572forge.ssh.getPublicKeyFingerprint(key);
573
574// gets a hex-encoded, colon-delimited SSH public key fingerprint
575forge.ssh.getPublicKeyFingerprint(key, {encoding: 'hex', delimiter: ':'});
576```
577
578<a name="xhr" />
579### XHR
580
581Provides an XmlHttpRequest implementation using forge.http as a backend.
582
583__Examples__
584
585```js
586// TODO
587```
588
589<a name="socket" />
590### Sockets
591
592Provides an interface to create and use raw sockets provided via Flash.
593
594__Examples__
595
596```js
597// TODO
598```
599
600Ciphers
601-------
602
603<a name="cipher" />
604### CIPHER
605
606Provides a basic API for block encryption and decryption. There is built-in
607support for the ciphers: [AES][], [3DES][], and [DES][], and for the modes
608of operation: [ECB][], [CBC][], [CFB][], [OFB][], [CTR][], and [GCM][].
609
610These algorithms are currently supported:
611
612* AES-ECB
613* AES-CBC
614* AES-CFB
615* AES-OFB
616* AES-CTR
617* AES-GCM
618* 3DES-ECB
619* 3DES-CBC
620* DES-ECB
621* DES-CBC
622
623When using an [AES][] algorithm, the key size will determine whether
624AES-128, AES-192, or AES-256 is used (all are supported). When a [DES][]
625algorithm is used, the key size will determine whether [3DES][] or regular
626[DES][] is used. Use a [3DES][] algorithm to enforce Triple-DES.
627
628__Examples__
629
630```js
631// generate a random key and IV
632// Note: a key size of 16 bytes will use AES-128, 24 => AES-192, 32 => AES-256
633var key = forge.random.getBytesSync(16);
634var iv = forge.random.getBytesSync(16);
635
636/* alternatively, generate a password-based 16-byte key
637var salt = forge.random.getBytesSync(128);
638var key = forge.pkcs5.pbkdf2('password', salt, numIterations, 16);
639*/
640
641// encrypt some bytes using CBC mode
642// (other modes include: ECB, CFB, OFB, CTR, and GCM)
643// Note: CBC and ECB modes use PKCS#7 padding as default
644var cipher = forge.cipher.createCipher('AES-CBC', key);
645cipher.start({iv: iv});
646cipher.update(forge.util.createBuffer(someBytes));
647cipher.finish();
648var encrypted = cipher.output;
649// outputs encrypted hex
650console.log(encrypted.toHex());
651
652// decrypt some bytes using CBC mode
653// (other modes include: CFB, OFB, CTR, and GCM)
654var decipher = forge.cipher.createDecipher('AES-CBC', key);
655decipher.start({iv: iv});
656decipher.update(encrypted);
657decipher.finish();
658// outputs decrypted hex
659console.log(decipher.output.toHex());
660
661// encrypt some bytes using GCM mode
662var cipher = forge.cipher.createCipher('AES-GCM', key);
663cipher.start({
664 iv: iv, // should be a 12-byte binary-encoded string or byte buffer
665 additionalData: 'binary-encoded string', // optional
666 tagLength: 128 // optional, defaults to 128 bits
667});
668cipher.update(forge.util.createBuffer(someBytes));
669cipher.finish();
670var encrypted = cipher.output;
671var tag = cipher.mode.tag;
672// outputs encrypted hex
673console.log(encrypted.toHex());
674// outputs authentication tag
675console.log(tag.toHex());
676
677// decrypt some bytes using GCM mode
678var decipher = forge.cipher.createDecipher('AES-GCM', key);
679decipher.start({
680 iv: iv,
681 additionalData: 'binary-encoded string', // optional
682 tagLength: 128, // optional, defaults to 128 bits
683 tag: tag // authentication tag from encryption
684});
685decipher.update(encrypted);
686var pass = decipher.finish();
687// pass is false if there was a failure (eg: authentication tag didn't match)
688if(pass) {
689 // outputs decrypted hex
690 console.log(decipher.output.toHex());
691}
692```
693
694Using forge in Node.js to match openssl's "enc" command line tool (**Note**: OpenSSL "enc" uses a non-standard file format with a custom key derivation function and a fixed iteration count of 1, which some consider less secure than alternatives such as [OpenPGP](https://tools.ietf.org/html/rfc4880)/[GnuPG](https://www.gnupg.org/)):
695
696```js
697var forge = require('node-forge');
698var fs = require('fs');
699
700// openssl enc -des3 -in input.txt -out input.enc
701function encrypt(password) {
702 var input = fs.readFileSync('input.txt', {encoding: 'binary'});
703
704 // 3DES key and IV sizes
705 var keySize = 24;
706 var ivSize = 8;
707
708 // get derived bytes
709 // Notes:
710 // 1. If using an alternative hash (eg: "-md sha1") pass
711 // "forge.md.sha1.create()" as the final parameter.
712 // 2. If using "-nosalt", set salt to null.
713 var salt = forge.random.getBytesSync(8);
714 // var md = forge.md.sha1.create(); // "-md sha1"
715 var derivedBytes = forge.pbe.opensslDeriveBytes(
716 password, salt, keySize + ivSize/*, md*/);
717 var buffer = forge.util.createBuffer(derivedBytes);
718 var key = buffer.getBytes(keySize);
719 var iv = buffer.getBytes(ivSize);
720
721 var cipher = forge.cipher.createCipher('3DES-CBC', key);
722 cipher.start({iv: iv});
723 cipher.update(forge.util.createBuffer(input, 'binary'));
724 cipher.finish();
725
726 var output = forge.util.createBuffer();
727
728 // if using a salt, prepend this to the output:
729 if(salt !== null) {
730 output.putBytes('Salted__'); // (add to match openssl tool output)
731 output.putBytes(salt);
732 }
733 output.putBuffer(cipher.output);
734
735 fs.writeFileSync('input.enc', output.getBytes(), {encoding: 'binary'});
736}
737
738// openssl enc -d -des3 -in input.enc -out input.dec.txt
739function decrypt(password) {
740 var input = fs.readFileSync('input.enc', {encoding: 'binary'});
741
742 // parse salt from input
743 input = forge.util.createBuffer(input, 'binary');
744 // skip "Salted__" (if known to be present)
745 input.getBytes('Salted__'.length);
746 // read 8-byte salt
747 var salt = input.getBytes(8);
748
749 // Note: if using "-nosalt", skip above parsing and use
750 // var salt = null;
751
752 // 3DES key and IV sizes
753 var keySize = 24;
754 var ivSize = 8;
755
756 var derivedBytes = forge.pbe.opensslDeriveBytes(
757 password, salt, keySize + ivSize);
758 var buffer = forge.util.createBuffer(derivedBytes);
759 var key = buffer.getBytes(keySize);
760 var iv = buffer.getBytes(ivSize);
761
762 var decipher = forge.cipher.createDecipher('3DES-CBC', key);
763 decipher.start({iv: iv});
764 decipher.update(input);
765 var result = decipher.finish(); // check 'result' for true/false
766
767 fs.writeFileSync(
768 'input.dec.txt', decipher.output.getBytes(), {encoding: 'binary'});
769}
770```
771
772<a name="aes" />
773### AES
774
775Provides [AES][] encryption and decryption in [CBC][], [CFB][], [OFB][],
776[CTR][], and [GCM][] modes. See [CIPHER](#cipher) for examples.
777
778<a name="des" />
779### DES
780
781Provides [3DES][] and [DES][] encryption and decryption in [ECB][] and
782[CBC][] modes. See [CIPHER](#cipher) for examples.
783
784<a name="rc2" />
785### RC2
786
787__Examples__
788
789```js
790// generate a random key and IV
791var key = forge.random.getBytesSync(16);
792var iv = forge.random.getBytesSync(8);
793
794// encrypt some bytes
795var cipher = forge.rc2.createEncryptionCipher(key);
796cipher.start(iv);
797cipher.update(forge.util.createBuffer(someBytes));
798cipher.finish();
799var encrypted = cipher.output;
800// outputs encrypted hex
801console.log(encrypted.toHex());
802
803// decrypt some bytes
804var cipher = forge.rc2.createDecryptionCipher(key);
805cipher.start(iv);
806cipher.update(encrypted);
807cipher.finish();
808// outputs decrypted hex
809console.log(cipher.output.toHex());
810```
811
812PKI
813---
814
815Provides [X.509][] certificate and RSA public and private key encoding,
816decoding, encryption/decryption, and signing/verifying.
817
818<a name="rsa" />
819### RSA
820
821__Examples__
822
823```js
824var rsa = forge.pki.rsa;
825
826// generate an RSA key pair synchronously
827// *NOT RECOMMENDED* -- can be significantly slower than async and will not
828// use native APIs if available.
829var keypair = rsa.generateKeyPair({bits: 2048, e: 0x10001});
830
831// generate an RSA key pair asynchronously (uses web workers if available)
832// use workers: -1 to run a fast core estimator to optimize # of workers
833// *RECOMMENDED* - can be significantly faster than sync -- and will use
834// native APIs if available.
835rsa.generateKeyPair({bits: 2048, workers: 2}, function(err, keypair) {
836 // keypair.privateKey, keypair.publicKey
837});
838
839// generate an RSA key pair in steps that attempt to run for a specified period
840// of time on the main JS thread
841var state = rsa.createKeyPairGenerationState(2048, 0x10001);
842var step = function() {
843 // run for 100 ms
844 if(!rsa.stepKeyPairGenerationState(state, 100)) {
845 setTimeout(step, 1);
846 }
847 else {
848 // done, turn off progress indicator, use state.keys
849 }
850};
851// turn on progress indicator, schedule generation to run
852setTimeout(step);
853
854// sign data with a private key and output DigestInfo DER-encoded bytes
855// (defaults to RSASSA PKCS#1 v1.5)
856var md = forge.md.sha1.create();
857md.update('sign this', 'utf8');
858var signature = privateKey.sign(md);
859
860// verify data with a public key
861// (defaults to RSASSA PKCS#1 v1.5)
862var verified = publicKey.verify(md.digest().bytes(), signature);
863
864// sign data using RSASSA-PSS where PSS uses a SHA-1 hash, a SHA-1 based
865// masking function MGF1, and a 20 byte salt
866var md = forge.md.sha1.create();
867md.update('sign this', 'utf8');
868var pss = forge.pss.create({
869 md: forge.md.sha1.create(),
870 mgf: forge.mgf.mgf1.create(forge.md.sha1.create()),
871 saltLength: 20
872 // optionally pass 'prng' with a custom PRNG implementation
873 // optionalls pass 'salt' with a forge.util.ByteBuffer w/custom salt
874});
875var signature = privateKey.sign(md, pss);
876
877// verify RSASSA-PSS signature
878var pss = forge.pss.create({
879 md: forge.md.sha1.create(),
880 mgf: forge.mgf.mgf1.create(forge.md.sha1.create()),
881 saltLength: 20
882 // optionally pass 'prng' with a custom PRNG implementation
883});
884var md = forge.md.sha1.create();
885md.update('sign this', 'utf8');
886publicKey.verify(md.digest().getBytes(), signature, pss);
887
888// encrypt data with a public key (defaults to RSAES PKCS#1 v1.5)
889var encrypted = publicKey.encrypt(bytes);
890
891// decrypt data with a private key (defaults to RSAES PKCS#1 v1.5)
892var decrypted = privateKey.decrypt(encrypted);
893
894// encrypt data with a public key using RSAES PKCS#1 v1.5
895var encrypted = publicKey.encrypt(bytes, 'RSAES-PKCS1-V1_5');
896
897// decrypt data with a private key using RSAES PKCS#1 v1.5
898var decrypted = privateKey.decrypt(encrypted, 'RSAES-PKCS1-V1_5');
899
900// encrypt data with a public key using RSAES-OAEP
901var encrypted = publicKey.encrypt(bytes, 'RSA-OAEP');
902
903// decrypt data with a private key using RSAES-OAEP
904var decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP');
905
906// encrypt data with a public key using RSAES-OAEP/SHA-256
907var encrypted = publicKey.encrypt(bytes, 'RSA-OAEP', {
908 md: forge.md.sha256.create()
909});
910
911// decrypt data with a private key using RSAES-OAEP/SHA-256
912var decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP', {
913 md: forge.md.sha256.create()
914});
915
916// encrypt data with a public key using RSAES-OAEP/SHA-256/MGF1-SHA-1
917// compatible with Java's RSA/ECB/OAEPWithSHA-256AndMGF1Padding
918var encrypted = publicKey.encrypt(bytes, 'RSA-OAEP', {
919 md: forge.md.sha256.create(),
920 mgf1: {
921 md: forge.md.sha1.create()
922 }
923});
924
925// decrypt data with a private key using RSAES-OAEP/SHA-256/MGF1-SHA-1
926// compatible with Java's RSA/ECB/OAEPWithSHA-256AndMGF1Padding
927var decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP', {
928 md: forge.md.sha256.create(),
929 mgf1: {
930 md: forge.md.sha1.create()
931 }
932});
933
934```
935
936<a name="rsakem" />
937### RSA-KEM
938
939__Examples__
940
941```js
942// generate an RSA key pair asynchronously (uses web workers if available)
943// use workers: -1 to run a fast core estimator to optimize # of workers
944forge.rsa.generateKeyPair({bits: 2048, workers: -1}, function(err, keypair) {
945 // keypair.privateKey, keypair.publicKey
946});
947
948// generate and encapsulate a 16-byte secret key
949var kdf1 = new forge.kem.kdf1(forge.md.sha1.create());
950var kem = forge.kem.rsa.create(kdf1);
951var result = kem.encrypt(keypair.publicKey, 16);
952// result has 'encapsulation' and 'key'
953
954// encrypt some bytes
955var iv = forge.random.getBytesSync(12);
956var someBytes = 'hello world!';
957var cipher = forge.cipher.createCipher('AES-GCM', result.key);
958cipher.start({iv: iv});
959cipher.update(forge.util.createBuffer(someBytes));
960cipher.finish();
961var encrypted = cipher.output.getBytes();
962var tag = cipher.mode.tag.getBytes();
963
964// send 'encrypted', 'iv', 'tag', and result.encapsulation to recipient
965
966// decrypt encapsulated 16-byte secret key
967var kdf1 = new forge.kem.kdf1(forge.md.sha1.create());
968var kem = forge.kem.rsa.create(kdf1);
969var key = kem.decrypt(keypair.privateKey, result.encapsulation, 16);
970
971// decrypt some bytes
972var decipher = forge.cipher.createDecipher('AES-GCM', key);
973decipher.start({iv: iv, tag: tag});
974decipher.update(forge.util.createBuffer(encrypted));
975var pass = decipher.finish();
976// pass is false if there was a failure (eg: authentication tag didn't match)
977if(pass) {
978 // outputs 'hello world!'
979 console.log(decipher.output.getBytes());
980}
981
982```
983
984<a name="x509" />
985### X.509
986
987__Examples__
988
989```js
990var pki = forge.pki;
991
992// convert a PEM-formatted public key to a Forge public key
993var publicKey = pki.publicKeyFromPem(pem);
994
995// convert a Forge public key to PEM-format
996var pem = pki.publicKeyToPem(publicKey);
997
998// convert an ASN.1 SubjectPublicKeyInfo to a Forge public key
999var publicKey = pki.publicKeyFromAsn1(subjectPublicKeyInfo);
1000
1001// convert a Forge public key to an ASN.1 SubjectPublicKeyInfo
1002var subjectPublicKeyInfo = pki.publicKeyToAsn1(publicKey);
1003
1004// gets a SHA-1 RSAPublicKey fingerprint a byte buffer
1005pki.getPublicKeyFingerprint(key);
1006
1007// gets a SHA-1 SubjectPublicKeyInfo fingerprint a byte buffer
1008pki.getPublicKeyFingerprint(key, {type: 'SubjectPublicKeyInfo'});
1009
1010// gets a hex-encoded, colon-delimited SHA-1 RSAPublicKey public key fingerprint
1011pki.getPublicKeyFingerprint(key, {encoding: 'hex', delimiter: ':'});
1012
1013// gets a hex-encoded, colon-delimited SHA-1 SubjectPublicKeyInfo public key fingerprint
1014pki.getPublicKeyFingerprint(key, {
1015 type: 'SubjectPublicKeyInfo',
1016 encoding: 'hex',
1017 delimiter: ':'
1018});
1019
1020// gets a hex-encoded, colon-delimited MD5 RSAPublicKey public key fingerprint
1021pki.getPublicKeyFingerprint(key, {
1022 md: forge.md.md5.create(),
1023 encoding: 'hex',
1024 delimiter: ':'
1025});
1026
1027// creates a CA store
1028var caStore = pki.createCaStore([/* PEM-encoded cert */, ...]);
1029
1030// add a certificate to the CA store
1031caStore.addCertificate(certObjectOrPemString);
1032
1033// gets the issuer (its certificate) for the given certificate
1034var issuerCert = caStore.getIssuer(subjectCert);
1035
1036// verifies a certificate chain against a CA store
1037pki.verifyCertificateChain(caStore, chain, customVerifyCallback);
1038
1039// signs a certificate using the given private key
1040cert.sign(privateKey);
1041
1042// signs a certificate using SHA-256 instead of SHA-1
1043cert.sign(privateKey, forge.md.sha256.create());
1044
1045// verifies an issued certificate using the certificates public key
1046var verified = issuer.verify(issued);
1047
1048// generate a keypair and create an X.509v3 certificate
1049var keys = pki.rsa.generateKeyPair(2048);
1050var cert = pki.createCertificate();
1051cert.publicKey = keys.publicKey;
1052// alternatively set public key from a csr
1053//cert.publicKey = csr.publicKey;
1054cert.serialNumber = '01';
1055cert.validity.notBefore = new Date();
1056cert.validity.notAfter = new Date();
1057cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);
1058var attrs = [{
1059 name: 'commonName',
1060 value: 'example.org'
1061}, {
1062 name: 'countryName',
1063 value: 'US'
1064}, {
1065 shortName: 'ST',
1066 value: 'Virginia'
1067}, {
1068 name: 'localityName',
1069 value: 'Blacksburg'
1070}, {
1071 name: 'organizationName',
1072 value: 'Test'
1073}, {
1074 shortName: 'OU',
1075 value: 'Test'
1076}];
1077cert.setSubject(attrs);
1078// alternatively set subject from a csr
1079//cert.setSubject(csr.subject.attributes);
1080cert.setIssuer(attrs);
1081cert.setExtensions([{
1082 name: 'basicConstraints',
1083 cA: true
1084}, {
1085 name: 'keyUsage',
1086 keyCertSign: true,
1087 digitalSignature: true,
1088 nonRepudiation: true,
1089 keyEncipherment: true,
1090 dataEncipherment: true
1091}, {
1092 name: 'extKeyUsage',
1093 serverAuth: true,
1094 clientAuth: true,
1095 codeSigning: true,
1096 emailProtection: true,
1097 timeStamping: true
1098}, {
1099 name: 'nsCertType',
1100 client: true,
1101 server: true,
1102 email: true,
1103 objsign: true,
1104 sslCA: true,
1105 emailCA: true,
1106 objCA: true
1107}, {
1108 name: 'subjectAltName',
1109 altNames: [{
1110 type: 6, // URI
1111 value: 'http://example.org/webid#me'
1112 }, {
1113 type: 7, // IP
1114 ip: '127.0.0.1'
1115 }]
1116}, {
1117 name: 'subjectKeyIdentifier'
1118}]);
1119/* alternatively set extensions from a csr
1120var extensions = csr.getAttribute({name: 'extensionRequest'}).extensions;
1121// optionally add more extensions
1122extensions.push.apply(extensions, [{
1123 name: 'basicConstraints',
1124 cA: true
1125}, {
1126 name: 'keyUsage',
1127 keyCertSign: true,
1128 digitalSignature: true,
1129 nonRepudiation: true,
1130 keyEncipherment: true,
1131 dataEncipherment: true
1132}]);
1133cert.setExtensions(extensions);
1134*/
1135// self-sign certificate
1136cert.sign(keys.privateKey);
1137
1138// convert a Forge certificate to PEM
1139var pem = pki.certificateToPem(cert);
1140
1141// convert a Forge certificate from PEM
1142var cert = pki.certificateFromPem(pem);
1143
1144// convert an ASN.1 X.509x3 object to a Forge certificate
1145var cert = pki.certificateFromAsn1(obj);
1146
1147// convert a Forge certificate to an ASN.1 X.509v3 object
1148var asn1Cert = pki.certificateToAsn1(cert);
1149```
1150
1151<a name="pkcs5" />
1152### PKCS#5
1153
1154Provides the password-based key-derivation function from [PKCS#5][].
1155
1156__Examples__
1157
1158```js
1159// generate a password-based 16-byte key
1160// note an optional message digest can be passed as the final parameter
1161var salt = forge.random.getBytesSync(128);
1162var derivedKey = forge.pkcs5.pbkdf2('password', salt, numIterations, 16);
1163
1164// generate key asynchronously
1165// note an optional message digest can be passed before the callback
1166forge.pkcs5.pbkdf2('password', salt, numIterations, 16, function(err, derivedKey) {
1167 // do something w/derivedKey
1168});
1169```
1170
1171<a name="pkcs7" />
1172### PKCS#7
1173
1174Provides cryptographically protected messages from [PKCS#7][].
1175
1176__Examples__
1177
1178```js
1179// convert a message from PEM
1180var p7 = forge.pkcs7.messageFromPem(pem);
1181// look at p7.recipients
1182
1183// find a recipient by the issuer of a certificate
1184var recipient = p7.findRecipient(cert);
1185
1186// decrypt
1187p7.decrypt(p7.recipients[0], privateKey);
1188
1189// create a p7 enveloped message
1190var p7 = forge.pkcs7.createEnvelopedData();
1191
1192// add a recipient
1193var cert = forge.pki.certificateFromPem(certPem);
1194p7.addRecipient(cert);
1195
1196// set content
1197p7.content = forge.util.createBuffer('Hello');
1198
1199// encrypt
1200p7.encrypt();
1201
1202// convert message to PEM
1203var pem = forge.pkcs7.messageToPem(p7);
1204
1205// create a degenerate PKCS#7 certificate container
1206// (CRLs not currently supported, only certificates)
1207var p7 = forge.pkcs7.createSignedData();
1208p7.addCertificate(certOrCertPem1);
1209p7.addCertificate(certOrCertPem2);
1210var pem = forge.pkcs7.messageToPem(p7);
1211
1212// create PKCS#7 signed data with authenticatedAttributes
1213// attributes include: PKCS#9 content-type, message-digest, and signing-time
1214var p7 = forge.pkcs7.createSignedData();
1215p7.content = forge.util.createBuffer('Some content to be signed.', 'utf8');
1216p7.addCertificate(certOrCertPem);
1217p7.addSigner({
1218 key: privateKeyAssociatedWithCert,
1219 certificate: certOrCertPem,
1220 digestAlgorithm: forge.pki.oids.sha256,
1221 authenticatedAttributes: [{
1222 type: forge.pki.oids.contentType,
1223 value: forge.pki.oids.data
1224 }, {
1225 type: forge.pki.oids.messageDigest
1226 // value will be auto-populated at signing time
1227 }, {
1228 type: forge.pki.oids.signingTime,
1229 // value can also be auto-populated at signing time
1230 value: new Date()
1231 }]
1232});
1233p7.sign();
1234var pem = forge.pkcs7.messageToPem(p7);
1235
1236```
1237
1238<a name="pkcs8" />
1239### PKCS#8
1240
1241__Examples__
1242
1243```js
1244var pki = forge.pki;
1245
1246// convert a PEM-formatted private key to a Forge private key
1247var privateKey = pki.privateKeyFromPem(pem);
1248
1249// convert a Forge private key to PEM-format
1250var pem = pki.privateKeyToPem(privateKey);
1251
1252// convert an ASN.1 PrivateKeyInfo or RSAPrivateKey to a Forge private key
1253var privateKey = pki.privateKeyFromAsn1(rsaPrivateKey);
1254
1255// convert a Forge private key to an ASN.1 RSAPrivateKey
1256var rsaPrivateKey = pki.privateKeyToAsn1(privateKey);
1257
1258// wrap an RSAPrivateKey ASN.1 object in a PKCS#8 ASN.1 PrivateKeyInfo
1259var privateKeyInfo = pki.wrapRsaPrivateKey(rsaPrivateKey);
1260
1261// convert a PKCS#8 ASN.1 PrivateKeyInfo to PEM
1262var pem = pki.privateKeyInfoToPem(privateKeyInfo);
1263
1264// encrypts a PrivateKeyInfo and outputs an EncryptedPrivateKeyInfo
1265var encryptedPrivateKeyInfo = pki.encryptPrivateKeyInfo(
1266 privateKeyInfo, 'password', {
1267 algorithm: 'aes256', // 'aes128', 'aes192', 'aes256', '3des'
1268 });
1269
1270// decrypts an ASN.1 EncryptedPrivateKeyInfo
1271var privateKeyInfo = pki.decryptPrivateKeyInfo(
1272 encryptedPrivateKeyInfo, 'password');
1273
1274// converts an EncryptedPrivateKeyInfo to PEM
1275var pem = pki.encryptedPrivateKeyToPem(encryptedPrivateKeyInfo);
1276
1277// converts a PEM-encoded EncryptedPrivateKeyInfo to ASN.1 format
1278var encryptedPrivateKeyInfo = pki.encryptedPrivateKeyFromPem(pem);
1279
1280// wraps and encrypts a Forge private key and outputs it in PEM format
1281var pem = pki.encryptRsaPrivateKey(privateKey, 'password');
1282
1283// encrypts a Forge private key and outputs it in PEM format using OpenSSL's
1284// proprietary legacy format + encapsulated PEM headers (DEK-Info)
1285var pem = pki.encryptRsaPrivateKey(privateKey, 'password', {legacy: true});
1286
1287// decrypts a PEM-formatted, encrypted private key
1288var privateKey = pki.decryptRsaPrivateKey(pem, 'password');
1289
1290// sets an RSA public key from a private key
1291var publicKey = pki.setRsaPublicKey(privateKey.n, privateKey.e);
1292```
1293
1294<a name="pkcs10" />
1295### PKCS#10
1296
1297Provides certification requests or certificate signing requests (CSR) from
1298[PKCS#10][].
1299
1300__Examples__
1301
1302```js
1303// generate a key pair
1304var keys = forge.pki.rsa.generateKeyPair(1024);
1305
1306// create a certification request (CSR)
1307var csr = forge.pki.createCertificationRequest();
1308csr.publicKey = keys.publicKey;
1309csr.setSubject([{
1310 name: 'commonName',
1311 value: 'example.org'
1312}, {
1313 name: 'countryName',
1314 value: 'US'
1315}, {
1316 shortName: 'ST',
1317 value: 'Virginia'
1318}, {
1319 name: 'localityName',
1320 value: 'Blacksburg'
1321}, {
1322 name: 'organizationName',
1323 value: 'Test'
1324}, {
1325 shortName: 'OU',
1326 value: 'Test'
1327}]);
1328// set (optional) attributes
1329csr.setAttributes([{
1330 name: 'challengePassword',
1331 value: 'password'
1332}, {
1333 name: 'unstructuredName',
1334 value: 'My Company, Inc.'
1335}, {
1336 name: 'extensionRequest',
1337 extensions: [{
1338 name: 'subjectAltName',
1339 altNames: [{
1340 // 2 is DNS type
1341 type: 2,
1342 value: 'test.domain.com'
1343 }, {
1344 type: 2,
1345 value: 'other.domain.com',
1346 }, {
1347 type: 2,
1348 value: 'www.domain.net'
1349 }]
1350 }]
1351}]);
1352
1353// sign certification request
1354csr.sign(keys.privateKey);
1355
1356// verify certification request
1357var verified = csr.verify();
1358
1359// convert certification request to PEM-format
1360var pem = forge.pki.certificationRequestToPem(csr);
1361
1362// convert a Forge certification request from PEM-format
1363var csr = forge.pki.certificationRequestFromPem(pem);
1364
1365// get an attribute
1366csr.getAttribute({name: 'challengePassword'});
1367
1368// get extensions array
1369csr.getAttribute({name: 'extensionRequest'}).extensions;
1370
1371```
1372
1373<a name="pkcs12" />
1374### PKCS#12
1375
1376Provides the cryptographic archive file format from [PKCS#12][].
1377
1378**Note for Chrome/Firefox/iOS/similar users**: If you have trouble importing
1379a PKCS#12 container, try using the TripleDES algorithm. It can be passed
1380to `forge.pkcs12.toPkcs12Asn1` using the `{algorithm: '3des'}` option.
1381
1382__Examples__
1383
1384```js
1385// decode p12 from base64
1386var p12Der = forge.util.decode64(p12b64);
1387// get p12 as ASN.1 object
1388var p12Asn1 = forge.asn1.fromDer(p12Der);
1389// decrypt p12 using the password 'password'
1390var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, 'password');
1391// decrypt p12 using non-strict parsing mode (resolves some ASN.1 parse errors)
1392var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, false, 'password');
1393// decrypt p12 using literally no password (eg: Mac OS X/apple push)
1394var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1);
1395// decrypt p12 using an "empty" password (eg: OpenSSL with no password input)
1396var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, '');
1397// p12.safeContents is an array of safe contents, each of
1398// which contains an array of safeBags
1399
1400// get bags by friendlyName
1401var bags = p12.getBags({friendlyName: 'test'});
1402// bags are key'd by attribute type (here "friendlyName")
1403// and the key values are an array of matching objects
1404var cert = bags.friendlyName[0];
1405
1406// get bags by localKeyId
1407var bags = p12.getBags({localKeyId: buffer});
1408// bags are key'd by attribute type (here "localKeyId")
1409// and the key values are an array of matching objects
1410var cert = bags.localKeyId[0];
1411
1412// get bags by localKeyId (input in hex)
1413var bags = p12.getBags({localKeyIdHex: '7b59377ff142d0be4565e9ac3d396c01401cd879'});
1414// bags are key'd by attribute type (here "localKeyId", *not* "localKeyIdHex")
1415// and the key values are an array of matching objects
1416var cert = bags.localKeyId[0];
1417
1418// get bags by type
1419var bags = p12.getBags({bagType: forge.pki.oids.certBag});
1420// bags are key'd by bagType and each bagType key's value
1421// is an array of matches (in this case, certificate objects)
1422var cert = bags[forge.pki.oids.certBag][0];
1423
1424// get bags by friendlyName and filter on bag type
1425var bags = p12.getBags({
1426 friendlyName: 'test',
1427 bagType: forge.pki.oids.certBag
1428});
1429
1430// get key bags
1431var bags = p12.getBags({bagType: forge.pki.oids.keyBag});
1432// get key
1433var bag = bags[forge.pki.oids.keyBag][0];
1434var key = bag.key;
1435// if the key is in a format unrecognized by forge then
1436// bag.key will be `null`, use bag.asn1 to get the ASN.1
1437// representation of the key
1438if(bag.key === null) {
1439 var keyAsn1 = bag.asn1;
1440 // can now convert back to DER/PEM/etc for export
1441}
1442
1443// generate a p12 using AES (default)
1444var p12Asn1 = forge.pkcs12.toPkcs12Asn1(
1445 privateKey, certificateChain, 'password');
1446
1447// generate a p12 that can be imported by Chrome/Firefox/iOS
1448// (requires the use of Triple DES instead of AES)
1449var p12Asn1 = forge.pkcs12.toPkcs12Asn1(
1450 privateKey, certificateChain, 'password',
1451 {algorithm: '3des'});
1452
1453// base64-encode p12
1454var p12Der = forge.asn1.toDer(p12Asn1).getBytes();
1455var p12b64 = forge.util.encode64(p12Der);
1456
1457// create download link for p12
1458var a = document.createElement('a');
1459a.download = 'example.p12';
1460a.setAttribute('href', 'data:application/x-pkcs12;base64,' + p12b64);
1461a.appendChild(document.createTextNode('Download'));
1462```
1463
1464<a name="asn" />
1465### ASN.1
1466
1467Provides [ASN.1][] DER encoding and decoding.
1468
1469__Examples__
1470
1471```js
1472var asn1 = forge.asn1;
1473
1474// create a SubjectPublicKeyInfo
1475var subjectPublicKeyInfo =
1476 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
1477 // AlgorithmIdentifier
1478 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
1479 // algorithm
1480 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
1481 asn1.oidToDer(pki.oids['rsaEncryption']).getBytes()),
1482 // parameters (null)
1483 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')
1484 ]),
1485 // subjectPublicKey
1486 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, [
1487 // RSAPublicKey
1488 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
1489 // modulus (n)
1490 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
1491 _bnToBytes(key.n)),
1492 // publicExponent (e)
1493 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
1494 _bnToBytes(key.e))
1495 ])
1496 ])
1497 ]);
1498
1499// serialize an ASN.1 object to DER format
1500var derBuffer = asn1.toDer(subjectPublicKeyInfo);
1501
1502// deserialize to an ASN.1 object from a byte buffer filled with DER data
1503var object = asn1.fromDer(derBuffer);
1504
1505// convert an OID dot-separated string to a byte buffer
1506var derOidBuffer = asn1.oidToDer('1.2.840.113549.1.1.5');
1507
1508// convert a byte buffer with a DER-encoded OID to a dot-separated string
1509console.log(asn1.derToOid(derOidBuffer));
1510// output: 1.2.840.113549.1.1.5
1511
1512// validates that an ASN.1 object matches a particular ASN.1 structure and
1513// captures data of interest from that structure for easy access
1514var publicKeyValidator = {
1515 name: 'SubjectPublicKeyInfo',
1516 tagClass: asn1.Class.UNIVERSAL,
1517 type: asn1.Type.SEQUENCE,
1518 constructed: true,
1519 captureAsn1: 'subjectPublicKeyInfo',
1520 value: [{
1521 name: 'SubjectPublicKeyInfo.AlgorithmIdentifier',
1522 tagClass: asn1.Class.UNIVERSAL,
1523 type: asn1.Type.SEQUENCE,
1524 constructed: true,
1525 value: [{
1526 name: 'AlgorithmIdentifier.algorithm',
1527 tagClass: asn1.Class.UNIVERSAL,
1528 type: asn1.Type.OID,
1529 constructed: false,
1530 capture: 'publicKeyOid'
1531 }]
1532 }, {
1533 // subjectPublicKey
1534 name: 'SubjectPublicKeyInfo.subjectPublicKey',
1535 tagClass: asn1.Class.UNIVERSAL,
1536 type: asn1.Type.BITSTRING,
1537 constructed: false,
1538 value: [{
1539 // RSAPublicKey
1540 name: 'SubjectPublicKeyInfo.subjectPublicKey.RSAPublicKey',
1541 tagClass: asn1.Class.UNIVERSAL,
1542 type: asn1.Type.SEQUENCE,
1543 constructed: true,
1544 optional: true,
1545 captureAsn1: 'rsaPublicKey'
1546 }]
1547 }]
1548};
1549
1550var capture = {};
1551var errors = [];
1552if(!asn1.validate(
1553 publicKeyValidator, subjectPublicKeyInfo, validator, capture, errors)) {
1554 throw 'ASN.1 object is not a SubjectPublicKeyInfo.';
1555}
1556// capture.subjectPublicKeyInfo contains the full ASN.1 object
1557// capture.rsaPublicKey contains the full ASN.1 object for the RSA public key
1558// capture.publicKeyOid only contains the value for the OID
1559var oid = asn1.derToOid(capture.publicKeyOid);
1560if(oid !== pki.oids['rsaEncryption']) {
1561 throw 'Unsupported OID.';
1562}
1563
1564// pretty print an ASN.1 object to a string for debugging purposes
1565asn1.prettyPrint(object);
1566```
1567
1568Message Digests
1569----------------
1570
1571<a name="sha1" />
1572### SHA1
1573
1574Provides [SHA-1][] message digests.
1575
1576__Examples__
1577
1578```js
1579var md = forge.md.sha1.create();
1580md.update('The quick brown fox jumps over the lazy dog');
1581console.log(md.digest().toHex());
1582// output: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
1583```
1584
1585<a name="sha256" />
1586### SHA256
1587
1588Provides [SHA-256][] message digests.
1589
1590__Examples__
1591
1592```js
1593var md = forge.md.sha256.create();
1594md.update('The quick brown fox jumps over the lazy dog');
1595console.log(md.digest().toHex());
1596// output: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592
1597```
1598
1599<a name="sha384" />
1600### SHA384
1601
1602Provides [SHA-384][] message digests.
1603
1604__Examples__
1605
1606```js
1607var md = forge.md.sha384.create();
1608md.update('The quick brown fox jumps over the lazy dog');
1609console.log(md.digest().toHex());
1610// output: ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1
1611```
1612
1613<a name="sha512" />
1614### SHA512
1615
1616Provides [SHA-512][] message digests.
1617
1618__Examples__
1619
1620```js
1621// SHA-512
1622var md = forge.md.sha512.create();
1623md.update('The quick brown fox jumps over the lazy dog');
1624console.log(md.digest().toHex());
1625// output: 07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6
1626
1627// SHA-512/224
1628var md = forge.md.sha512.sha224.create();
1629md.update('The quick brown fox jumps over the lazy dog');
1630console.log(md.digest().toHex());
1631// output: 944cd2847fb54558d4775db0485a50003111c8e5daa63fe722c6aa37
1632
1633// SHA-512/256
1634var md = forge.md.sha512.sha256.create();
1635md.update('The quick brown fox jumps over the lazy dog');
1636console.log(md.digest().toHex());
1637// output: dd9d67b371519c339ed8dbd25af90e976a1eeefd4ad3d889005e532fc5bef04d
1638```
1639
1640<a name="md5" />
1641### MD5
1642
1643Provides [MD5][] message digests.
1644
1645__Examples__
1646
1647```js
1648var md = forge.md.md5.create();
1649md.update('The quick brown fox jumps over the lazy dog');
1650console.log(md.digest().toHex());
1651// output: 9e107d9d372bb6826bd81d3542a419d6
1652```
1653
1654<a name="hmac" />
1655### HMAC
1656
1657Provides [HMAC][] w/any supported message digest algorithm.
1658
1659__Examples__
1660
1661```js
1662var hmac = forge.hmac.create();
1663hmac.start('sha1', 'Jefe');
1664hmac.update('what do ya want for nothing?');
1665console.log(hmac.digest().toHex());
1666// output: effcdf6ae5eb2fa2d27416d5f184df9c259a7c79
1667```
1668
1669Utilities
1670---------
1671
1672<a name="prime" />
1673### Prime
1674
1675Provides an API for generating large, random, probable primes.
1676
1677__Examples__
1678
1679```js
1680// generate a random prime on the main JS thread
1681var bits = 1024;
1682forge.prime.generateProbablePrime(bits, function(err, num) {
1683 console.log('random prime', num.toString(16));
1684});
1685
1686// generate a random prime using Web Workers (if available, otherwise
1687// falls back to the main thread)
1688var bits = 1024;
1689var options = {
1690 algorithm: {
1691 name: 'PRIMEINC',
1692 workers: -1 // auto-optimize # of workers
1693 }
1694};
1695forge.prime.generateProbablePrime(bits, options, function(err, num) {
1696 console.log('random prime', num.toString(16));
1697});
1698```
1699
1700<a name="prng" />
1701### PRNG
1702
1703Provides a [Fortuna][]-based cryptographically-secure pseudo-random number
1704generator, to be used with a cryptographic function backend, e.g. [AES][]. An
1705implementation using [AES][] as a backend is provided. An API for collecting
1706entropy is given, though if window.crypto.getRandomValues is available, it will
1707be used automatically.
1708
1709__Examples__
1710
1711```js
1712// get some random bytes synchronously
1713var bytes = forge.random.getBytesSync(32);
1714console.log(forge.util.bytesToHex(bytes));
1715
1716// get some random bytes asynchronously
1717forge.random.getBytes(32, function(err, bytes) {
1718 console.log(forge.util.bytesToHex(bytes));
1719});
1720
1721// collect some entropy if you'd like
1722forge.random.collect(someRandomBytes);
1723jQuery().mousemove(function(e) {
1724 forge.random.collectInt(e.clientX, 16);
1725 forge.random.collectInt(e.clientY, 16);
1726});
1727
1728// specify a seed file for use with the synchronous API if you'd like
1729forge.random.seedFileSync = function(needed) {
1730 // get 'needed' number of random bytes from somewhere
1731 return fetchedRandomBytes;
1732};
1733
1734// specify a seed file for use with the asynchronous API if you'd like
1735forge.random.seedFile = function(needed, callback) {
1736 // get the 'needed' number of random bytes from somewhere
1737 callback(null, fetchedRandomBytes);
1738});
1739
1740// register the main thread to send entropy or a Web Worker to receive
1741// entropy on demand from the main thread
1742forge.random.registerWorker(self);
1743
1744// generate a new instance of a PRNG with no collected entropy
1745var myPrng = forge.random.createInstance();
1746```
1747
1748<a name="task" />
1749### Tasks
1750
1751Provides queuing and synchronizing tasks in a web application.
1752
1753__Examples__
1754
1755```js
1756// TODO
1757```
1758
1759<a name="util" />
1760### Utilities
1761
1762Provides utility functions, including byte buffer support, base64,
1763bytes to/from hex, zlib inflate/deflate, etc.
1764
1765__Examples__
1766
1767```js
1768// encode/decode base64
1769var encoded = forge.util.encode64(str);
1770var str = forge.util.decode64(encoded);
1771
1772// encode/decode UTF-8
1773var encoded = forge.util.encodeUtf8(str);
1774var str = forge.util.decodeUtf8(encoded);
1775
1776// bytes to/from hex
1777var bytes = forge.util.hexToBytes(hex);
1778var hex = forge.util.bytesToHex(bytes);
1779
1780// create an empty byte buffer
1781var buffer = forge.util.createBuffer();
1782// create a byte buffer from raw binary bytes
1783var buffer = forge.util.createBuffer(input, 'raw');
1784// create a byte buffer from utf8 bytes
1785var buffer = forge.util.createBuffer(input, 'utf8');
1786
1787// get the length of the buffer in bytes
1788buffer.length();
1789// put bytes into the buffer
1790buffer.putBytes(bytes);
1791// put a 32-bit integer into the buffer
1792buffer.putInt32(10);
1793// buffer to hex
1794buffer.toHex();
1795// get a copy of the bytes in the buffer
1796bytes.bytes(/* count */);
1797// empty this buffer and get its contents
1798bytes.getBytes(/* count */);
1799
1800// convert a forge buffer into a Node.js Buffer
1801// make sure you specify the encoding as 'binary'
1802var forgeBuffer = forge.util.createBuffer();
1803var nodeBuffer = new Buffer(forgeBuffer.getBytes(), 'binary');
1804
1805// convert a Node.js Buffer into a forge buffer
1806// make sure you specify the encoding as 'binary'
1807var nodeBuffer = new Buffer();
1808var forgeBuffer = forge.util.createBuffer(nodeBuffer.toString('binary'));
1809
1810// parse a URL
1811var parsed = forge.util.parseUrl('http://example.com/foo?bar=baz');
1812// parsed.scheme, parsed.host, parsed.port, parsed.path, parsed.fullHost
1813```
1814
1815<a name="log" />
1816### Logging
1817
1818Provides logging to a javascript console using various categories and
1819levels of verbosity.
1820
1821__Examples__
1822
1823```js
1824// TODO
1825```
1826
1827<a name="debug" />
1828### Debugging
1829
1830Provides storage of debugging information normally inaccessible in
1831closures for viewing/investigation.
1832
1833__Examples__
1834
1835```js
1836// TODO
1837```
1838
1839<a name="flash" />
1840### Flash Networking Support
1841
1842The [flash README](./flash/README.md) provides details on rebuilding the
1843optional Flash component used for networking. It also provides details on
1844Policy Server support.
1845
1846Security Considerations
1847-----------------------
1848
1849When using this code please keep the following in mind:
1850
1851- Cryptography is hard. Please review and test this code before depending on it
1852 for critical functionality.
1853- The nature of JavaScript is that execution of this code depends on trusting a
1854 very large set of JavaScript tools and systems. Consider runtime variations,
1855 runtime characteristics, runtime optimization, code optimization, code
1856 minimization, code obfuscation, bundling tools, possible bugs, the Forge code
1857 itself, and so on.
1858- If using pre-built bundles from [Bower][] or similar be aware someone else
1859 ran the tools to create those files.
1860- Use a secure transport channel such as [TLS][] to load scripts and consider
1861 using additional security mechanisms such as [Subresource Integrity][] script
1862 attributes.
1863- Use "native" functionality where possible. This can be critical when dealing
1864 with performance and random number generation. Note that the JavaScript
1865 random number algorithms should perform well if given suitable entropy.
1866- Understand possible attacks against cryptographic systems. For instance side
1867 channel and timing attacks may be possible due to the difficulty in
1868 implementing constant time algorithms in pure JavaScript.
1869- Certain features in this library are less susceptible to attacks depending on
1870 usage. This primarily includes features that deal with data format
1871 manipulation or those that are not involved in communication.
1872
1873Library Background
1874------------------
1875
1876* http://digitalbazaar.com/2010/07/20/javascript-tls-1/
1877* http://digitalbazaar.com/2010/07/20/javascript-tls-2/
1878
1879Contact
1880-------
1881
1882* Code: https://github.com/digitalbazaar/forge
1883* Bugs: https://github.com/digitalbazaar/forge/issues
1884* Email: support@digitalbazaar.com
1885* IRC: [#forgejs][] on [freenode][]
1886
1887Donations
1888---------
1889
1890Financial support is welcome and helps contribute to futher development:
1891
1892* For [PayPal][] please send to paypal@digitalbazaar.com.
1893* Something else? Please contact support@digitalbazaar.com.
1894
1895[#forgejs]: https://webchat.freenode.net/?channels=#forgejs
1896[0.6.x]: https://github.com/digitalbazaar/forge/tree/0.6.x
1897[3DES]: http://en.wikipedia.org/wiki/Triple_DES
1898[AES]: http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
1899[ASN.1]: http://en.wikipedia.org/wiki/ASN.1
1900[Bower]: https://bower.io/
1901[Browserify]: http://browserify.org/
1902[CBC]: http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
1903[CFB]: http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
1904[CTR]: http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
1905[CommonJS]: https://en.wikipedia.org/wiki/CommonJS
1906[DES]: http://en.wikipedia.org/wiki/Data_Encryption_Standard
1907[ECB]: http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
1908[Fortuna]: http://en.wikipedia.org/wiki/Fortuna_(PRNG)
1909[GCM]: http://en.wikipedia.org/wiki/GCM_mode
1910[HMAC]: http://en.wikipedia.org/wiki/HMAC
1911[JavaScript]: http://en.wikipedia.org/wiki/JavaScript
1912[Karma]: https://karma-runner.github.io/
1913[MD5]: http://en.wikipedia.org/wiki/MD5
1914[Node.js]: http://nodejs.org/
1915[OFB]: http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
1916[PKCS#10]: http://en.wikipedia.org/wiki/Certificate_signing_request
1917[PKCS#12]: http://en.wikipedia.org/wiki/PKCS_%E2%99%AF12
1918[PKCS#5]: http://en.wikipedia.org/wiki/PKCS
1919[PKCS#7]: http://en.wikipedia.org/wiki/Cryptographic_Message_Syntax
1920[PayPal]: https://www.paypal.com/
1921[RC2]: http://en.wikipedia.org/wiki/RC2
1922[SHA-1]: http://en.wikipedia.org/wiki/SHA-1
1923[SHA-256]: http://en.wikipedia.org/wiki/SHA-256
1924[SHA-384]: http://en.wikipedia.org/wiki/SHA-384
1925[SHA-512]: http://en.wikipedia.org/wiki/SHA-512
1926[Subresource Integrity]: https://www.w3.org/TR/SRI/
1927[TLS]: http://en.wikipedia.org/wiki/Transport_Layer_Security
1928[UMD]: https://github.com/umdjs/umd
1929[X.509]: http://en.wikipedia.org/wiki/X.509
1930[freenode]: https://freenode.net/
1931[webpack]: https://webpack.github.io/