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.

2071 lines
58 KiB

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