digitalbazaar/forge

Name: forge

Owner: Digital Bazaar, Inc.

Description: A native implementation of TLS in Javascript and tools to write crypto-based and network-heavy webapps

Created: 2010-07-16 20:49:48.0

Updated: 2018-01-15 14:11:39.0

Pushed: 2017-11-11 01:08:19.0

Homepage: http://digitalbazaar.com/

Size: 4439

Language: JavaScript

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

Forge

npm package

Build status

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:

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://npmjs.org/package/node-forge

Installation:

npm install node-forge

You can then use forge as a regular module:

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.

Bundle / Bower

Each release is published in a separate repository as pre-built and minimized basic forge bundles using the UMD format.

https://github.com/digitalbazaar/forge-dist

This bundle can be used in many environments. In particular it can be installed with Bower:

bower install forge
jsDelivr CDN

To use it via jsDelivr include this in your html:

ipt src="https://cdn.jsdelivr.net/npm/node-forge@0.7.0/dist/forge.min.js"></script>
unpkg CDN

To use it via unpkg include this in your html:

ipt src="https://unpkg.com/node-forge@0.7.0/dist/forge.min.js"></script>
Development Requirements

The core JavaScript has the following requirements to build and test:

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:

ipt src="YOUR_SCRIPT_PATH/forge.js"></script>

or

ipt 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

See the testing README for full details.

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 PhantomJS

Automated testing is done via Karma. By default it will run the tests in a headless manner with PhantomJS.

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,PhantomJS

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.usePureJavaScriptflag 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:

un this *after* including the forge script
e.options.usePureJavaScript = true;

To disable native code when using Node.js:

forge = require('node-forge');
e.options.usePureJavaScript = true;
Transports

TLS

Provides a native javascript client and server-side TLS implementation.

Examples

reate TLS client
client = forge.tls.createConnection({
rver: false,
Store: /* Array of PEM-formatted certs or a CA store object */,
ssionCache: {},
 supported cipher suites in order of preference
pherSuites: [
forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA,
forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA],
rtualHost: 'example.com',
rify: function(connection, verified, depth, certs) {
if(depth === 0) {
  var cn = certs[0].subject.getField('CN').value;
  if(cn !== 'example.com') {
    verified = {
      alert: forge.tls.Alert.Description.bad_certificate,
      message: 'Certificate common name does not match hostname.'
    };
  }
}
return verified;

nnected: function(connection) {
console.log('connected');
// send message to server
connection.prepare(forge.util.encodeUtf8('Hi server!'));
/* NOTE: experimental, start heartbeat retransmission timer
myHeartbeatTimer = setInterval(function() {
  connection.prepareHeartbeatRequest(forge.util.createBuffer('1234'));
}, 5*60*1000);*/

 provide a client-side cert if you want
tCertificate: function(connection, hint) {
return myClientCertificate;

 the private key for the client-side cert if provided */
tPrivateKey: function(connection, cert) {
return myClientPrivateKey;

sDataReady: function(connection) {
// TLS data (encrypted) is ready to be sent to the server
sendToServerSomehow(connection.tlsData.getBytes());
// if you were communicating with the server below, you'd do:
// server.process(connection.tlsData.getBytes());

taReady: function(connection) {
// clear data from the server is ready
console.log('the server sent: ' +
  forge.util.decodeUtf8(connection.data.getBytes()));
// close connection
connection.close();

 NOTE: experimental
artbeatReceived: function(connection, payload) {
// restart retransmission timer, look at payload
clearInterval(myHeartbeatTimer);
myHeartbeatTimer = setInterval(function() {
  connection.prepareHeartbeatRequest(forge.util.createBuffer('1234'));
}, 5*60*1000);
payload.getBytes();
*/
osed: function(connection) {
console.log('disconnected');

ror: function(connection, error) {
console.log('uh oh', error);



tart the handshake process
nt.handshake();

hen encrypted TLS data is received from the server, process it
nt.process(encryptedBytesFromServer);

reate TLS server
server = forge.tls.createConnection({
rver: true,
Store: /* Array of PEM-formatted certs or a CA store object */,
ssionCache: {},
 supported cipher suites in order of preference
pherSuites: [
forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA,
forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA],
 require a client-side certificate if you want
rifyClient: true,
rify: function(connection, verified, depth, certs) {
if(depth === 0) {
  var cn = certs[0].subject.getField('CN').value;
  if(cn !== 'the-client') {
    verified = {
      alert: forge.tls.Alert.Description.bad_certificate,
      message: 'Certificate common name does not match expected client.'
    };
  }
}
return verified;

nnected: function(connection) {
console.log('connected');
// send message to client
connection.prepare(forge.util.encodeUtf8('Hi client!'));
/* NOTE: experimental, start heartbeat retransmission timer
myHeartbeatTimer = setInterval(function() {
  connection.prepareHeartbeatRequest(forge.util.createBuffer('1234'));
}, 5*60*1000);*/

tCertificate: function(connection, hint) {
return myServerCertificate;

tPrivateKey: function(connection, cert) {
return myServerPrivateKey;

sDataReady: function(connection) {
// TLS data (encrypted) is ready to be sent to the client
sendToClientSomehow(connection.tlsData.getBytes());
// if you were communicating with the client above you'd do:
// client.process(connection.tlsData.getBytes());

taReady: function(connection) {
// clear data from the client is ready
console.log('the client sent: ' +
  forge.util.decodeUtf8(connection.data.getBytes()));
// close connection
connection.close();

 NOTE: experimental
artbeatReceived: function(connection, payload) {
// restart retransmission timer, look at payload
clearInterval(myHeartbeatTimer);
myHeartbeatTimer = setInterval(function() {
  connection.prepareHeartbeatRequest(forge.util.createBuffer('1234'));
}, 5*60*1000);
payload.getBytes();
*/
osed: function(connection) {
console.log('disconnected');

ror: function(connection, error) {
console.log('uh oh', error);



hen encrypted TLS data is received from the client, process it
er.process(encryptedBytesFromClient);

Connect to a TLS server using node's net.Socket:

socket = new net.Socket();

client = forge.tls.createConnection({
rver: false,
rify: function(connection, verified, depth, certs) {
// skip verification for testing
console.log('[tls] server certificate verified');
return true;

nnected: function(connection) {
console.log('[tls] connected');
// prepare some data to send (note that the string is interpreted as
// 'binary' encoded, which works for HTTP which only uses ASCII, use
// forge.util.encodeUtf8(str) otherwise
client.prepare('GET / HTTP/1.0\r\n\r\n');

sDataReady: function(connection) {
// encrypted data is ready to be sent to the server
var data = connection.tlsData.getBytes();
socket.write(data, 'binary'); // encoding should be 'binary'

taReady: function(connection) {
// clear data from the server is ready
var data = connection.data.getBytes();
console.log('[tls] data received from the server: ' + data);

osed: function() {
console.log('[tls] disconnected');

ror: function(connection, error) {
console.log('[tls] error', error);



et.on('connect', function() {
nsole.log('[socket] connected');
ient.handshake();

et.on('data', function(data) {
ient.process(data.toString('binary')); // encoding should be 'binary'

et.on('end', function() {
nsole.log('[socket] disconnected');


onnect to google.com
et.connect(443, 'google.com');

r connect to gmail's imap server (but don't send the HTTP header above)
cket.connect(993, 'imap.gmail.com');

HTTP

Provides a native JavaScript mini-implementation of an http client that uses pooled sockets.

Examples

reate an HTTP GET request
request = forge.http.createRequest({method: 'GET', path: url.path});

end the request somewhere
Somehow(request.toString());

eceive response
buffer = forge.util.createBuffer();
response = forge.http.createResponse();
someAsyncDataHandler = function(bytes) {
(!response.bodyReceived) {
buffer.putBytes(bytes);
if(!response.headerReceived) {
  if(response.readHeader(buffer)) {
    console.log('HTTP response header: ' + response.toString());
  }
}
if(response.headerReceived && !response.bodyReceived) {
  if(response.readBody(buffer)) {
    console.log('HTTP response body: ' + response.body);
  }
}


SSH

Provides some SSH utility functions.

Examples

ncodes (and optionally encrypts) a private RSA key as a Putty PPK file
e.ssh.privateKeyToPutty(privateKey, passphrase, comment);

ncodes a public RSA key as an OpenSSH file
e.ssh.publicKeyToOpenSSH(key, comment);

ncodes a private RSA key as an OpenSSH file
e.ssh.privateKeyToOpenSSH(privateKey, passphrase);

ets the SSH public key fingerprint in a byte buffer
e.ssh.getPublicKeyFingerprint(key);

ets a hex-encoded, colon-delimited SSH public key fingerprint
e.ssh.getPublicKeyFingerprint(key, {encoding: 'hex', delimiter: ':'});

XHR

Provides an XmlHttpRequest implementation using forge.http as a backend.

Examples

ODO

Sockets

Provides an interface to create and use raw sockets provided via Flash.

Examples

ODO
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:

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

enerate a random key and IV
ote: a key size of 16 bytes will use AES-128, 24 => AES-192, 32 => AES-256
key = forge.random.getBytesSync(16);
iv = forge.random.getBytesSync(16);

lternatively, generate a password-based 16-byte key
salt = forge.random.getBytesSync(128);
key = forge.pkcs5.pbkdf2('password', salt, numIterations, 16);


ncrypt some bytes using CBC mode
other modes include: ECB, CFB, OFB, CTR, and GCM)
ote: CBC and ECB modes use PKCS#7 padding as default
cipher = forge.cipher.createCipher('AES-CBC', key);
er.start({iv: iv});
er.update(forge.util.createBuffer(someBytes));
er.finish();
encrypted = cipher.output;
utputs encrypted hex
ole.log(encrypted.toHex());

ecrypt some bytes using CBC mode
other modes include: CFB, OFB, CTR, and GCM)
decipher = forge.cipher.createDecipher('AES-CBC', key);
pher.start({iv: iv});
pher.update(encrypted);
result = decipher.finish(); // check 'result' for true/false
utputs decrypted hex
ole.log(decipher.output.toHex());

ecrypt bytes using CBC mode and streaming
erformance can suffer for large multi-MB inputs due to buffer
anipulations. Stream processing in chunks can offer significant
mprovement. CPU intensive update() calls could also be performed with
etImmediate/setTimeout to avoid blocking the main browser UI thread (not
hown here). Optimal block size depends on the JavaScript VM and other
actors. Encryption can use a simple technique for increased performance.
encryptedBytes = encrypted.bytes();
decipher = forge.cipher.createDecipher('AES-CBC', key);
pher.start({iv: iv});
length = encryptedBytes.length;
chunkSize = 1024 * 64;
index = 0;
decrypted = '';

crypted += decipher.output.getBytes();
r buf = forge.util.createBuffer(encryptedBytes.substr(index, chunkSize));
cipher.update(buf);
dex += chunkSize;
ile(index < length);
result = decipher.finish();
rt(result);
ypted += decipher.output.getBytes();
ole.log(forge.util.bytesToHex(decrypted));

ncrypt some bytes using GCM mode
cipher = forge.cipher.createCipher('AES-GCM', key);
er.start({
: iv, // should be a 12-byte binary-encoded string or byte buffer
ditionalData: 'binary-encoded string', // optional
gLength: 128 // optional, defaults to 128 bits

er.update(forge.util.createBuffer(someBytes));
er.finish();
encrypted = cipher.output;
tag = cipher.mode.tag;
utputs encrypted hex
ole.log(encrypted.toHex());
utputs authentication tag
ole.log(tag.toHex());

ecrypt some bytes using GCM mode
decipher = forge.cipher.createDecipher('AES-GCM', key);
pher.start({
: iv,
ditionalData: 'binary-encoded string', // optional
gLength: 128, // optional, defaults to 128 bits
g: tag // authentication tag from encryption

pher.update(encrypted);
pass = decipher.finish();
ass is false if there was a failure (eg: authentication tag didn't match)
ass) {
 outputs decrypted hex
nsole.log(decipher.output.toHex());

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):

forge = require('node-forge');
fs = require('fs');

penssl enc -des3 -in input.txt -out input.enc
tion encrypt(password) {
r input = fs.readFileSync('input.txt', {encoding: 'binary'});

 3DES key and IV sizes
r keySize = 24;
r ivSize = 8;

 get derived bytes
 Notes:
 1. If using an alternative hash (eg: "-md sha1") pass
   "forge.md.sha1.create()" as the final parameter.
 2. If using "-nosalt", set salt to null.
r salt = forge.random.getBytesSync(8);
 var md = forge.md.sha1.create(); // "-md sha1"
r derivedBytes = forge.pbe.opensslDeriveBytes(
password, salt, keySize + ivSize/*, md*/);
r buffer = forge.util.createBuffer(derivedBytes);
r key = buffer.getBytes(keySize);
r iv = buffer.getBytes(ivSize);

r cipher = forge.cipher.createCipher('3DES-CBC', key);
pher.start({iv: iv});
pher.update(forge.util.createBuffer(input, 'binary'));
pher.finish();

r output = forge.util.createBuffer();

 if using a salt, prepend this to the output:
(salt !== null) {
output.putBytes('Salted__'); // (add to match openssl tool output)
output.putBytes(salt);

tput.putBuffer(cipher.output);

.writeFileSync('input.enc', output.getBytes(), {encoding: 'binary'});


penssl enc -d -des3 -in input.enc -out input.dec.txt
tion decrypt(password) {
r input = fs.readFileSync('input.enc', {encoding: 'binary'});

 parse salt from input
put = forge.util.createBuffer(input, 'binary');
 skip "Salted__" (if known to be present)
put.getBytes('Salted__'.length);
 read 8-byte salt
r salt = input.getBytes(8);

 Note: if using "-nosalt", skip above parsing and use
 var salt = null;

 3DES key and IV sizes
r keySize = 24;
r ivSize = 8;

r derivedBytes = forge.pbe.opensslDeriveBytes(
password, salt, keySize + ivSize);
r buffer = forge.util.createBuffer(derivedBytes);
r key = buffer.getBytes(keySize);
r iv = buffer.getBytes(ivSize);

r decipher = forge.cipher.createDecipher('3DES-CBC', key);
cipher.start({iv: iv});
cipher.update(input);
r result = decipher.finish(); // check 'result' for true/false

.writeFileSync(
'input.dec.txt', decipher.output.getBytes(), {encoding: 'binary'});

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

enerate a random key and IV
key = forge.random.getBytesSync(16);
iv = forge.random.getBytesSync(8);

ncrypt some bytes
cipher = forge.rc2.createEncryptionCipher(key);
er.start(iv);
er.update(forge.util.createBuffer(someBytes));
er.finish();
encrypted = cipher.output;
utputs encrypted hex
ole.log(encrypted.toHex());

ecrypt some bytes
cipher = forge.rc2.createDecryptionCipher(key);
er.start(iv);
er.update(encrypted);
er.finish();
utputs decrypted hex
ole.log(cipher.output.toHex());
PKI

Provides X.509 certificate and RSA public and private key encoding, decoding, encryption/decryption, and signing/verifying.

RSA

Examples

rsa = forge.pki.rsa;

enerate an RSA key pair synchronously
NOT RECOMMENDED* -- can be significantly slower than async and will not
se native APIs if available.
keypair = rsa.generateKeyPair({bits: 2048, e: 0x10001});

enerate an RSA key pair asynchronously (uses web workers if available)
se workers: -1 to run a fast core estimator to optimize # of workers
RECOMMENDED* - can be significantly faster than sync -- and will use
ative APIs if available.
generateKeyPair({bits: 2048, workers: 2}, function(err, keypair) {
 keypair.privateKey, keypair.publicKey


enerate an RSA key pair in steps that attempt to run for a specified period
f time on the main JS thread
state = rsa.createKeyPairGenerationState(2048, 0x10001);
step = function() {
 run for 100 ms
(!rsa.stepKeyPairGenerationState(state, 100)) {
setTimeout(step, 1);

se {
// done, turn off progress indicator, use state.keys


urn on progress indicator, schedule generation to run
imeout(step);

ign data with a private key and output DigestInfo DER-encoded bytes
defaults to RSASSA PKCS#1 v1.5)
md = forge.md.sha1.create();
pdate('sign this', 'utf8');
signature = privateKey.sign(md);

erify data with a public key
defaults to RSASSA PKCS#1 v1.5)
verified = publicKey.verify(md.digest().bytes(), signature);

ign data using RSASSA-PSS where PSS uses a SHA-1 hash, a SHA-1 based
asking function MGF1, and a 20 byte salt
md = forge.md.sha1.create();
pdate('sign this', 'utf8');
pss = forge.pss.create({
: forge.md.sha1.create(),
f: forge.mgf.mgf1.create(forge.md.sha1.create()),
ltLength: 20
 optionally pass 'prng' with a custom PRNG implementation
 optionalls pass 'salt' with a forge.util.ByteBuffer w/custom salt

signature = privateKey.sign(md, pss);

erify RSASSA-PSS signature
pss = forge.pss.create({
: forge.md.sha1.create(),
f: forge.mgf.mgf1.create(forge.md.sha1.create()),
ltLength: 20
 optionally pass 'prng' with a custom PRNG implementation

md = forge.md.sha1.create();
pdate('sign this', 'utf8');
icKey.verify(md.digest().getBytes(), signature, pss);

ncrypt data with a public key (defaults to RSAES PKCS#1 v1.5)
encrypted = publicKey.encrypt(bytes);

ecrypt data with a private key (defaults to RSAES PKCS#1 v1.5)
decrypted = privateKey.decrypt(encrypted);

ncrypt data with a public key using RSAES PKCS#1 v1.5
encrypted = publicKey.encrypt(bytes, 'RSAES-PKCS1-V1_5');

ecrypt data with a private key using RSAES PKCS#1 v1.5
decrypted = privateKey.decrypt(encrypted, 'RSAES-PKCS1-V1_5');

ncrypt data with a public key using RSAES-OAEP
encrypted = publicKey.encrypt(bytes, 'RSA-OAEP');

ecrypt data with a private key using RSAES-OAEP
decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP');

ncrypt data with a public key using RSAES-OAEP/SHA-256
encrypted = publicKey.encrypt(bytes, 'RSA-OAEP', {
: forge.md.sha256.create()


ecrypt data with a private key using RSAES-OAEP/SHA-256
decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP', {
: forge.md.sha256.create()


ncrypt data with a public key using RSAES-OAEP/SHA-256/MGF1-SHA-1
ompatible with Java's RSA/ECB/OAEPWithSHA-256AndMGF1Padding
encrypted = publicKey.encrypt(bytes, 'RSA-OAEP', {
: forge.md.sha256.create(),
f1: {
md: forge.md.sha1.create()



ecrypt data with a private key using RSAES-OAEP/SHA-256/MGF1-SHA-1
ompatible with Java's RSA/ECB/OAEPWithSHA-256AndMGF1Padding
decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP', {
: forge.md.sha256.create(),
f1: {
md: forge.md.sha1.create()


RSA-KEM

Examples

enerate an RSA key pair asynchronously (uses web workers if available)
se workers: -1 to run a fast core estimator to optimize # of workers
e.rsa.generateKeyPair({bits: 2048, workers: -1}, function(err, keypair) {
 keypair.privateKey, keypair.publicKey


enerate and encapsulate a 16-byte secret key
kdf1 = new forge.kem.kdf1(forge.md.sha1.create());
kem = forge.kem.rsa.create(kdf1);
result = kem.encrypt(keypair.publicKey, 16);
esult has 'encapsulation' and 'key'

ncrypt some bytes
iv = forge.random.getBytesSync(12);
someBytes = 'hello world!';
cipher = forge.cipher.createCipher('AES-GCM', result.key);
er.start({iv: iv});
er.update(forge.util.createBuffer(someBytes));
er.finish();
encrypted = cipher.output.getBytes();
tag = cipher.mode.tag.getBytes();

end 'encrypted', 'iv', 'tag', and result.encapsulation to recipient

ecrypt encapsulated 16-byte secret key
kdf1 = new forge.kem.kdf1(forge.md.sha1.create());
kem = forge.kem.rsa.create(kdf1);
key = kem.decrypt(keypair.privateKey, result.encapsulation, 16);

ecrypt some bytes
decipher = forge.cipher.createDecipher('AES-GCM', key);
pher.start({iv: iv, tag: tag});
pher.update(forge.util.createBuffer(encrypted));
pass = decipher.finish();
ass is false if there was a failure (eg: authentication tag didn't match)
ass) {
 outputs 'hello world!'
nsole.log(decipher.output.getBytes());

X.509

Examples

pki = forge.pki;

onvert a PEM-formatted public key to a Forge public key
publicKey = pki.publicKeyFromPem(pem);

onvert a Forge public key to PEM-format
pem = pki.publicKeyToPem(publicKey);

onvert an ASN.1 SubjectPublicKeyInfo to a Forge public key
publicKey = pki.publicKeyFromAsn1(subjectPublicKeyInfo);

onvert a Forge public key to an ASN.1 SubjectPublicKeyInfo
subjectPublicKeyInfo = pki.publicKeyToAsn1(publicKey);

ets a SHA-1 RSAPublicKey fingerprint a byte buffer
getPublicKeyFingerprint(key);

ets a SHA-1 SubjectPublicKeyInfo fingerprint a byte buffer
getPublicKeyFingerprint(key, {type: 'SubjectPublicKeyInfo'});

ets a hex-encoded, colon-delimited SHA-1 RSAPublicKey public key fingerprint
getPublicKeyFingerprint(key, {encoding: 'hex', delimiter: ':'});

ets a hex-encoded, colon-delimited SHA-1 SubjectPublicKeyInfo public key fingerprint
getPublicKeyFingerprint(key, {
pe: 'SubjectPublicKeyInfo',
coding: 'hex',
limiter: ':'


ets a hex-encoded, colon-delimited MD5 RSAPublicKey public key fingerprint
getPublicKeyFingerprint(key, {
: forge.md.md5.create(),
coding: 'hex',
limiter: ':'


reates a CA store
caStore = pki.createCaStore([/* PEM-encoded cert */, ...]);

dd a certificate to the CA store
ore.addCertificate(certObjectOrPemString);

ets the issuer (its certificate) for the given certificate
issuerCert = caStore.getIssuer(subjectCert);

erifies a certificate chain against a CA store
verifyCertificateChain(caStore, chain, customVerifyCallback);

igns a certificate using the given private key
.sign(privateKey);

igns a certificate using SHA-256 instead of SHA-1
.sign(privateKey, forge.md.sha256.create());

erifies an issued certificate using the certificates public key
verified = issuer.verify(issued);

enerate a keypair and create an X.509v3 certificate
keys = pki.rsa.generateKeyPair(2048);
cert = pki.createCertificate();
.publicKey = keys.publicKey;
lternatively set public key from a csr
rt.publicKey = csr.publicKey;
OTE: serialNumber is the hex encoded value of an ASN.1 INTEGER.
onforming CAs should ensure serialNumber is:
 no more than 20 octets
 non-negative (prefix a '00' if your value starts with a '1' bit)
.serialNumber = '01';
.validity.notBefore = new Date();
.validity.notAfter = new Date();
.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);
attrs = [{
me: 'commonName',
lue: 'example.org'

me: 'countryName',
lue: 'US'

ortName: 'ST',
lue: 'Virginia'

me: 'localityName',
lue: 'Blacksburg'

me: 'organizationName',
lue: 'Test'

ortName: 'OU',
lue: 'Test'

.setSubject(attrs);
lternatively set subject from a csr
rt.setSubject(csr.subject.attributes);
.setIssuer(attrs);
.setExtensions([{
me: 'basicConstraints',
: true

me: 'keyUsage',
yCertSign: true,
gitalSignature: true,
nRepudiation: true,
yEncipherment: true,
taEncipherment: true

me: 'extKeyUsage',
rverAuth: true,
ientAuth: true,
deSigning: true,
ailProtection: true,
meStamping: true

me: 'nsCertType',
ient: true,
rver: true,
ail: true,
jsign: true,
lCA: true,
ailCA: true,
jCA: true

me: 'subjectAltName',
tNames: [{
type: 6, // URI
value: 'http://example.org/webid#me'
 {
type: 7, // IP
ip: '127.0.0.1'


me: 'subjectKeyIdentifier'

lternatively set extensions from a csr
extensions = csr.getAttribute({name: 'extensionRequest'}).extensions;
ptionally add more extensions
nsions.push.apply(extensions, [{
me: 'basicConstraints',
: true

me: 'keyUsage',
yCertSign: true,
gitalSignature: true,
nRepudiation: true,
yEncipherment: true,
taEncipherment: true

.setExtensions(extensions);

elf-sign certificate
.sign(keys.privateKey);

onvert a Forge certificate to PEM
pem = pki.certificateToPem(cert);

onvert a Forge certificate from PEM
cert = pki.certificateFromPem(pem);

onvert an ASN.1 X.509x3 object to a Forge certificate
cert = pki.certificateFromAsn1(obj);

onvert a Forge certificate to an ASN.1 X.509v3 object
asn1Cert = pki.certificateToAsn1(cert);

PKCS#5

Provides the password-based key-derivation function from PKCS#5.

Examples

enerate a password-based 16-byte key
ote an optional message digest can be passed as the final parameter
salt = forge.random.getBytesSync(128);
derivedKey = forge.pkcs5.pbkdf2('password', salt, numIterations, 16);

enerate key asynchronously
ote an optional message digest can be passed before the callback
e.pkcs5.pbkdf2('password', salt, numIterations, 16, function(err, derivedKey) {
 do something w/derivedKey

PKCS#7

Provides cryptographically protected messages from PKCS#7.

Examples

onvert a message from PEM
p7 = forge.pkcs7.messageFromPem(pem);
ook at p7.recipients

ind a recipient by the issuer of a certificate
recipient = p7.findRecipient(cert);

ecrypt
ecrypt(p7.recipients[0], privateKey);

reate a p7 enveloped message
p7 = forge.pkcs7.createEnvelopedData();

dd a recipient
cert = forge.pki.certificateFromPem(certPem);
ddRecipient(cert);

et content
ontent = forge.util.createBuffer('Hello');

ncrypt
ncrypt();

onvert message to PEM
pem = forge.pkcs7.messageToPem(p7);

reate a degenerate PKCS#7 certificate container
CRLs not currently supported, only certificates)
p7 = forge.pkcs7.createSignedData();
ddCertificate(certOrCertPem1);
ddCertificate(certOrCertPem2);
pem = forge.pkcs7.messageToPem(p7);

reate PKCS#7 signed data with authenticatedAttributes
ttributes include: PKCS#9 content-type, message-digest, and signing-time
p7 = forge.pkcs7.createSignedData();
ontent = forge.util.createBuffer('Some content to be signed.', 'utf8');
ddCertificate(certOrCertPem);
ddSigner({
y: privateKeyAssociatedWithCert,
rtificate: certOrCertPem,
gestAlgorithm: forge.pki.oids.sha256,
thenticatedAttributes: [{
type: forge.pki.oids.contentType,
value: forge.pki.oids.data
 {
type: forge.pki.oids.messageDigest
// value will be auto-populated at signing time
 {
type: forge.pki.oids.signingTime,
// value can also be auto-populated at signing time
value: new Date()


ign();
pem = forge.pkcs7.messageToPem(p7);

PKCS#8

Examples

pki = forge.pki;

onvert a PEM-formatted private key to a Forge private key
privateKey = pki.privateKeyFromPem(pem);

onvert a Forge private key to PEM-format
pem = pki.privateKeyToPem(privateKey);

onvert an ASN.1 PrivateKeyInfo or RSAPrivateKey to a Forge private key
privateKey = pki.privateKeyFromAsn1(rsaPrivateKey);

onvert a Forge private key to an ASN.1 RSAPrivateKey
rsaPrivateKey = pki.privateKeyToAsn1(privateKey);

rap an RSAPrivateKey ASN.1 object in a PKCS#8 ASN.1 PrivateKeyInfo
privateKeyInfo = pki.wrapRsaPrivateKey(rsaPrivateKey);

onvert a PKCS#8 ASN.1 PrivateKeyInfo to PEM
pem = pki.privateKeyInfoToPem(privateKeyInfo);

ncrypts a PrivateKeyInfo and outputs an EncryptedPrivateKeyInfo
encryptedPrivateKeyInfo = pki.encryptPrivateKeyInfo(
ivateKeyInfo, 'password', {
algorithm: 'aes256', // 'aes128', 'aes192', 'aes256', '3des'
;

ecrypts an ASN.1 EncryptedPrivateKeyInfo
privateKeyInfo = pki.decryptPrivateKeyInfo(
cryptedPrivateKeyInfo, 'password');

onverts an EncryptedPrivateKeyInfo to PEM
pem = pki.encryptedPrivateKeyToPem(encryptedPrivateKeyInfo);

onverts a PEM-encoded EncryptedPrivateKeyInfo to ASN.1 format
encryptedPrivateKeyInfo = pki.encryptedPrivateKeyFromPem(pem);

raps and encrypts a Forge private key and outputs it in PEM format
pem = pki.encryptRsaPrivateKey(privateKey, 'password');

ncrypts a Forge private key and outputs it in PEM format using OpenSSL's
roprietary legacy format + encapsulated PEM headers (DEK-Info)
pem = pki.encryptRsaPrivateKey(privateKey, 'password', {legacy: true});

ecrypts a PEM-formatted, encrypted private key
privateKey = pki.decryptRsaPrivateKey(pem, 'password');

ets an RSA public key from a private key
publicKey = pki.setRsaPublicKey(privateKey.n, privateKey.e);

PKCS#10

Provides certification requests or certificate signing requests (CSR) from PKCS#10.

Examples

enerate a key pair
keys = forge.pki.rsa.generateKeyPair(1024);

reate a certification request (CSR)
csr = forge.pki.createCertificationRequest();
publicKey = keys.publicKey;
setSubject([{
me: 'commonName',
lue: 'example.org'

me: 'countryName',
lue: 'US'

ortName: 'ST',
lue: 'Virginia'

me: 'localityName',
lue: 'Blacksburg'

me: 'organizationName',
lue: 'Test'

ortName: 'OU',
lue: 'Test'

et (optional) attributes
setAttributes([{
me: 'challengePassword',
lue: 'password'

me: 'unstructuredName',
lue: 'My Company, Inc.'

me: 'extensionRequest',
tensions: [{
name: 'subjectAltName',
altNames: [{
  // 2 is DNS type
  type: 2,
  value: 'test.domain.com'
}, {
  type: 2,
  value: 'other.domain.com',
}, {
  type: 2,
  value: 'www.domain.net'
}]



ign certification request
sign(keys.privateKey);

erify certification request
verified = csr.verify();

onvert certification request to PEM-format
pem = forge.pki.certificationRequestToPem(csr);

onvert a Forge certification request from PEM-format
csr = forge.pki.certificationRequestFromPem(pem);

et an attribute
getAttribute({name: 'challengePassword'});

et extensions array
getAttribute({name: 'extensionRequest'}).extensions;

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

ecode p12 from base64
p12Der = forge.util.decode64(p12b64);
et p12 as ASN.1 object
p12Asn1 = forge.asn1.fromDer(p12Der);
ecrypt p12 using the password 'password'
p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, 'password');
ecrypt p12 using non-strict parsing mode (resolves some ASN.1 parse errors)
p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, false, 'password');
ecrypt p12 using literally no password (eg: Mac OS X/apple push)
p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1);
ecrypt p12 using an "empty" password (eg: OpenSSL with no password input)
p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, '');
12.safeContents is an array of safe contents, each of
hich contains an array of safeBags

et bags by friendlyName
bags = p12.getBags({friendlyName: 'test'});
ags are key'd by attribute type (here "friendlyName")
nd the key values are an array of matching objects
cert = bags.friendlyName[0];

et bags by localKeyId
bags = p12.getBags({localKeyId: buffer});
ags are key'd by attribute type (here "localKeyId")
nd the key values are an array of matching objects
cert = bags.localKeyId[0];

et bags by localKeyId (input in hex)
bags = p12.getBags({localKeyIdHex: '7b59377ff142d0be4565e9ac3d396c01401cd879'});
ags are key'd by attribute type (here "localKeyId", *not* "localKeyIdHex")
nd the key values are an array of matching objects
cert = bags.localKeyId[0];

et bags by type
bags = p12.getBags({bagType: forge.pki.oids.certBag});
ags are key'd by bagType and each bagType key's value
s an array of matches (in this case, certificate objects)
cert = bags[forge.pki.oids.certBag][0];

et bags by friendlyName and filter on bag type
bags = p12.getBags({
iendlyName: 'test',
gType: forge.pki.oids.certBag


et key bags
bags = p12.getBags({bagType: forge.pki.oids.keyBag});
et key
bag = bags[forge.pki.oids.keyBag][0];
key = bag.key;
f the key is in a format unrecognized by forge then
ag.key will be `null`, use bag.asn1 to get the ASN.1
epresentation of the key
ag.key === null) {
r keyAsn1 = bag.asn1;
 can now convert back to DER/PEM/etc for export


enerate a p12 using AES (default)
p12Asn1 = forge.pkcs12.toPkcs12Asn1(
ivateKey, certificateChain, 'password');

enerate a p12 that can be imported by Chrome/Firefox/iOS
requires the use of Triple DES instead of AES)
p12Asn1 = forge.pkcs12.toPkcs12Asn1(
ivateKey, certificateChain, 'password',
lgorithm: '3des'});

ase64-encode p12
p12Der = forge.asn1.toDer(p12Asn1).getBytes();
p12b64 = forge.util.encode64(p12Der);

reate download link for p12
a = document.createElement('a');
wnload = 'example.p12';
tAttribute('href', 'data:application/x-pkcs12;base64,' + p12b64);
pendChild(document.createTextNode('Download'));

ASN.1

Provides ASN.1 DER encoding and decoding.

Examples

asn1 = forge.asn1;

reate a SubjectPublicKeyInfo
subjectPublicKeyInfo =
n1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
// AlgorithmIdentifier
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
  // algorithm
  asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
    asn1.oidToDer(pki.oids['rsaEncryption']).getBytes()),
  // parameters (null)
  asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')
]),
// subjectPublicKey
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, [
  // RSAPublicKey
  asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
    // modulus (n)
    asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
      _bnToBytes(key.n)),
    // publicExponent (e)
    asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
      _bnToBytes(key.e))
  ])
])
;

erialize an ASN.1 object to DER format
derBuffer = asn1.toDer(subjectPublicKeyInfo);

eserialize to an ASN.1 object from a byte buffer filled with DER data
object = asn1.fromDer(derBuffer);

onvert an OID dot-separated string to a byte buffer
derOidBuffer = asn1.oidToDer('1.2.840.113549.1.1.5');

onvert a byte buffer with a DER-encoded OID to a dot-separated string
ole.log(asn1.derToOid(derOidBuffer));
utput: 1.2.840.113549.1.1.5

alidates that an ASN.1 object matches a particular ASN.1 structure and
aptures data of interest from that structure for easy access
publicKeyValidator = {
me: 'SubjectPublicKeyInfo',
gClass: asn1.Class.UNIVERSAL,
pe: asn1.Type.SEQUENCE,
nstructed: true,
ptureAsn1: 'subjectPublicKeyInfo',
lue: [{
name: 'SubjectPublicKeyInfo.AlgorithmIdentifier',
tagClass: asn1.Class.UNIVERSAL,
type: asn1.Type.SEQUENCE,
constructed: true,
value: [{
  name: 'AlgorithmIdentifier.algorithm',
  tagClass: asn1.Class.UNIVERSAL,
  type: asn1.Type.OID,
  constructed: false,
  capture: 'publicKeyOid'
}]
 {
// subjectPublicKey
name: 'SubjectPublicKeyInfo.subjectPublicKey',
tagClass: asn1.Class.UNIVERSAL,
type: asn1.Type.BITSTRING,
constructed: false,
value: [{
  // RSAPublicKey
  name: 'SubjectPublicKeyInfo.subjectPublicKey.RSAPublicKey',
  tagClass: asn1.Class.UNIVERSAL,
  type: asn1.Type.SEQUENCE,
  constructed: true,
  optional: true,
  captureAsn1: 'rsaPublicKey'
}]



capture = {};
errors = [];
asn1.validate(
blicKeyValidator, subjectPublicKeyInfo, validator, capture, errors)) {
row 'ASN.1 object is not a SubjectPublicKeyInfo.';

apture.subjectPublicKeyInfo contains the full ASN.1 object
apture.rsaPublicKey contains the full ASN.1 object for the RSA public key
apture.publicKeyOid only contains the value for the OID
oid = asn1.derToOid(capture.publicKeyOid);
id !== pki.oids['rsaEncryption']) {
row 'Unsupported OID.';


retty print an ASN.1 object to a string for debugging purposes
.prettyPrint(object);
Message Digests

SHA1

Provides SHA-1 message digests.

Examples

md = forge.md.sha1.create();
pdate('The quick brown fox jumps over the lazy dog');
ole.log(md.digest().toHex());
utput: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12

SHA256

Provides SHA-256 message digests.

Examples

md = forge.md.sha256.create();
pdate('The quick brown fox jumps over the lazy dog');
ole.log(md.digest().toHex());
utput: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592

SHA384

Provides SHA-384 message digests.

Examples

md = forge.md.sha384.create();
pdate('The quick brown fox jumps over the lazy dog');
ole.log(md.digest().toHex());
utput: ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1

SHA512

Provides SHA-512 message digests.

Examples

HA-512
md = forge.md.sha512.create();
pdate('The quick brown fox jumps over the lazy dog');
ole.log(md.digest().toHex());
utput: 07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6

HA-512/224
md = forge.md.sha512.sha224.create();
pdate('The quick brown fox jumps over the lazy dog');
ole.log(md.digest().toHex());
utput: 944cd2847fb54558d4775db0485a50003111c8e5daa63fe722c6aa37

HA-512/256
md = forge.md.sha512.sha256.create();
pdate('The quick brown fox jumps over the lazy dog');
ole.log(md.digest().toHex());
utput: dd9d67b371519c339ed8dbd25af90e976a1eeefd4ad3d889005e532fc5bef04d

MD5

Provides MD5 message digests.

Examples

md = forge.md.md5.create();
pdate('The quick brown fox jumps over the lazy dog');
ole.log(md.digest().toHex());
utput: 9e107d9d372bb6826bd81d3542a419d6

HMAC

Provides HMAC w/any supported message digest algorithm.

Examples

hmac = forge.hmac.create();
.start('sha1', 'Jefe');
.update('what do ya want for nothing?');
ole.log(hmac.digest().toHex());
utput: effcdf6ae5eb2fa2d27416d5f184df9c259a7c79
Utilities

Prime

Provides an API for generating large, random, probable primes.

Examples

enerate a random prime on the main JS thread
bits = 1024;
e.prime.generateProbablePrime(bits, function(err, num) {
nsole.log('random prime', num.toString(16));


enerate a random prime using Web Workers (if available, otherwise
alls back to the main thread)
bits = 1024;
options = {
gorithm: {
name: 'PRIMEINC',
workers: -1 // auto-optimize # of workers


e.prime.generateProbablePrime(bits, options, function(err, num) {
nsole.log('random prime', num.toString(16));

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

et some random bytes synchronously
bytes = forge.random.getBytesSync(32);
ole.log(forge.util.bytesToHex(bytes));

et some random bytes asynchronously
e.random.getBytes(32, function(err, bytes) {
nsole.log(forge.util.bytesToHex(bytes));


ollect some entropy if you'd like
e.random.collect(someRandomBytes);
ry().mousemove(function(e) {
rge.random.collectInt(e.clientX, 16);
rge.random.collectInt(e.clientY, 16);


pecify a seed file for use with the synchronous API if you'd like
e.random.seedFileSync = function(needed) {
 get 'needed' number of random bytes from somewhere
turn fetchedRandomBytes;


pecify a seed file for use with the asynchronous API if you'd like
e.random.seedFile = function(needed, callback) {
 get the 'needed' number of random bytes from somewhere
llback(null, fetchedRandomBytes);


egister the main thread to send entropy or a Web Worker to receive
ntropy on demand from the main thread
e.random.registerWorker(self);

enerate a new instance of a PRNG with no collected entropy
myPrng = forge.random.createInstance();

Tasks

Provides queuing and synchronizing tasks in a web application.

Examples

ODO

Utilities

Provides utility functions, including byte buffer support, base64, bytes to/from hex, zlib inflate/deflate, etc.

Examples

ncode/decode base64
encoded = forge.util.encode64(str);
str = forge.util.decode64(encoded);

ncode/decode UTF-8
encoded = forge.util.encodeUtf8(str);
str = forge.util.decodeUtf8(encoded);

ytes to/from hex
bytes = forge.util.hexToBytes(hex);
hex = forge.util.bytesToHex(bytes);

reate an empty byte buffer
buffer = forge.util.createBuffer();
reate a byte buffer from raw binary bytes
buffer = forge.util.createBuffer(input, 'raw');
reate a byte buffer from utf8 bytes
buffer = forge.util.createBuffer(input, 'utf8');

et the length of the buffer in bytes
er.length();
ut bytes into the buffer
er.putBytes(bytes);
ut a 32-bit integer into the buffer
er.putInt32(10);
uffer to hex
er.toHex();
et a copy of the bytes in the buffer
s.bytes(/* count */);
mpty this buffer and get its contents
s.getBytes(/* count */);

onvert a forge buffer into a Node.js Buffer
ake sure you specify the encoding as 'binary'
forgeBuffer = forge.util.createBuffer();
nodeBuffer = new Buffer(forgeBuffer.getBytes(), 'binary');

onvert a Node.js Buffer into a forge buffer
ake sure you specify the encoding as 'binary'
nodeBuffer = new Buffer();
forgeBuffer = forge.util.createBuffer(nodeBuffer.toString('binary'));

arse a URL
parsed = forge.util.parseUrl('http://example.com/foo?bar=baz');
arsed.scheme, parsed.host, parsed.port, parsed.path, parsed.fullHost

Logging

Provides logging to a javascript console using various categories and levels of verbosity.

Examples

ODO

Debugging

Provides storage of debugging information normally inaccessible in closures for viewing/investigation.

Examples

ODO

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:

Library Background
Contact
Donations

Financial support is welcome and helps contribute to futher development:


This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.