Projekt

Obecné

Profil

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