A native implementation of TLS in Javascript and tools to write crypto-based and network-heavy webapps
Installations
npm install node-forge
Releases
Unable to fetch releases
Developer
Developer Guide
Module System
CommonJS, UMD
Min. Node Version
>= 6.13.0
Typescript Support
No
Node Version
14.19.1
NPM Version
6.14.5
Statistics
5,086 Stars
1,706 Commits
785 Forks
151 Watching
18 Branches
80 Contributors
Updated on 28 Nov 2024
Bundle Size
273.95 kB
Minified
71.77 kB
Minified + Gzipped
Languages
JavaScript (93.33%)
HTML (4.16%)
ActionScript (1.47%)
C (0.76%)
Python (0.2%)
CSS (0.07%)
Total Downloads
Cumulative downloads
Total Downloads
4,495,154,469
Last day
-9.8%
3,765,527
Compared to previous day
Last week
1.7%
22,217,240
Compared to previous week
Last month
6.4%
93,151,990
Compared to previous month
Last year
2.5%
1,014,404,427
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Dev Dependencies
27
Forge
A native implementation of TLS (and various other cryptographic tools) in JavaScript.
Introduction
The Forge software is a fully native implementation of the TLS protocol in JavaScript, a set of cryptography utilities, and a set of tools for developing Web Apps that utilize many network resources.
Performance
Forge is fast. Benchmarks against other popular JavaScript cryptography libraries can be found here:
- http://dominictarr.github.io/crypto-bench/
- http://cryptojs.altervista.org/test/simulate-threading-speed_test.html
Documentation
API
Transports
Ciphers
PKI
Message Digests
Utilities
Other
Installation
Note: Please see the Security Considerations section before using packaging systems and pre-built files.
Forge uses a CommonJS module structure with a build process for browser bundles. The older 0.6.x branch with standalone files is available but will not be regularly updated.
Node.js
If you want to use forge with Node.js, it is available through npm
:
https://www.npmjs.com/package/node-forge
Installation:
npm install node-forge
You can then use forge as a regular module:
1var forge = require('node-forge');
The npm package includes pre-built forge.min.js
, forge.all.min.js
, and
prime.worker.min.js
using the UMD format.
jsDelivr CDN
To use it via jsDelivr include this in your html:
1<script src="https://cdn.jsdelivr.net/npm/node-forge@1.0.0/dist/forge.min.js"></script>
unpkg CDN
To use it via unpkg include this in your html:
1<script src="https://unpkg.com/node-forge@1.0.0/dist/forge.min.js"></script>
Development Requirements
The core JavaScript has the following requirements to build and test:
- Building a browser bundle:
- Node.js
- npm
- Testing
- Node.js
- npm
- Chrome, Firefox, Safari (optional)
Some special networking features can optionally use a Flash component. See the Flash README for details.
Building for a web browser
To create single file bundles for use with browsers run the following:
npm install
npm run build
This will create single non-minimized and minimized files that can be included in the browser:
dist/forge.js
dist/forge.min.js
A bundle that adds some utilities and networking support is also available:
dist/forge.all.js
dist/forge.all.min.js
Include the file via:
1<script src="YOUR_SCRIPT_PATH/forge.js"></script>
or
1<script src="YOUR_SCRIPT_PATH/forge.min.js"></script>
The above bundles will synchronously create a global 'forge' object.
Note: These bundles will not include any WebWorker scripts (eg:
dist/prime.worker.js
), so these will need to be accessible from the browser
if any WebWorkers are used.
Building a custom browser bundle
The build process uses webpack and the config file can be modified to generate a file or files that only contain the parts of forge you need.
Browserify override support is also present in package.json
.
Testing
Prepare to run tests
npm install
Running automated tests with Node.js
Forge natively runs in a Node.js environment:
npm test
Running automated tests with Headless Chrome
Automated testing is done via Karma. By default it will run the tests with Headless Chrome.
npm run test-karma
Is 'mocha' reporter output too verbose? Other reporters are available. Try 'dots', 'progress', or 'tap'.
npm run test-karma -- --reporters progress
By default webpack is used. Browserify can also be used.
BUNDLER=browserify npm run test-karma
Running automated tests with one or more browsers
You can also specify one or more browsers to use.
npm run test-karma -- --browsers Chrome,Firefox,Safari,ChromeHeadless
The reporter option and BUNDLER
environment variable can also be used.
Running manual tests in a browser
Testing in a browser uses webpack to combine forge and all tests and then
loading the result in a browser. A simple web server is provided that will
output the HTTP or HTTPS URLs to load. It also will start a simple Flash Policy
Server. Unit tests and older legacy tests are provided. Custom ports can be
used by running node tests/server.js
manually.
To run the unit tests in a browser a special forge build is required:
npm run test-build
To run legacy browser based tests the main forge build is required:
npm run build
The tests are run with a custom server that prints out the URLs to use:
npm run test-server
Running other tests
There are some other random tests and benchmarks available in the tests directory.
Coverage testing
To perform coverage testing of the unit tests, run the following. The results
will be put in the coverage/
directory. Note that coverage testing can slow
down some tests considerably.
npm install
npm run coverage
Contributing
Any contributions (eg: PRs) that are accepted will be brought under the same license used by the rest of the Forge project. This license allows Forge to be used under the terms of either the BSD License or the GNU General Public License (GPL) Version 2.
See: LICENSE
If a contribution contains 3rd party source code with its own license, it may retain it, so long as that license is compatible with the Forge license.
API
Options
If at any time you wish to disable the use of native code, where available,
for particular forge features like its secure random number generator, you
may set the forge.options.usePureJavaScript
flag to true
. It is
not recommended that you set this flag as native code is typically more
performant and may have stronger security properties. It may be useful to
set this flag to test certain features that you plan to run in environments
that are different from your testing environment.
To disable native code when including forge in the browser:
1// run this *after* including the forge script 2forge.options.usePureJavaScript = true;
To disable native code when using Node.js:
1var forge = require('node-forge'); 2forge.options.usePureJavaScript = true;
Transports
TLS
Provides a native javascript client and server-side TLS implementation.
Examples
1// create TLS client
2var client = forge.tls.createConnection({
3 server: false,
4 caStore: /* Array of PEM-formatted certs or a CA store object */,
5 sessionCache: {},
6 // supported cipher suites in order of preference
7 cipherSuites: [
8 forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA,
9 forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA],
10 virtualHost: 'example.com',
11 verify: function(connection, verified, depth, certs) {
12 if(depth === 0) {
13 var cn = certs[0].subject.getField('CN').value;
14 if(cn !== 'example.com') {
15 verified = {
16 alert: forge.tls.Alert.Description.bad_certificate,
17 message: 'Certificate common name does not match hostname.'
18 };
19 }
20 }
21 return verified;
22 },
23 connected: function(connection) {
24 console.log('connected');
25 // send message to server
26 connection.prepare(forge.util.encodeUtf8('Hi server!'));
27 /* NOTE: experimental, start heartbeat retransmission timer
28 myHeartbeatTimer = setInterval(function() {
29 connection.prepareHeartbeatRequest(forge.util.createBuffer('1234'));
30 }, 5*60*1000);*/
31 },
32 /* provide a client-side cert if you want
33 getCertificate: function(connection, hint) {
34 return myClientCertificate;
35 },
36 /* the private key for the client-side cert if provided */
37 getPrivateKey: function(connection, cert) {
38 return myClientPrivateKey;
39 },
40 tlsDataReady: function(connection) {
41 // TLS data (encrypted) is ready to be sent to the server
42 sendToServerSomehow(connection.tlsData.getBytes());
43 // if you were communicating with the server below, you'd do:
44 // server.process(connection.tlsData.getBytes());
45 },
46 dataReady: function(connection) {
47 // clear data from the server is ready
48 console.log('the server sent: ' +
49 forge.util.decodeUtf8(connection.data.getBytes()));
50 // close connection
51 connection.close();
52 },
53 /* NOTE: experimental
54 heartbeatReceived: function(connection, payload) {
55 // restart retransmission timer, look at payload
56 clearInterval(myHeartbeatTimer);
57 myHeartbeatTimer = setInterval(function() {
58 connection.prepareHeartbeatRequest(forge.util.createBuffer('1234'));
59 }, 5*60*1000);
60 payload.getBytes();
61 },*/
62 closed: function(connection) {
63 console.log('disconnected');
64 },
65 error: function(connection, error) {
66 console.log('uh oh', error);
67 }
68});
69
70// start the handshake process
71client.handshake();
72
73// when encrypted TLS data is received from the server, process it
74client.process(encryptedBytesFromServer);
75
76// create TLS server
77var server = forge.tls.createConnection({
78 server: true,
79 caStore: /* Array of PEM-formatted certs or a CA store object */,
80 sessionCache: {},
81 // supported cipher suites in order of preference
82 cipherSuites: [
83 forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA,
84 forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA],
85 // require a client-side certificate if you want
86 verifyClient: true,
87 verify: function(connection, verified, depth, certs) {
88 if(depth === 0) {
89 var cn = certs[0].subject.getField('CN').value;
90 if(cn !== 'the-client') {
91 verified = {
92 alert: forge.tls.Alert.Description.bad_certificate,
93 message: 'Certificate common name does not match expected client.'
94 };
95 }
96 }
97 return verified;
98 },
99 connected: function(connection) {
100 console.log('connected');
101 // send message to client
102 connection.prepare(forge.util.encodeUtf8('Hi client!'));
103 /* NOTE: experimental, start heartbeat retransmission timer
104 myHeartbeatTimer = setInterval(function() {
105 connection.prepareHeartbeatRequest(forge.util.createBuffer('1234'));
106 }, 5*60*1000);*/
107 },
108 getCertificate: function(connection, hint) {
109 return myServerCertificate;
110 },
111 getPrivateKey: function(connection, cert) {
112 return myServerPrivateKey;
113 },
114 tlsDataReady: function(connection) {
115 // TLS data (encrypted) is ready to be sent to the client
116 sendToClientSomehow(connection.tlsData.getBytes());
117 // if you were communicating with the client above you'd do:
118 // client.process(connection.tlsData.getBytes());
119 },
120 dataReady: function(connection) {
121 // clear data from the client is ready
122 console.log('the client sent: ' +
123 forge.util.decodeUtf8(connection.data.getBytes()));
124 // close connection
125 connection.close();
126 },
127 /* NOTE: experimental
128 heartbeatReceived: function(connection, payload) {
129 // restart retransmission timer, look at payload
130 clearInterval(myHeartbeatTimer);
131 myHeartbeatTimer = setInterval(function() {
132 connection.prepareHeartbeatRequest(forge.util.createBuffer('1234'));
133 }, 5*60*1000);
134 payload.getBytes();
135 },*/
136 closed: function(connection) {
137 console.log('disconnected');
138 },
139 error: function(connection, error) {
140 console.log('uh oh', error);
141 }
142});
143
144// when encrypted TLS data is received from the client, process it
145server.process(encryptedBytesFromClient);
Connect to a TLS server using node's net.Socket:
1var socket = new net.Socket(); 2 3var client = forge.tls.createConnection({ 4 server: false, 5 verify: function(connection, verified, depth, certs) { 6 // skip verification for testing 7 console.log('[tls] server certificate verified'); 8 return true; 9 }, 10 connected: function(connection) { 11 console.log('[tls] connected'); 12 // prepare some data to send (note that the string is interpreted as 13 // 'binary' encoded, which works for HTTP which only uses ASCII, use 14 // forge.util.encodeUtf8(str) otherwise 15 client.prepare('GET / HTTP/1.0\r\n\r\n'); 16 }, 17 tlsDataReady: function(connection) { 18 // encrypted data is ready to be sent to the server 19 var data = connection.tlsData.getBytes(); 20 socket.write(data, 'binary'); // encoding should be 'binary' 21 }, 22 dataReady: function(connection) { 23 // clear data from the server is ready 24 var data = connection.data.getBytes(); 25 console.log('[tls] data received from the server: ' + data); 26 }, 27 closed: function() { 28 console.log('[tls] disconnected'); 29 }, 30 error: function(connection, error) { 31 console.log('[tls] error', error); 32 } 33}); 34 35socket.on('connect', function() { 36 console.log('[socket] connected'); 37 client.handshake(); 38}); 39socket.on('data', function(data) { 40 client.process(data.toString('binary')); // encoding should be 'binary' 41}); 42socket.on('end', function() { 43 console.log('[socket] disconnected'); 44}); 45 46// connect to google.com 47socket.connect(443, 'google.com'); 48 49// or connect to gmail's imap server (but don't send the HTTP header above) 50//socket.connect(993, 'imap.gmail.com');
HTTP
Provides a native JavaScript mini-implementation of an http client that uses pooled sockets.
Examples
1// create an HTTP GET request 2var request = forge.http.createRequest({method: 'GET', path: url.path}); 3 4// send the request somewhere 5sendSomehow(request.toString()); 6 7// receive response 8var buffer = forge.util.createBuffer(); 9var response = forge.http.createResponse(); 10var someAsyncDataHandler = function(bytes) { 11 if(!response.bodyReceived) { 12 buffer.putBytes(bytes); 13 if(!response.headerReceived) { 14 if(response.readHeader(buffer)) { 15 console.log('HTTP response header: ' + response.toString()); 16 } 17 } 18 if(response.headerReceived && !response.bodyReceived) { 19 if(response.readBody(buffer)) { 20 console.log('HTTP response body: ' + response.body); 21 } 22 } 23 } 24};
SSH
Provides some SSH utility functions.
Examples
1// encodes (and optionally encrypts) a private RSA key as a Putty PPK file
2forge.ssh.privateKeyToPutty(privateKey, passphrase, comment);
3
4// encodes a public RSA key as an OpenSSH file
5forge.ssh.publicKeyToOpenSSH(key, comment);
6
7// encodes a private RSA key as an OpenSSH file
8forge.ssh.privateKeyToOpenSSH(privateKey, passphrase);
9
10// gets the SSH public key fingerprint in a byte buffer
11forge.ssh.getPublicKeyFingerprint(key);
12
13// gets a hex-encoded, colon-delimited SSH public key fingerprint
14forge.ssh.getPublicKeyFingerprint(key, {encoding: 'hex', delimiter: ':'});
XHR
Provides an XmlHttpRequest implementation using forge.http as a backend.
Examples
1// TODO
Sockets
Provides an interface to create and use raw sockets provided via Flash.
Examples
1// TODO
Ciphers
CIPHER
Provides a basic API for block encryption and decryption. There is built-in support for the ciphers: AES, 3DES, and DES, and for the modes of operation: ECB, CBC, CFB, OFB, CTR, and GCM.
These algorithms are currently supported:
- AES-ECB
- AES-CBC
- AES-CFB
- AES-OFB
- AES-CTR
- AES-GCM
- 3DES-ECB
- 3DES-CBC
- DES-ECB
- DES-CBC
When using an AES algorithm, the key size will determine whether AES-128, AES-192, or AES-256 is used (all are supported). When a DES algorithm is used, the key size will determine whether 3DES or regular DES is used. Use a 3DES algorithm to enforce Triple-DES.
Examples
1// generate a random key and IV 2// Note: a key size of 16 bytes will use AES-128, 24 => AES-192, 32 => AES-256 3var key = forge.random.getBytesSync(16); 4var iv = forge.random.getBytesSync(16); 5 6/* alternatively, generate a password-based 16-byte key 7var salt = forge.random.getBytesSync(128); 8var key = forge.pkcs5.pbkdf2('password', salt, numIterations, 16); 9*/ 10 11// encrypt some bytes using CBC mode 12// (other modes include: ECB, CFB, OFB, CTR, and GCM) 13// Note: CBC and ECB modes use PKCS#7 padding as default 14var cipher = forge.cipher.createCipher('AES-CBC', key); 15cipher.start({iv: iv}); 16cipher.update(forge.util.createBuffer(someBytes)); 17cipher.finish(); 18var encrypted = cipher.output; 19// outputs encrypted hex 20console.log(encrypted.toHex()); 21 22// decrypt some bytes using CBC mode 23// (other modes include: CFB, OFB, CTR, and GCM) 24var decipher = forge.cipher.createDecipher('AES-CBC', key); 25decipher.start({iv: iv}); 26decipher.update(encrypted); 27var result = decipher.finish(); // check 'result' for true/false 28// outputs decrypted hex 29console.log(decipher.output.toHex()); 30 31// decrypt bytes using CBC mode and streaming 32// Performance can suffer for large multi-MB inputs due to buffer 33// manipulations. Stream processing in chunks can offer significant 34// improvement. CPU intensive update() calls could also be performed with 35// setImmediate/setTimeout to avoid blocking the main browser UI thread (not 36// shown here). Optimal block size depends on the JavaScript VM and other 37// factors. Encryption can use a simple technique for increased performance. 38var encryptedBytes = encrypted.bytes(); 39var decipher = forge.cipher.createDecipher('AES-CBC', key); 40decipher.start({iv: iv}); 41var length = encryptedBytes.length; 42var chunkSize = 1024 * 64; 43var index = 0; 44var decrypted = ''; 45do { 46 decrypted += decipher.output.getBytes(); 47 var buf = forge.util.createBuffer(encryptedBytes.substr(index, chunkSize)); 48 decipher.update(buf); 49 index += chunkSize; 50} while(index < length); 51var result = decipher.finish(); 52assert(result); 53decrypted += decipher.output.getBytes(); 54console.log(forge.util.bytesToHex(decrypted)); 55 56// encrypt some bytes using GCM mode 57var cipher = forge.cipher.createCipher('AES-GCM', key); 58cipher.start({ 59 iv: iv, // should be a 12-byte binary-encoded string or byte buffer 60 additionalData: 'binary-encoded string', // optional 61 tagLength: 128 // optional, defaults to 128 bits 62}); 63cipher.update(forge.util.createBuffer(someBytes)); 64cipher.finish(); 65var encrypted = cipher.output; 66var tag = cipher.mode.tag; 67// outputs encrypted hex 68console.log(encrypted.toHex()); 69// outputs authentication tag 70console.log(tag.toHex()); 71 72// decrypt some bytes using GCM mode 73var decipher = forge.cipher.createDecipher('AES-GCM', key); 74decipher.start({ 75 iv: iv, 76 additionalData: 'binary-encoded string', // optional 77 tagLength: 128, // optional, defaults to 128 bits 78 tag: tag // authentication tag from encryption 79}); 80decipher.update(encrypted); 81var pass = decipher.finish(); 82// pass is false if there was a failure (eg: authentication tag didn't match) 83if(pass) { 84 // outputs decrypted hex 85 console.log(decipher.output.toHex()); 86}
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/GnuPG):
1var forge = require('node-forge'); 2var fs = require('fs'); 3 4// openssl enc -des3 -in input.txt -out input.enc 5function encrypt(password) { 6 var input = fs.readFileSync('input.txt', {encoding: 'binary'}); 7 8 // 3DES key and IV sizes 9 var keySize = 24; 10 var ivSize = 8; 11 12 // get derived bytes 13 // Notes: 14 // 1. If using an alternative hash (eg: "-md sha1") pass 15 // "forge.md.sha1.create()" as the final parameter. 16 // 2. If using "-nosalt", set salt to null. 17 var salt = forge.random.getBytesSync(8); 18 // var md = forge.md.sha1.create(); // "-md sha1" 19 var derivedBytes = forge.pbe.opensslDeriveBytes( 20 password, salt, keySize + ivSize/*, md*/); 21 var buffer = forge.util.createBuffer(derivedBytes); 22 var key = buffer.getBytes(keySize); 23 var iv = buffer.getBytes(ivSize); 24 25 var cipher = forge.cipher.createCipher('3DES-CBC', key); 26 cipher.start({iv: iv}); 27 cipher.update(forge.util.createBuffer(input, 'binary')); 28 cipher.finish(); 29 30 var output = forge.util.createBuffer(); 31 32 // if using a salt, prepend this to the output: 33 if(salt !== null) { 34 output.putBytes('Salted__'); // (add to match openssl tool output) 35 output.putBytes(salt); 36 } 37 output.putBuffer(cipher.output); 38 39 fs.writeFileSync('input.enc', output.getBytes(), {encoding: 'binary'}); 40} 41 42// openssl enc -d -des3 -in input.enc -out input.dec.txt 43function decrypt(password) { 44 var input = fs.readFileSync('input.enc', {encoding: 'binary'}); 45 46 // parse salt from input 47 input = forge.util.createBuffer(input, 'binary'); 48 // skip "Salted__" (if known to be present) 49 input.getBytes('Salted__'.length); 50 // read 8-byte salt 51 var salt = input.getBytes(8); 52 53 // Note: if using "-nosalt", skip above parsing and use 54 // var salt = null; 55 56 // 3DES key and IV sizes 57 var keySize = 24; 58 var ivSize = 8; 59 60 var derivedBytes = forge.pbe.opensslDeriveBytes( 61 password, salt, keySize + ivSize); 62 var buffer = forge.util.createBuffer(derivedBytes); 63 var key = buffer.getBytes(keySize); 64 var iv = buffer.getBytes(ivSize); 65 66 var decipher = forge.cipher.createDecipher('3DES-CBC', key); 67 decipher.start({iv: iv}); 68 decipher.update(input); 69 var result = decipher.finish(); // check 'result' for true/false 70 71 fs.writeFileSync( 72 'input.dec.txt', decipher.output.getBytes(), {encoding: 'binary'}); 73}
AES
Provides AES encryption and decryption in CBC, CFB, OFB, CTR, and GCM modes. See CIPHER for examples.
DES
Provides 3DES and DES encryption and decryption in ECB and CBC modes. See CIPHER for examples.
RC2
Examples
1// generate a random key and IV 2var key = forge.random.getBytesSync(16); 3var iv = forge.random.getBytesSync(8); 4 5// encrypt some bytes 6var cipher = forge.rc2.createEncryptionCipher(key); 7cipher.start(iv); 8cipher.update(forge.util.createBuffer(someBytes)); 9cipher.finish(); 10var encrypted = cipher.output; 11// outputs encrypted hex 12console.log(encrypted.toHex()); 13 14// decrypt some bytes 15var cipher = forge.rc2.createDecryptionCipher(key); 16cipher.start(iv); 17cipher.update(encrypted); 18cipher.finish(); 19// outputs decrypted hex 20console.log(cipher.output.toHex());
PKI
Provides X.509 certificate support, ED25519 key generation and signing/verifying, and RSA public and private key encoding, decoding, encryption/decryption, and signing/verifying.
ED25519
Special thanks to TweetNaCl.js for providing the bulk of the implementation.
Examples
1var ed25519 = forge.pki.ed25519; 2 3// generate a random ED25519 keypair 4var keypair = ed25519.generateKeyPair(); 5// `keypair.publicKey` is a node.js Buffer or Uint8Array 6// `keypair.privateKey` is a node.js Buffer or Uint8Array 7 8// generate a random ED25519 keypair based on a random 32-byte seed 9var seed = forge.random.getBytesSync(32); 10var keypair = ed25519.generateKeyPair({seed: seed}); 11 12// generate a random ED25519 keypair based on a "password" 32-byte seed 13var password = 'Mai9ohgh6ahxee0jutheew0pungoozil'; 14var seed = new forge.util.ByteBuffer(password, 'utf8'); 15var keypair = ed25519.generateKeyPair({seed: seed}); 16 17// sign a UTF-8 message 18var signature = ED25519.sign({ 19 message: 'test', 20 // also accepts `binary` if you want to pass a binary string 21 encoding: 'utf8', 22 // node.js Buffer, Uint8Array, forge ByteBuffer, binary string 23 privateKey: privateKey 24}); 25// `signature` is a node.js Buffer or Uint8Array 26 27// sign a message passed as a buffer 28var signature = ED25519.sign({ 29 // also accepts a forge ByteBuffer or Uint8Array 30 message: Buffer.from('test', 'utf8'), 31 privateKey: privateKey 32}); 33 34// sign a message digest (shorter "message" == better performance) 35var md = forge.md.sha256.create(); 36md.update('test', 'utf8'); 37var signature = ED25519.sign({ 38 md: md, 39 privateKey: privateKey 40}); 41 42// verify a signature on a UTF-8 message 43var verified = ED25519.verify({ 44 message: 'test', 45 encoding: 'utf8', 46 // node.js Buffer, Uint8Array, forge ByteBuffer, or binary string 47 signature: signature, 48 // node.js Buffer, Uint8Array, forge ByteBuffer, or binary string 49 publicKey: publicKey 50}); 51// `verified` is true/false 52 53// sign a message passed as a buffer 54var verified = ED25519.verify({ 55 // also accepts a forge ByteBuffer or Uint8Array 56 message: Buffer.from('test', 'utf8'), 57 // node.js Buffer, Uint8Array, forge ByteBuffer, or binary string 58 signature: signature, 59 // node.js Buffer, Uint8Array, forge ByteBuffer, or binary string 60 publicKey: publicKey 61}); 62 63// verify a signature on a message digest 64var md = forge.md.sha256.create(); 65md.update('test', 'utf8'); 66var verified = ED25519.verify({ 67 md: md, 68 // node.js Buffer, Uint8Array, forge ByteBuffer, or binary string 69 signature: signature, 70 // node.js Buffer, Uint8Array, forge ByteBuffer, or binary string 71 publicKey: publicKey 72});
RSA
Examples
1var rsa = forge.pki.rsa; 2 3// generate an RSA key pair synchronously 4// *NOT RECOMMENDED*: Can be significantly slower than async and may block 5// JavaScript execution. Will use native Node.js 10.12.0+ API if possible. 6var keypair = rsa.generateKeyPair({bits: 2048, e: 0x10001}); 7 8// generate an RSA key pair asynchronously (uses web workers if available) 9// use workers: -1 to run a fast core estimator to optimize # of workers 10// *RECOMMENDED*: Can be significantly faster than sync. Will use native 11// Node.js 10.12.0+ or WebCrypto API if possible. 12rsa.generateKeyPair({bits: 2048, workers: 2}, function(err, keypair) { 13 // keypair.privateKey, keypair.publicKey 14}); 15 16// generate an RSA key pair in steps that attempt to run for a specified period 17// of time on the main JS thread 18var state = rsa.createKeyPairGenerationState(2048, 0x10001); 19var step = function() { 20 // run for 100 ms 21 if(!rsa.stepKeyPairGenerationState(state, 100)) { 22 setTimeout(step, 1); 23 } 24 else { 25 // done, turn off progress indicator, use state.keys 26 } 27}; 28// turn on progress indicator, schedule generation to run 29setTimeout(step); 30 31// sign data with a private key and output DigestInfo DER-encoded bytes 32// (defaults to RSASSA PKCS#1 v1.5) 33var md = forge.md.sha1.create(); 34md.update('sign this', 'utf8'); 35var signature = privateKey.sign(md); 36 37// verify data with a public key 38// (defaults to RSASSA PKCS#1 v1.5) 39var verified = publicKey.verify(md.digest().bytes(), signature); 40 41// sign data using RSASSA-PSS where PSS uses a SHA-1 hash, a SHA-1 based 42// masking function MGF1, and a 20 byte salt 43var md = forge.md.sha1.create(); 44md.update('sign this', 'utf8'); 45var pss = forge.pss.create({ 46 md: forge.md.sha1.create(), 47 mgf: forge.mgf.mgf1.create(forge.md.sha1.create()), 48 saltLength: 20 49 // optionally pass 'prng' with a custom PRNG implementation 50 // optionalls pass 'salt' with a forge.util.ByteBuffer w/custom salt 51}); 52var signature = privateKey.sign(md, pss); 53 54// verify RSASSA-PSS signature 55var pss = forge.pss.create({ 56 md: forge.md.sha1.create(), 57 mgf: forge.mgf.mgf1.create(forge.md.sha1.create()), 58 saltLength: 20 59 // optionally pass 'prng' with a custom PRNG implementation 60}); 61var md = forge.md.sha1.create(); 62md.update('sign this', 'utf8'); 63publicKey.verify(md.digest().getBytes(), signature, pss); 64 65// encrypt data with a public key (defaults to RSAES PKCS#1 v1.5) 66var encrypted = publicKey.encrypt(bytes); 67 68// decrypt data with a private key (defaults to RSAES PKCS#1 v1.5) 69var decrypted = privateKey.decrypt(encrypted); 70 71// encrypt data with a public key using RSAES PKCS#1 v1.5 72var encrypted = publicKey.encrypt(bytes, 'RSAES-PKCS1-V1_5'); 73 74// decrypt data with a private key using RSAES PKCS#1 v1.5 75var decrypted = privateKey.decrypt(encrypted, 'RSAES-PKCS1-V1_5'); 76 77// encrypt data with a public key using RSAES-OAEP 78var encrypted = publicKey.encrypt(bytes, 'RSA-OAEP'); 79 80// decrypt data with a private key using RSAES-OAEP 81var decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP'); 82 83// encrypt data with a public key using RSAES-OAEP/SHA-256 84var encrypted = publicKey.encrypt(bytes, 'RSA-OAEP', { 85 md: forge.md.sha256.create() 86}); 87 88// decrypt data with a private key using RSAES-OAEP/SHA-256 89var decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP', { 90 md: forge.md.sha256.create() 91}); 92 93// encrypt data with a public key using RSAES-OAEP/SHA-256/MGF1-SHA-1 94// compatible with Java's RSA/ECB/OAEPWithSHA-256AndMGF1Padding 95var encrypted = publicKey.encrypt(bytes, 'RSA-OAEP', { 96 md: forge.md.sha256.create(), 97 mgf1: { 98 md: forge.md.sha1.create() 99 } 100}); 101 102// decrypt data with a private key using RSAES-OAEP/SHA-256/MGF1-SHA-1 103// compatible with Java's RSA/ECB/OAEPWithSHA-256AndMGF1Padding 104var decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP', { 105 md: forge.md.sha256.create(), 106 mgf1: { 107 md: forge.md.sha1.create() 108 } 109}); 110
RSA-KEM
Examples
1// generate an RSA key pair asynchronously (uses web workers if available) 2// use workers: -1 to run a fast core estimator to optimize # of workers 3forge.rsa.generateKeyPair({bits: 2048, workers: -1}, function(err, keypair) { 4 // keypair.privateKey, keypair.publicKey 5}); 6 7// generate and encapsulate a 16-byte secret key 8var kdf1 = new forge.kem.kdf1(forge.md.sha1.create()); 9var kem = forge.kem.rsa.create(kdf1); 10var result = kem.encrypt(keypair.publicKey, 16); 11// result has 'encapsulation' and 'key' 12 13// encrypt some bytes 14var iv = forge.random.getBytesSync(12); 15var someBytes = 'hello world!'; 16var cipher = forge.cipher.createCipher('AES-GCM', result.key); 17cipher.start({iv: iv}); 18cipher.update(forge.util.createBuffer(someBytes)); 19cipher.finish(); 20var encrypted = cipher.output.getBytes(); 21var tag = cipher.mode.tag.getBytes(); 22 23// send 'encrypted', 'iv', 'tag', and result.encapsulation to recipient 24 25// decrypt encapsulated 16-byte secret key 26var kdf1 = new forge.kem.kdf1(forge.md.sha1.create()); 27var kem = forge.kem.rsa.create(kdf1); 28var key = kem.decrypt(keypair.privateKey, result.encapsulation, 16); 29 30// decrypt some bytes 31var decipher = forge.cipher.createDecipher('AES-GCM', key); 32decipher.start({iv: iv, tag: tag}); 33decipher.update(forge.util.createBuffer(encrypted)); 34var pass = decipher.finish(); 35// pass is false if there was a failure (eg: authentication tag didn't match) 36if(pass) { 37 // outputs 'hello world!' 38 console.log(decipher.output.getBytes()); 39} 40
X.509
Examples
1var pki = forge.pki;
2
3// convert a PEM-formatted public key to a Forge public key
4var publicKey = pki.publicKeyFromPem(pem);
5
6// convert a Forge public key to PEM-format
7var pem = pki.publicKeyToPem(publicKey);
8
9// convert an ASN.1 SubjectPublicKeyInfo to a Forge public key
10var publicKey = pki.publicKeyFromAsn1(subjectPublicKeyInfo);
11
12// convert a Forge public key to an ASN.1 SubjectPublicKeyInfo
13var subjectPublicKeyInfo = pki.publicKeyToAsn1(publicKey);
14
15// gets a SHA-1 RSAPublicKey fingerprint a byte buffer
16pki.getPublicKeyFingerprint(key);
17
18// gets a SHA-1 SubjectPublicKeyInfo fingerprint a byte buffer
19pki.getPublicKeyFingerprint(key, {type: 'SubjectPublicKeyInfo'});
20
21// gets a hex-encoded, colon-delimited SHA-1 RSAPublicKey public key fingerprint
22pki.getPublicKeyFingerprint(key, {encoding: 'hex', delimiter: ':'});
23
24// gets a hex-encoded, colon-delimited SHA-1 SubjectPublicKeyInfo public key fingerprint
25pki.getPublicKeyFingerprint(key, {
26 type: 'SubjectPublicKeyInfo',
27 encoding: 'hex',
28 delimiter: ':'
29});
30
31// gets a hex-encoded, colon-delimited MD5 RSAPublicKey public key fingerprint
32pki.getPublicKeyFingerprint(key, {
33 md: forge.md.md5.create(),
34 encoding: 'hex',
35 delimiter: ':'
36});
37
38// creates a CA store
39var caStore = pki.createCaStore([/* PEM-encoded cert */, ...]);
40
41// add a certificate to the CA store
42caStore.addCertificate(certObjectOrPemString);
43
44// gets the issuer (its certificate) for the given certificate
45var issuerCert = caStore.getIssuer(subjectCert);
46
47// verifies a certificate chain against a CA store
48pki.verifyCertificateChain(caStore, chain, customVerifyCallback);
49
50// signs a certificate using the given private key
51cert.sign(privateKey);
52
53// signs a certificate using SHA-256 instead of SHA-1
54cert.sign(privateKey, forge.md.sha256.create());
55
56// verifies an issued certificate using the certificates public key
57var verified = issuer.verify(issued);
58
59// generate a keypair and create an X.509v3 certificate
60var keys = pki.rsa.generateKeyPair(2048);
61var cert = pki.createCertificate();
62cert.publicKey = keys.publicKey;
63// alternatively set public key from a csr
64//cert.publicKey = csr.publicKey;
65// NOTE: serialNumber is the hex encoded value of an ASN.1 INTEGER.
66// Conforming CAs should ensure serialNumber is:
67// - no more than 20 octets
68// - non-negative (prefix a '00' if your value starts with a '1' bit)
69cert.serialNumber = '01';
70cert.validity.notBefore = new Date();
71cert.validity.notAfter = new Date();
72cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);
73var attrs = [{
74 name: 'commonName',
75 value: 'example.org'
76}, {
77 name: 'countryName',
78 value: 'US'
79}, {
80 shortName: 'ST',
81 value: 'Virginia'
82}, {
83 name: 'localityName',
84 value: 'Blacksburg'
85}, {
86 name: 'organizationName',
87 value: 'Test'
88}, {
89 shortName: 'OU',
90 value: 'Test'
91}];
92cert.setSubject(attrs);
93// alternatively set subject from a csr
94//cert.setSubject(csr.subject.attributes);
95cert.setIssuer(attrs);
96cert.setExtensions([{
97 name: 'basicConstraints',
98 cA: true
99}, {
100 name: 'keyUsage',
101 keyCertSign: true,
102 digitalSignature: true,
103 nonRepudiation: true,
104 keyEncipherment: true,
105 dataEncipherment: true
106}, {
107 name: 'extKeyUsage',
108 serverAuth: true,
109 clientAuth: true,
110 codeSigning: true,
111 emailProtection: true,
112 timeStamping: true
113}, {
114 name: 'nsCertType',
115 client: true,
116 server: true,
117 email: true,
118 objsign: true,
119 sslCA: true,
120 emailCA: true,
121 objCA: true
122}, {
123 name: 'subjectAltName',
124 altNames: [{
125 type: 6, // URI
126 value: 'http://example.org/webid#me'
127 }, {
128 type: 7, // IP
129 ip: '127.0.0.1'
130 }]
131}, {
132 name: 'subjectKeyIdentifier'
133}]);
134/* alternatively set extensions from a csr
135var extensions = csr.getAttribute({name: 'extensionRequest'}).extensions;
136// optionally add more extensions
137extensions.push.apply(extensions, [{
138 name: 'basicConstraints',
139 cA: true
140}, {
141 name: 'keyUsage',
142 keyCertSign: true,
143 digitalSignature: true,
144 nonRepudiation: true,
145 keyEncipherment: true,
146 dataEncipherment: true
147}]);
148cert.setExtensions(extensions);
149*/
150// self-sign certificate
151cert.sign(keys.privateKey);
152
153// convert a Forge certificate to PEM
154var pem = pki.certificateToPem(cert);
155
156// convert a Forge certificate from PEM
157var cert = pki.certificateFromPem(pem);
158
159// convert an ASN.1 X.509x3 object to a Forge certificate
160var cert = pki.certificateFromAsn1(obj);
161
162// convert a Forge certificate to an ASN.1 X.509v3 object
163var asn1Cert = pki.certificateToAsn1(cert);
PKCS#5
Provides the password-based key-derivation function from PKCS#5.
Examples
1// generate a password-based 16-byte key 2// note an optional message digest can be passed as the final parameter 3var salt = forge.random.getBytesSync(128); 4var derivedKey = forge.pkcs5.pbkdf2('password', salt, numIterations, 16); 5 6// generate key asynchronously 7// note an optional message digest can be passed before the callback 8forge.pkcs5.pbkdf2('password', salt, numIterations, 16, function(err, derivedKey) { 9 // do something w/derivedKey 10});
PKCS#7
Provides cryptographically protected messages from PKCS#7.
Examples
1// convert a message from PEM
2var p7 = forge.pkcs7.messageFromPem(pem);
3// look at p7.recipients
4
5// find a recipient by the issuer of a certificate
6var recipient = p7.findRecipient(cert);
7
8// decrypt
9p7.decrypt(p7.recipients[0], privateKey);
10
11// create a p7 enveloped message
12var p7 = forge.pkcs7.createEnvelopedData();
13
14// add a recipient
15var cert = forge.pki.certificateFromPem(certPem);
16p7.addRecipient(cert);
17
18// set content
19p7.content = forge.util.createBuffer('Hello');
20
21// encrypt
22p7.encrypt();
23
24// convert message to PEM
25var pem = forge.pkcs7.messageToPem(p7);
26
27// create a degenerate PKCS#7 certificate container
28// (CRLs not currently supported, only certificates)
29var p7 = forge.pkcs7.createSignedData();
30p7.addCertificate(certOrCertPem1);
31p7.addCertificate(certOrCertPem2);
32var pem = forge.pkcs7.messageToPem(p7);
33
34// create PKCS#7 signed data with authenticatedAttributes
35// attributes include: PKCS#9 content-type, message-digest, and signing-time
36var p7 = forge.pkcs7.createSignedData();
37p7.content = forge.util.createBuffer('Some content to be signed.', 'utf8');
38p7.addCertificate(certOrCertPem);
39p7.addSigner({
40 key: privateKeyAssociatedWithCert,
41 certificate: certOrCertPem,
42 digestAlgorithm: forge.pki.oids.sha256,
43 authenticatedAttributes: [{
44 type: forge.pki.oids.contentType,
45 value: forge.pki.oids.data
46 }, {
47 type: forge.pki.oids.messageDigest
48 // value will be auto-populated at signing time
49 }, {
50 type: forge.pki.oids.signingTime,
51 // value can also be auto-populated at signing time
52 value: new Date()
53 }]
54});
55p7.sign();
56var pem = forge.pkcs7.messageToPem(p7);
57
58// PKCS#7 Sign in detached mode.
59// Includes the signature and certificate without the signed data.
60p7.sign({detached: true});
61
PKCS#8
Examples
1var pki = forge.pki;
2
3// convert a PEM-formatted private key to a Forge private key
4var privateKey = pki.privateKeyFromPem(pem);
5
6// convert a Forge private key to PEM-format
7var pem = pki.privateKeyToPem(privateKey);
8
9// convert an ASN.1 PrivateKeyInfo or RSAPrivateKey to a Forge private key
10var privateKey = pki.privateKeyFromAsn1(rsaPrivateKey);
11
12// convert a Forge private key to an ASN.1 RSAPrivateKey
13var rsaPrivateKey = pki.privateKeyToAsn1(privateKey);
14
15// wrap an RSAPrivateKey ASN.1 object in a PKCS#8 ASN.1 PrivateKeyInfo
16var privateKeyInfo = pki.wrapRsaPrivateKey(rsaPrivateKey);
17
18// convert a PKCS#8 ASN.1 PrivateKeyInfo to PEM
19var pem = pki.privateKeyInfoToPem(privateKeyInfo);
20
21// encrypts a PrivateKeyInfo using a custom password and
22// outputs an EncryptedPrivateKeyInfo
23var encryptedPrivateKeyInfo = pki.encryptPrivateKeyInfo(
24 privateKeyInfo, 'myCustomPasswordHere', {
25 algorithm: 'aes256', // 'aes128', 'aes192', 'aes256', '3des'
26 });
27
28// decrypts an ASN.1 EncryptedPrivateKeyInfo that was encrypted
29// with a custom password
30var privateKeyInfo = pki.decryptPrivateKeyInfo(
31 encryptedPrivateKeyInfo, 'myCustomPasswordHere');
32
33// converts an EncryptedPrivateKeyInfo to PEM
34var pem = pki.encryptedPrivateKeyToPem(encryptedPrivateKeyInfo);
35
36// converts a PEM-encoded EncryptedPrivateKeyInfo to ASN.1 format
37var encryptedPrivateKeyInfo = pki.encryptedPrivateKeyFromPem(pem);
38
39// wraps and encrypts a Forge private key and outputs it in PEM format
40var pem = pki.encryptRsaPrivateKey(privateKey, 'password');
41
42// encrypts a Forge private key and outputs it in PEM format using OpenSSL's
43// proprietary legacy format + encapsulated PEM headers (DEK-Info)
44var pem = pki.encryptRsaPrivateKey(privateKey, 'password', {legacy: true});
45
46// decrypts a PEM-formatted, encrypted private key
47var privateKey = pki.decryptRsaPrivateKey(pem, 'password');
48
49// sets an RSA public key from a private key
50var publicKey = pki.setRsaPublicKey(privateKey.n, privateKey.e);
PKCS#10
Provides certification requests or certificate signing requests (CSR) from PKCS#10.
Examples
1// generate a key pair
2var keys = forge.pki.rsa.generateKeyPair(2048);
3
4// create a certification request (CSR)
5var csr = forge.pki.createCertificationRequest();
6csr.publicKey = keys.publicKey;
7csr.setSubject([{
8 name: 'commonName',
9 value: 'example.org'
10}, {
11 name: 'countryName',
12 value: 'US'
13}, {
14 shortName: 'ST',
15 value: 'Virginia'
16}, {
17 name: 'localityName',
18 value: 'Blacksburg'
19}, {
20 name: 'organizationName',
21 value: 'Test'
22}, {
23 shortName: 'OU',
24 value: 'Test'
25}]);
26// set (optional) attributes
27csr.setAttributes([{
28 name: 'challengePassword',
29 value: 'password'
30}, {
31 name: 'unstructuredName',
32 value: 'My Company, Inc.'
33}, {
34 name: 'extensionRequest',
35 extensions: [{
36 name: 'subjectAltName',
37 altNames: [{
38 // 2 is DNS type
39 type: 2,
40 value: 'test.domain.com'
41 }, {
42 type: 2,
43 value: 'other.domain.com',
44 }, {
45 type: 2,
46 value: 'www.domain.net'
47 }]
48 }]
49}]);
50
51// sign certification request
52csr.sign(keys.privateKey);
53
54// verify certification request
55var verified = csr.verify();
56
57// convert certification request to PEM-format
58var pem = forge.pki.certificationRequestToPem(csr);
59
60// convert a Forge certification request from PEM-format
61var csr = forge.pki.certificationRequestFromPem(pem);
62
63// get an attribute
64csr.getAttribute({name: 'challengePassword'});
65
66// get extensions array
67csr.getAttribute({name: 'extensionRequest'}).extensions;
68
PKCS#12
Provides the cryptographic archive file format from PKCS#12.
Note for Chrome/Firefox/iOS/similar users: If you have trouble importing
a PKCS#12 container, try using the TripleDES algorithm. It can be passed
to forge.pkcs12.toPkcs12Asn1
using the {algorithm: '3des'}
option.
Examples
1// decode p12 from base64 2var p12Der = forge.util.decode64(p12b64); 3// get p12 as ASN.1 object 4var p12Asn1 = forge.asn1.fromDer(p12Der); 5// decrypt p12 using the password 'password' 6var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, 'password'); 7// decrypt p12 using non-strict parsing mode (resolves some ASN.1 parse errors) 8var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, false, 'password'); 9// decrypt p12 using literally no password (eg: Mac OS X/apple push) 10var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1); 11// decrypt p12 using an "empty" password (eg: OpenSSL with no password input) 12var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, ''); 13// p12.safeContents is an array of safe contents, each of 14// which contains an array of safeBags 15 16// get bags by friendlyName 17var bags = p12.getBags({friendlyName: 'test'}); 18// bags are key'd by attribute type (here "friendlyName") 19// and the key values are an array of matching objects 20var cert = bags.friendlyName[0]; 21 22// get bags by localKeyId 23var bags = p12.getBags({localKeyId: buffer}); 24// bags are key'd by attribute type (here "localKeyId") 25// and the key values are an array of matching objects 26var cert = bags.localKeyId[0]; 27 28// get bags by localKeyId (input in hex) 29var bags = p12.getBags({localKeyIdHex: '7b59377ff142d0be4565e9ac3d396c01401cd879'}); 30// bags are key'd by attribute type (here "localKeyId", *not* "localKeyIdHex") 31// and the key values are an array of matching objects 32var cert = bags.localKeyId[0]; 33 34// get bags by type 35var bags = p12.getBags({bagType: forge.pki.oids.certBag}); 36// bags are key'd by bagType and each bagType key's value 37// is an array of matches (in this case, certificate objects) 38var cert = bags[forge.pki.oids.certBag][0]; 39 40// get bags by friendlyName and filter on bag type 41var bags = p12.getBags({ 42 friendlyName: 'test', 43 bagType: forge.pki.oids.certBag 44}); 45 46// get key bags 47var bags = p12.getBags({bagType: forge.pki.oids.keyBag}); 48// get key 49var bag = bags[forge.pki.oids.keyBag][0]; 50var key = bag.key; 51// if the key is in a format unrecognized by forge then 52// bag.key will be `null`, use bag.asn1 to get the ASN.1 53// representation of the key 54if(bag.key === null) { 55 var keyAsn1 = bag.asn1; 56 // can now convert back to DER/PEM/etc for export 57} 58 59// generate a p12 using AES (default) 60var p12Asn1 = forge.pkcs12.toPkcs12Asn1( 61 privateKey, certificateChain, 'password'); 62 63// generate a p12 that can be imported by Chrome/Firefox/iOS 64// (requires the use of Triple DES instead of AES) 65var p12Asn1 = forge.pkcs12.toPkcs12Asn1( 66 privateKey, certificateChain, 'password', 67 {algorithm: '3des'}); 68 69// base64-encode p12 70var p12Der = forge.asn1.toDer(p12Asn1).getBytes(); 71var p12b64 = forge.util.encode64(p12Der); 72 73// create download link for p12 74var a = document.createElement('a'); 75a.download = 'example.p12'; 76a.setAttribute('href', 'data:application/x-pkcs12;base64,' + p12b64); 77a.appendChild(document.createTextNode('Download'));
ASN.1
Provides ASN.1 DER encoding and decoding.
Examples
1var asn1 = forge.asn1; 2 3// create a SubjectPublicKeyInfo 4var subjectPublicKeyInfo = 5 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ 6 // AlgorithmIdentifier 7 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ 8 // algorithm 9 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, 10 asn1.oidToDer(pki.oids['rsaEncryption']).getBytes()), 11 // parameters (null) 12 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') 13 ]), 14 // subjectPublicKey 15 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, [ 16 // RSAPublicKey 17 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ 18 // modulus (n) 19 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, 20 _bnToBytes(key.n)), 21 // publicExponent (e) 22 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, 23 _bnToBytes(key.e)) 24 ]) 25 ]) 26 ]); 27 28// serialize an ASN.1 object to DER format 29var derBuffer = asn1.toDer(subjectPublicKeyInfo); 30 31// deserialize to an ASN.1 object from a byte buffer filled with DER data 32var object = asn1.fromDer(derBuffer); 33 34// convert an OID dot-separated string to a byte buffer 35var derOidBuffer = asn1.oidToDer('1.2.840.113549.1.1.5'); 36 37// convert a byte buffer with a DER-encoded OID to a dot-separated string 38console.log(asn1.derToOid(derOidBuffer)); 39// output: 1.2.840.113549.1.1.5 40 41// validates that an ASN.1 object matches a particular ASN.1 structure and 42// captures data of interest from that structure for easy access 43var publicKeyValidator = { 44 name: 'SubjectPublicKeyInfo', 45 tagClass: asn1.Class.UNIVERSAL, 46 type: asn1.Type.SEQUENCE, 47 constructed: true, 48 captureAsn1: 'subjectPublicKeyInfo', 49 value: [{ 50 name: 'SubjectPublicKeyInfo.AlgorithmIdentifier', 51 tagClass: asn1.Class.UNIVERSAL, 52 type: asn1.Type.SEQUENCE, 53 constructed: true, 54 value: [{ 55 name: 'AlgorithmIdentifier.algorithm', 56 tagClass: asn1.Class.UNIVERSAL, 57 type: asn1.Type.OID, 58 constructed: false, 59 capture: 'publicKeyOid' 60 }] 61 }, { 62 // subjectPublicKey 63 name: 'SubjectPublicKeyInfo.subjectPublicKey', 64 tagClass: asn1.Class.UNIVERSAL, 65 type: asn1.Type.BITSTRING, 66 constructed: false, 67 value: [{ 68 // RSAPublicKey 69 name: 'SubjectPublicKeyInfo.subjectPublicKey.RSAPublicKey', 70 tagClass: asn1.Class.UNIVERSAL, 71 type: asn1.Type.SEQUENCE, 72 constructed: true, 73 optional: true, 74 captureAsn1: 'rsaPublicKey' 75 }] 76 }] 77}; 78 79var capture = {}; 80var errors = []; 81if(!asn1.validate( 82 publicKeyValidator, subjectPublicKeyInfo, validator, capture, errors)) { 83 throw 'ASN.1 object is not a SubjectPublicKeyInfo.'; 84} 85// capture.subjectPublicKeyInfo contains the full ASN.1 object 86// capture.rsaPublicKey contains the full ASN.1 object for the RSA public key 87// capture.publicKeyOid only contains the value for the OID 88var oid = asn1.derToOid(capture.publicKeyOid); 89if(oid !== pki.oids['rsaEncryption']) { 90 throw 'Unsupported OID.'; 91} 92 93// pretty print an ASN.1 object to a string for debugging purposes 94asn1.prettyPrint(object);
Message Digests
SHA1
Provides SHA-1 message digests.
Examples
1var md = forge.md.sha1.create(); 2md.update('The quick brown fox jumps over the lazy dog'); 3console.log(md.digest().toHex()); 4// output: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
SHA256
Provides SHA-256 message digests.
Examples
1var md = forge.md.sha256.create(); 2md.update('The quick brown fox jumps over the lazy dog'); 3console.log(md.digest().toHex()); 4// output: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592
SHA384
Provides SHA-384 message digests.
Examples
1var md = forge.md.sha384.create(); 2md.update('The quick brown fox jumps over the lazy dog'); 3console.log(md.digest().toHex()); 4// output: ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1
SHA512
Provides SHA-512 message digests.
Examples
1// SHA-512 2var md = forge.md.sha512.create(); 3md.update('The quick brown fox jumps over the lazy dog'); 4console.log(md.digest().toHex()); 5// output: 07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6 6 7// SHA-512/224 8var md = forge.md.sha512.sha224.create(); 9md.update('The quick brown fox jumps over the lazy dog'); 10console.log(md.digest().toHex()); 11// output: 944cd2847fb54558d4775db0485a50003111c8e5daa63fe722c6aa37 12 13// SHA-512/256 14var md = forge.md.sha512.sha256.create(); 15md.update('The quick brown fox jumps over the lazy dog'); 16console.log(md.digest().toHex()); 17// output: dd9d67b371519c339ed8dbd25af90e976a1eeefd4ad3d889005e532fc5bef04d
MD5
Examples
1var md = forge.md.md5.create(); 2md.update('The quick brown fox jumps over the lazy dog'); 3console.log(md.digest().toHex()); 4// output: 9e107d9d372bb6826bd81d3542a419d6
HMAC
Provides HMAC w/any supported message digest algorithm.
Examples
1var hmac = forge.hmac.create(); 2hmac.start('sha1', 'Jefe'); 3hmac.update('what do ya want for nothing?'); 4console.log(hmac.digest().toHex()); 5// output: effcdf6ae5eb2fa2d27416d5f184df9c259a7c79
Utilities
Prime
Provides an API for generating large, random, probable primes.
Examples
1// generate a random prime on the main JS thread
2var bits = 1024;
3forge.prime.generateProbablePrime(bits, function(err, num) {
4 console.log('random prime', num.toString(16));
5});
6
7// generate a random prime using Web Workers (if available, otherwise
8// falls back to the main thread)
9var bits = 1024;
10var options = {
11 algorithm: {
12 name: 'PRIMEINC',
13 workers: -1 // auto-optimize # of workers
14 }
15};
16forge.prime.generateProbablePrime(bits, options, function(err, num) {
17 console.log('random prime', num.toString(16));
18});
PRNG
Provides a Fortuna-based cryptographically-secure pseudo-random number generator, to be used with a cryptographic function backend, e.g. AES. An implementation using AES as a backend is provided. An API for collecting entropy is given, though if window.crypto.getRandomValues is available, it will be used automatically.
Examples
1// get some random bytes synchronously 2var bytes = forge.random.getBytesSync(32); 3console.log(forge.util.bytesToHex(bytes)); 4 5// get some random bytes asynchronously 6forge.random.getBytes(32, function(err, bytes) { 7 console.log(forge.util.bytesToHex(bytes)); 8}); 9 10// collect some entropy if you'd like 11forge.random.collect(someRandomBytes); 12jQuery().mousemove(function(e) { 13 forge.random.collectInt(e.clientX, 16); 14 forge.random.collectInt(e.clientY, 16); 15}); 16 17// specify a seed file for use with the synchronous API if you'd like 18forge.random.seedFileSync = function(needed) { 19 // get 'needed' number of random bytes from somewhere 20 return fetchedRandomBytes; 21}; 22 23// specify a seed file for use with the asynchronous API if you'd like 24forge.random.seedFile = function(needed, callback) { 25 // get the 'needed' number of random bytes from somewhere 26 callback(null, fetchedRandomBytes); 27}); 28 29// register the main thread to send entropy or a Web Worker to receive 30// entropy on demand from the main thread 31forge.random.registerWorker(self); 32 33// generate a new instance of a PRNG with no collected entropy 34var myPrng = forge.random.createInstance();
Tasks
Provides queuing and synchronizing tasks in a web application.
Examples
1// TODO
Utilities
Provides utility functions, including byte buffer support, base64, bytes to/from hex, zlib inflate/deflate, etc.
Examples
1// encode/decode base64 2var encoded = forge.util.encode64(str); 3var str = forge.util.decode64(encoded); 4 5// encode/decode UTF-8 6var encoded = forge.util.encodeUtf8(str); 7var str = forge.util.decodeUtf8(encoded); 8 9// bytes to/from hex 10var bytes = forge.util.hexToBytes(hex); 11var hex = forge.util.bytesToHex(bytes); 12 13// create an empty byte buffer 14var buffer = forge.util.createBuffer(); 15// create a byte buffer from raw binary bytes 16var buffer = forge.util.createBuffer(input, 'raw'); 17// create a byte buffer from utf8 bytes 18var buffer = forge.util.createBuffer(input, 'utf8'); 19 20// get the length of the buffer in bytes 21buffer.length(); 22// put bytes into the buffer 23buffer.putBytes(bytes); 24// put a 32-bit integer into the buffer 25buffer.putInt32(10); 26// buffer to hex 27buffer.toHex(); 28// get a copy of the bytes in the buffer 29bytes.bytes(/* count */); 30// empty this buffer and get its contents 31bytes.getBytes(/* count */); 32 33// convert a forge buffer into a Node.js Buffer 34// make sure you specify the encoding as 'binary' 35var forgeBuffer = forge.util.createBuffer(); 36var nodeBuffer = Buffer.from(forgeBuffer.getBytes(), 'binary'); 37 38// convert a Node.js Buffer into a forge buffer 39// make sure you specify the encoding as 'binary' 40var nodeBuffer = Buffer.from('CAFE', 'hex'); 41var forgeBuffer = forge.util.createBuffer(nodeBuffer.toString('binary'));
Logging
Provides logging to a javascript console using various categories and levels of verbosity.
Examples
1// TODO
Flash Networking Support
The flash README provides details on rebuilding the optional Flash component used for networking. It also provides details on Policy Server support.
Security Considerations
When using this code please keep the following in mind:
- Cryptography is hard. Please review and test this code before depending on it for critical functionality.
- The nature of JavaScript is that execution of this code depends on trusting a very large set of JavaScript tools and systems. Consider runtime variations, runtime characteristics, runtime optimization, code optimization, code minimization, code obfuscation, bundling tools, possible bugs, the Forge code itself, and so on.
- If using pre-built bundles from NPM, another CDN, or similar, be aware someone else ran the tools to create those files.
- Use a secure transport channel such as TLS to load scripts and consider using additional security mechanisms such as Subresource Integrity script attributes.
- Use "native" functionality where possible. This can be critical when dealing with performance and random number generation. Note that the JavaScript random number algorithms should perform well if given suitable entropy.
- Understand possible attacks against cryptographic systems. For instance side channel and timing attacks may be possible due to the difficulty in implementing constant time algorithms in pure JavaScript.
- Certain features in this library are less susceptible to attacks depending on usage. This primarily includes features that deal with data format manipulation or those that are not involved in communication.
Library Background
- https://digitalbazaar.com/2010/07/20/javascript-tls-1/
- https://digitalbazaar.com/2010/07/20/javascript-tls-2/
Contact
- Code: https://github.com/digitalbazaar/forge
- Bugs: https://github.com/digitalbazaar/forge/issues
- Email: support@digitalbazaar.com
- IRC: #forgejs on Libera.Chat (people may also be on freenode for historical reasons).
Donations
Financial support is welcome and helps contribute to futher development:
- For PayPal please send to paypal@digitalbazaar.com.
- Something else? Please contact support@digitalbazaar.com.
Stable Version
The latest stable version of the package.
Stable Version
1.3.1
HIGH
3
8.8/10
Summary
Prototype Pollution in node-forge
Affected Versions
< 0.10.0
Patched Versions
0.10.0
7.5/10
Summary
Improper Verification of Cryptographic Signature in node-forge
Affected Versions
< 1.3.0
Patched Versions
1.3.0
7.5/10
Summary
Improper Verification of Cryptographic Signature in node-forge
Affected Versions
< 1.3.0
Patched Versions
1.3.0
MODERATE
2
6.1/10
Summary
Open Redirect in node-forge
Affected Versions
< 1.0.0
Patched Versions
1.0.0
5.3/10
Summary
Improper Verification of Cryptographic Signature in `node-forge`
Affected Versions
< 1.3.0
Patched Versions
1.3.0
LOW
3
0/10
Summary
Prototype Pollution in node-forge debug API.
Affected Versions
< 1.0.0
Patched Versions
1.0.0
0/10
Summary
Prototype Pollution in node-forge util.setPath API
Affected Versions
< 0.10.0
Patched Versions
0.10.0
0/10
Summary
URL parsing in node-forge could lead to undesired behavior.
Affected Versions
< 1.0.0
Patched Versions
1.0.0
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
0 existing vulnerabilities detected
Reason
security policy file detected
Details
- Info: security policy file detected: SECURITY.md:1
- Info: Found linked content: SECURITY.md:1
- Warn: One or no descriptive hints of disclosure, vulnerability, and/or timelines in security policy
- Info: Found text in security policy: SECURITY.md:1
Reason
license file detected
Details
- Info: project has a license file: LICENSE:0
- Warn: project license file does not contain an FSF or OSI license.
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
Found 1/24 approved changesets -- score normalized to 0
Reason
detected GitHub workflow tokens with excessive permissions
Details
- Warn: no topLevel permission defined: .github/workflows/main.yml:1
- Info: no jobLevel write permissions found
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/digitalbazaar/forge/main.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/digitalbazaar/forge/main.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/digitalbazaar/forge/main.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:31: update your workflow using https://app.stepsecurity.io/secureworkflow/digitalbazaar/forge/main.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:61: update your workflow using https://app.stepsecurity.io/secureworkflow/digitalbazaar/forge/main.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:63: update your workflow using https://app.stepsecurity.io/secureworkflow/digitalbazaar/forge/main.yml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/main.yml:70: update your workflow using https://app.stepsecurity.io/secureworkflow/digitalbazaar/forge/main.yml/main?enable=pin
- Warn: npmCommand not pinned by hash: .github/workflows/main.yml:19
- Warn: npmCommand not pinned by hash: .github/workflows/main.yml:35
- Warn: npmCommand not pinned by hash: .github/workflows/main.yml:67
- Info: 0 out of 6 GitHub-owned GitHubAction dependencies pinned
- Info: 0 out of 1 third-party GitHubAction dependencies pinned
- Info: 0 out of 3 npmCommand dependencies pinned
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 10 are checked with a SAST tool
Score
4.4
/10
Last Scanned on 2024-11-25
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More