You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2099 lines
59 KiB

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