### Install dependencies for building SocketPool.swf Source: https://github.com/digitalbazaar/forge/blob/main/flash/README.md Run this command to install the npm module that provides the Flex SDK if it is not already installed. ```bash npm install ``` -------------------------------- ### Create TLS client and server with forge.tls.createConnection Source: https://github.com/digitalbazaar/forge/blob/main/README.md Shows how to create a TLS client and server using forge.tls.createConnection. The client sets server:false, specifies a virtualHost, and verifies the server certificate's CN against 'example.com'. The server sets server:true, optionally requires a client certificate with verifyClient:true, and verifies the client's CN against 'the-client'. Both examples configure cipher suites, session cache, and callbacks for connected, tlsDataReady, dataReady, closed, and error. The client example also demonstrates starting the handshake and processing encrypted bytes from the server. ```javascript // create TLS client var client = forge.tls.createConnection({ server: false, caStore: /* Array of PEM-formatted certs or a CA store object */, sessionCache: {}, // supported cipher suites in order of preference cipherSuites: [ forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA], virtualHost: 'example.com', verify: 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; }, connected: 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 getCertificate: function(connection, hint) { return myClientCertificate; }, /* the private key for the client-side cert if provided */ getPrivateKey: function(connection, cert) { return myClientPrivateKey; }, tlsDataReady: 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()); }, dataReady: 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 heartbeatReceived: 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(); },*/ closed: function(connection) { console.log('disconnected'); }, error: function(connection, error) { console.log('uh oh', error); } }); // start the handshake process client.handshake(); // when encrypted TLS data is received from the server, process it client.process(encryptedBytesFromServer); ``` ```javascript // create TLS server var server = forge.tls.createConnection({ server: true, caStore: /* Array of PEM-formatted certs or a CA store object */, sessionCache: {}, // supported cipher suites in order of preference cipherSuites: [ 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 verifyClient: true, verify: 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; }, connected: 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);*/ }, getCertificate: function(connection, hint) { return myServerCertificate; }, getPrivateKey: function(connection, cert) { return myServerPrivateKey; }, tlsDataReady: 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()); }, dataReady: 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 heartbeatReceived: 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(); },*/ closed: function(connection) { console.log('disconnected'); }, error: function(connection, error) { console.log('uh oh', error); } }); ``` -------------------------------- ### Create and send HTTP GET request with forge.http Source: https://github.com/digitalbazaar/forge/blob/main/README.md Create an HTTP GET request with forge.http.createRequest, send it, and receive the response using forge.http.createResponse. The example shows how to read the response header and body asynchronously. ```javascript // create an HTTP GET request var request = forge.http.createRequest({method: 'GET', path: url.path}); // send the request somewhere sendSomehow(request.toString()); // receive response var buffer = forge.util.createBuffer(); var response = forge.http.createResponse(); var someAsyncDataHandler = function(bytes) { if(!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); } } } }; ``` -------------------------------- ### Build forge browser bundles Source: https://github.com/digitalbazaar/forge/blob/main/README.md Install dependencies and build browser bundles for forge. ```bash npm install ``` ```bash npm run build ``` -------------------------------- ### XHR example placeholder Source: https://github.com/digitalbazaar/forge/blob/main/README.md Placeholder example for the XHR section, showing no actual code yet. ```javascript // TODO ``` -------------------------------- ### Install node-forge with npm Source: https://github.com/digitalbazaar/forge/blob/main/README.md Install the node-forge package via npm for use in Node.js projects. ```bash npm install node-forge ``` -------------------------------- ### Run manual browser tests Source: https://github.com/digitalbazaar/forge/blob/main/README.md Commands to run manual tests in a browser. 'npm run test-build' builds a special forge build for unit tests, 'npm run build' builds the main forge build for legacy tests, and 'npm run test-server' starts a custom server that prints URLs to load. The server also starts a simple Flash Policy Server. ```bash npm run test-build ``` ```bash npm run build ``` ```bash npm run test-server ``` -------------------------------- ### Forge utilities and byte buffer example Source: https://github.com/digitalbazaar/forge/blob/main/README.md Covers forge.util functions: base64, UTF-8, hex conversion, byte buffer creation and operations, and conversion between forge buffers and Node.js Buffers. Note the 'binary' encoding requirement for Node.js Buffer conversions. ```javascript // encode/decode base64 var encoded = forge.util.encode64(str); var str = forge.util.decode64(encoded); // encode/decode UTF-8 var encoded = forge.util.encodeUtf8(str); var str = forge.util.decodeUtf8(encoded); // bytes to/from hex var bytes = forge.util.hexToBytes(hex); var hex = forge.util.bytesToHex(bytes); // create an empty byte buffer var buffer = forge.util.createBuffer(); // create a byte buffer from raw binary bytes var buffer = forge.util.createBuffer(input, 'raw'); // create a byte buffer from utf8 bytes var buffer = forge.util.createBuffer(input, 'utf8'); // get the length of the buffer in bytes buffer.length(); // put bytes into the buffer buffer.putBytes(bytes); // put a 32-bit integer into the buffer buffer.putInt32(10); // buffer to hex buffer.toHex(); // get a copy of the bytes in the buffer bytes.bytes(/* count */); // empty this buffer and get its contents bytes.getBytes(/* count */); // convert a forge buffer into a Node.js Buffer // make sure you specify the encoding as 'binary' var forgeBuffer = forge.util.createBuffer(); var nodeBuffer = Buffer.from(forgeBuffer.getBytes(), 'binary'); // convert a Node.js Buffer into a forge buffer // make sure you specify the encoding as 'binary' var nodeBuffer = Buffer.from('CAFE', 'hex'); var forgeBuffer = forge.util.createBuffer(nodeBuffer.toString('binary')); ``` -------------------------------- ### Connect to a TLS server with forge.tls and net.Socket Source: https://github.com/digitalbazaar/forge/blob/main/README.md Connect to a TLS server using node's net.Socket and forge.tls.createConnection. The example skips certificate verification for testing, sends an HTTP GET request, and handles TLS data ready, clear data, and connection events. Note that the string is interpreted as 'binary' encoded, which works for HTTP (ASCII only); use forge.util.encodeUtf8(str) otherwise. ```javascript var socket = new net.Socket(); var client = forge.tls.createConnection({ server: false, verify: function(connection, verified, depth, certs) { // skip verification for testing console.log('[tls] server certificate verified'); return true; }, connected: 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'); }, tlsDataReady: 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' }, dataReady: function(connection) { // clear data from the server is ready var data = connection.data.getBytes(); console.log('[tls] data received from the server: ' + data); }, closed: function() { console.log('[tls] disconnected'); }, error: function(connection, error) { console.log('[tls] error', error); } }); socket.on('connect', function() { console.log('[socket] connected'); client.handshake(); }); socket.on('data', function(data) { client.process(data.toString('binary')); // encoding should be 'binary' }); socket.on('end', function() { console.log('[socket] disconnected'); }); // connect to google.com socket.connect(443, 'google.com'); // or connect to gmail's imap server (but don't send the HTTP header above) //socket.connect(993, 'imap.gmail.com'); ``` -------------------------------- ### PRNG random bytes and entropy example Source: https://github.com/digitalbazaar/forge/blob/main/README.md Shows the PRNG API: synchronous and asynchronous random byte generation, entropy collection, custom seed file functions, worker registration, and creating a new PRNG instance. Uses window.crypto.getRandomValues automatically if available. ```javascript // get some random bytes synchronously var bytes = forge.random.getBytesSync(32); console.log(forge.util.bytesToHex(bytes)); // get some random bytes asynchronously forge.random.getBytes(32, function(err, bytes) { console.log(forge.util.bytesToHex(bytes)); }); // collect some entropy if you'd like forge.random.collect(someRandomBytes); jQuery().mousemove(function(e) { forge.random.collectInt(e.clientX, 16); forge.random.collectInt(e.clientY, 16); }); // specify a seed file for use with the synchronous API if you'd like forge.random.seedFileSync = function(needed) { // get 'needed' number of random bytes from somewhere return fetchedRandomBytes; }; // specify a seed file for use with the asynchronous API if you'd like forge.random.seedFile = function(needed, callback) { // get the 'needed' number of random bytes from somewhere callback(null, fetchedRandomBytes); }); // register the main thread to send entropy or a Web Worker to receive // entropy on demand from the main thread forge.random.registerWorker(self); // generate a new instance of a PRNG with no collected entropy var myPrng = forge.random.createInstance(); ``` -------------------------------- ### MD5 digest example Source: https://github.com/digitalbazaar/forge/blob/main/README.md Creates an MD5 message digest, updates it with a string, and prints the hex digest. The expected output is 9e107d9d372bb6826bd81d3542a419d6. ```javascript var md = forge.md.md5.create(); md.update('The quick brown fox jumps over the lazy dog'); console.log(md.digest().toHex()); // output: 9e107d9d372bb6826bd81d3542a419d6 ``` -------------------------------- ### RSA key generation, signing, and encryption with forge.pki.rsa Source: https://github.com/digitalbazaar/forge/blob/main/README.md Comprehensive RSA operations using forge.pki.rsa: key generation (sync, async, and step-based), signing/verifying with PKCS#1 v1.5 and RSASSA-PSS, and encryption/decryption with PKCS#1 v1.5, RSAES-OAEP, and OAEP with SHA-256/MGF1-SHA-1. Sync generation is not recommended; async uses web workers and native APIs when available. The step-based generator runs on the main thread for a specified time (100 ms in the example) and exposes state.keys when done. ```javascript var rsa = forge.pki.rsa; // generate an RSA key pair synchronously // *NOT RECOMMENDED*: Can be significantly slower than async and may block // JavaScript execution. Will use native Node.js 10.12.0+ API if possible. var keypair = rsa.generateKeyPair({bits: 2048, e: 0x10001}); // generate an RSA key pair asynchronously (uses web workers if available) // use workers: -1 to run a fast core estimator to optimize # of workers // *RECOMMENDED*: Can be significantly faster than sync. Will use native // Node.js 10.12.0+ or WebCrypto API if possible. rsa.generateKeyPair({bits: 2048, workers: 2}, function(err, keypair) { // keypair.privateKey, keypair.publicKey }); // generate an RSA key pair in steps that attempt to run for a specified period // of time on the main JS thread var state = rsa.createKeyPairGenerationState(2048, 0x10001); var step = function() { // run for 100 ms if(!rsa.stepKeyPairGenerationState(state, 100)) { setTimeout(step, 1); } else { // done, turn off progress indicator, use state.keys } }; // turn on progress indicator, schedule generation to run setTimeout(step); // sign data with a private key and output DigestInfo DER-encoded bytes // (defaults to RSASSA PKCS#1 v1.5) var md = forge.md.sha1.create(); md.update('sign this', 'utf8'); var signature = privateKey.sign(md); // verify data with a public key // (defaults to RSASSA PKCS#1 v1.5) var verified = publicKey.verify(md.digest().bytes(), signature); // sign data using RSASSA-PSS where PSS uses a SHA-1 hash, a SHA-1 based // masking function MGF1, and a 20 byte salt var md = forge.md.sha1.create(); md.update('sign this', 'utf8'); var pss = forge.pss.create({ md: forge.md.sha1.create(), mgf: forge.mgf.mgf1.create(forge.md.sha1.create()), saltLength: 20 // optionally pass 'prng' with a custom PRNG implementation // optionalls pass 'salt' with a forge.util.ByteBuffer w/custom salt }); var signature = privateKey.sign(md, pss); // verify RSASSA-PSS signature var pss = forge.pss.create({ md: forge.md.sha1.create(), mgf: forge.mgf.mgf1.create(forge.md.sha1.create()), saltLength: 20 // optionally pass 'prng' with a custom PRNG implementation }); var md = forge.md.sha1.create(); md.update('sign this', 'utf8'); publicKey.verify(md.digest().getBytes(), signature, pss); // encrypt data with a public key (defaults to RSAES PKCS#1 v1.5) var encrypted = publicKey.encrypt(bytes); // decrypt data with a private key (defaults to RSAES PKCS#1 v1.5) var decrypted = privateKey.decrypt(encrypted); // encrypt data with a public key using RSAES PKCS#1 v1.5 var encrypted = publicKey.encrypt(bytes, 'RSAES-PKCS1-V1_5'); // decrypt data with a private key using RSAES PKCS#1 v1.5 var decrypted = privateKey.decrypt(encrypted, 'RSAES-PKCS1-V1_5'); // encrypt data with a public key using RSAES-OAEP var encrypted = publicKey.encrypt(bytes, 'RSA-OAEP'); // decrypt data with a private key using RSAES-OAEP var decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP'); // encrypt data with a public key using RSAES-OAEP/SHA-256 var encrypted = publicKey.encrypt(bytes, 'RSA-OAEP', { md: forge.md.sha256.create() }); // decrypt data with a private key using RSAES-OAEP/SHA-256 var decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP', { md: forge.md.sha256.create() }); // encrypt data with a public key using RSAES-OAEP/SHA-256/MGF1-SHA-1 // compatible with Java's RSA/ECB/OAEPWithSHA-256AndMGF1Padding var encrypted = publicKey.encrypt(bytes, 'RSA-OAEP', { md: forge.md.sha256.create(), mgf1: { md: forge.md.sha1.create() } }); // decrypt data with a private key using RSAES-OAEP/SHA-256/MGF1-SHA-1 // compatible with Java's RSA/ECB/OAEPWithSHA-256AndMGF1Padding var decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP', { md: forge.md.sha256.create(), mgf1: { md: forge.md.sha1.create() } }); ``` -------------------------------- ### ASN.1 DER encoding, decoding, validation, and pretty-printing Source: https://github.com/digitalbazaar/forge/blob/main/README.md Shows how to create a SubjectPublicKeyInfo ASN.1 structure, serialize it to DER, deserialize it, convert OIDs, validate the structure with a validator, and pretty-print it. The example uses forge.asn1 and assumes key, pki, and validator are defined elsewhere. ```js var asn1 = forge.asn1; // create a SubjectPublicKeyInfo var subjectPublicKeyInfo = asn1.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)) ]) ]) ]); // serialize an ASN.1 object to DER format var derBuffer = asn1.toDer(subjectPublicKeyInfo); // deserialize to an ASN.1 object from a byte buffer filled with DER data var object = asn1.fromDer(derBuffer); // convert an OID dot-separated string to a byte buffer var derOidBuffer = asn1.oidToDer('1.2.840.113549.1.1.5'); // convert a byte buffer with a DER-encoded OID to a dot-separated string console.log(asn1.derToOid(derOidBuffer)); // output: 1.2.840.113549.1.1.5 // validates that an ASN.1 object matches a particular ASN.1 structure and // captures data of interest from that structure for easy access var publicKeyValidator = { name: 'SubjectPublicKeyInfo', tagClass: asn1.Class.UNIVERSAL, type: asn1.Type.SEQUENCE, constructed: true, captureAsn1: 'subjectPublicKeyInfo', value: [{ 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' }] }] }; var capture = {}; var errors = []; if(!asn1.validate( publicKeyValidator, subjectPublicKeyInfo, validator, capture, errors)) { throw 'ASN.1 object is not a SubjectPublicKeyInfo.'; } // capture.subjectPublicKeyInfo contains the full ASN.1 object // capture.rsaPublicKey contains the full ASN.1 object for the RSA public key // capture.publicKeyOid only contains the value for the OID var oid = asn1.derToOid(capture.publicKeyOid); if(oid !== pki.oids['rsaEncryption']) { throw 'Unsupported OID.'; } // pretty print an ASN.1 object to a string for debugging purposes asn1.prettyPrint(object); ``` -------------------------------- ### HMAC SHA-1 example Source: https://github.com/digitalbazaar/forge/blob/main/README.md Creates an HMAC using SHA-1 with the key 'Jefe', updates it with a message, and prints the hex digest. The expected output is effcdf6ae5eb2fa2d27416d5f184df9c259a7c79. ```javascript var hmac = forge.hmac.create(); hmac.start('sha1', 'Jefe'); hmac.update('what do ya want for nothing?'); console.log(hmac.digest().toHex()); // output: effcdf6ae5eb2fa2d27416d5f184df9c259a7c79 ``` -------------------------------- ### X.509 certificate operations with forge.pki Source: https://github.com/digitalbazaar/forge/blob/main/README.md Comprehensive example of using forge.pki for X.509 operations: converting between PEM, ASN.1, and Forge public keys; computing fingerprints with configurable hash, encoding, and delimiter; managing a CA store; signing and verifying certificates; and generating a self-signed X.509v3 certificate with extensions. Note the serialNumber constraints (max 20 octets, non-negative) and the alternative to set subject/extensions from a CSR. ```javascript var pki = forge.pki; // convert a PEM-formatted public key to a Forge public key var publicKey = pki.publicKeyFromPem(pem); // convert a Forge public key to PEM-format var pem = pki.publicKeyToPem(publicKey); // convert an ASN.1 SubjectPublicKeyInfo to a Forge public key var publicKey = pki.publicKeyFromAsn1(subjectPublicKeyInfo); // convert a Forge public key to an ASN.1 SubjectPublicKeyInfo var subjectPublicKeyInfo = pki.publicKeyToAsn1(publicKey); // gets a SHA-1 RSAPublicKey fingerprint a byte buffer pki.getPublicKeyFingerprint(key); // gets a SHA-1 SubjectPublicKeyInfo fingerprint a byte buffer pki.getPublicKeyFingerprint(key, {type: 'SubjectPublicKeyInfo'}); // gets a hex-encoded, colon-delimited SHA-1 RSAPublicKey public key fingerprint pki.getPublicKeyFingerprint(key, {encoding: 'hex', delimiter: ':'}); // gets a hex-encoded, colon-delimited SHA-1 SubjectPublicKeyInfo public key fingerprint pki.getPublicKeyFingerprint(key, { type: 'SubjectPublicKeyInfo', encoding: 'hex', delimiter: ':' }); // gets a hex-encoded, colon-delimited MD5 RSAPublicKey public key fingerprint pki.getPublicKeyFingerprint(key, { md: forge.md.md5.create(), encoding: 'hex', delimiter: ':' }); // creates a CA store var caStore = pki.createCaStore([/* PEM-encoded cert */, ...]); // add a certificate to the CA store caStore.addCertificate(certObjectOrPemString); // gets the issuer (its certificate) for the given certificate var issuerCert = caStore.getIssuer(subjectCert); // verifies a certificate chain against a CA store pki.verifyCertificateChain(caStore, chain, customVerifyCallback); // signs a certificate using the given private key cert.sign(privateKey); // signs a certificate using SHA-256 instead of SHA-1 cert.sign(privateKey, forge.md.sha256.create()); // verifies an issued certificate using the certificates public key var verified = issuer.verify(issued); // generate a keypair and create an X.509v3 certificate var keys = pki.rsa.generateKeyPair(2048); var cert = pki.createCertificate(); cert.publicKey = keys.publicKey; // alternatively set public key from a csr //cert.publicKey = csr.publicKey; // NOTE: serialNumber is the hex encoded value of an ASN.1 INTEGER. // Conforming CAs should ensure serialNumber is: // - no more than 20 octets // - non-negative (prefix a '00' if your value starts with a '1' bit) cert.serialNumber = '01'; cert.validity.notBefore = new Date(); cert.validity.notAfter = new Date(); cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1); var attrs = [{ name: 'commonName', value: 'example.org' }, { name: 'countryName', value: 'US' }, { shortName: 'ST', value: 'Virginia' }, { name: 'localityName', value: 'Blacksburg' }, { name: 'organizationName', value: 'Test' }, { shortName: 'OU', value: 'Test' }]; cert.setSubject(attrs); // alternatively set subject from a csr //cert.setSubject(csr.subject.attributes); cert.setIssuer(attrs); cert.setExtensions([{ name: 'basicConstraints', cA: true }, { name: 'keyUsage', keyCertSign: true, digitalSignature: true, nonRepudiation: true, keyEncipherment: true, dataEncipherment: true }, { name: 'extKeyUsage', serverAuth: true, clientAuth: true, codeSigning: true, emailProtection: true, timeStamping: true }, { name: 'nsCertType', client: true, server: true, email: true, objsign: true, sslCA: true, emailCA: true, objCA: true }, { name: 'subjectAltName', altNames: [{ type: 6, // URI value: 'http://example.org/webid#me' }, { type: 7, // IP ip: '127.0.0.1' }] }, { name: 'subjectKeyIdentifier' }]); /* alternatively set extensions from a csr var extensions = csr.getAttribute({name: 'extensionRequest'}).extensions; // optionally add more extensions extensions.push.apply(extensions, [{ name: 'basicConstraints', cA: true }, { name: 'keyUsage', keyCertSign: true, digitalSignature: true, nonRepudiation: true, keyEncipherment: true, dataEncipherment: true }]); cert.setExtensions(extensions); */ // self-sign certificate cert.sign(keys.privateKey); // convert a Forge certificate to PEM var pem = pki.certificateToPem(cert); // convert a Forge certificate from PEM var cert = pki.certificateFromPem(pem); // convert an ASN.1 X.509x3 object to a Forge certificate var cert = pki.certificateFromAsn1(obj); // convert a Forge certificate to an ASN.1 X.509v3 object var asn1Cert = pki.certificateToAsn1(cert); ``` -------------------------------- ### Create and manage a PKCS#10 CSR with forge.pki Source: https://github.com/digitalbazaar/forge/blob/main/README.md Create, sign, verify, and convert a PKCS#10 certification request (CSR) using forge.pki. Includes setting subject and optional attributes (challengePassword, unstructuredName, extensionRequest with subjectAltName). The example shows PEM conversion and attribute retrieval. ```javascript // generate a key pair var keys = forge.pki.rsa.generateKeyPair(2048); // create a certification request (CSR) var csr = forge.pki.createCertificationRequest(); csr.publicKey = keys.publicKey; csr.setSubject([{ name: 'commonName', value: 'example.org' }, { name: 'countryName', value: 'US' }, { shortName: 'ST', value: 'Virginia' }, { name: 'localityName', value: 'Blacksburg' }, { name: 'organizationName', value: 'Test' }, { shortName: 'OU', value: 'Test' }]); // set (optional) attributes csr.setAttributes([{ name: 'challengePassword', value: 'password' }, { name: 'unstructuredName', value: 'My Company, Inc.' }, { name: 'extensionRequest', extensions: [{ 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' }] }] }]); // sign certification request csr.sign(keys.privateKey); // verify certification request var verified = csr.verify(); // convert certification request to PEM-format var pem = forge.pki.certificationRequestToPem(csr); // convert a Forge certification request from PEM-format var csr = forge.pki.certificationRequestFromPem(pem); // get an attribute csr.getAttribute({name: 'challengePassword'}); // get extensions array csr.getAttribute({name: 'extensionRequest'}).extensions; ``` -------------------------------- ### RSA-KEM key encapsulation and AES-GCM encryption/decryption Source: https://github.com/digitalbazaar/forge/blob/main/README.md Complete RSA-KEM workflow: generate an RSA key pair asynchronously (optionally using web workers), encapsulate a 16-byte secret key with forge.kem.rsa, encrypt data with AES-GCM, then decrypt the key and data on the recipient side. The example shows the full round-trip including the authentication tag check; pass is false if the tag doesn't match. ```javascript // generate an RSA key pair asynchronously (uses web workers if available) // use workers: -1 to run a fast core estimator to optimize # of workers forge.rsa.generateKeyPair({bits: 2048, workers: -1}, function(err, keypair) { // keypair.privateKey, keypair.publicKey }); // generate and encapsulate a 16-byte secret key var kdf1 = new forge.kem.kdf1(forge.md.sha1.create()); var kem = forge.kem.rsa.create(kdf1); var result = kem.encrypt(keypair.publicKey, 16); // result has 'encapsulation' and 'key' // encrypt some bytes var iv = forge.random.getBytesSync(12); var someBytes = 'hello world!'; var cipher = forge.cipher.createCipher('AES-GCM', result.key); cipher.start({iv: iv}); cipher.update(forge.util.createBuffer(someBytes)); cipher.finish(); var encrypted = cipher.output.getBytes(); var tag = cipher.mode.tag.getBytes(); // send 'encrypted', 'iv', 'tag', and result.encapsulation to recipient // decrypt encapsulated 16-byte secret key var kdf1 = new forge.kem.kdf1(forge.md.sha1.create()); var kem = forge.kem.rsa.create(kdf1); var key = kem.decrypt(keypair.privateKey, result.encapsulation, 16); // decrypt some bytes var decipher = forge.cipher.createDecipher('AES-GCM', key); decipher.start({iv: iv, tag: tag}); decipher.update(forge.util.createBuffer(encrypted)); var pass = decipher.finish(); // pass is false if there was a failure (eg: authentication tag didn't match) if(pass) { // outputs 'hello world!' console.log(decipher.output.getBytes()); } ``` -------------------------------- ### AES-CBC and AES-GCM encryption/decryption with forge Source: https://github.com/digitalbazaar/forge/blob/main/README.md Complete example of AES encryption and decryption using forge's cipher API. Covers CBC mode with random key/IV generation, streaming decryption for large inputs, and GCM mode with authentication tag. Note that CBC and ECB use PKCS#7 padding by default; GCM requires a 12-byte IV and supports optional additionalData and tagLength (default 128 bits). ```javascript // generate a random key and IV // Note: a key size of 16 bytes will use AES-128, 24 => AES-192, 32 => AES-256 var key = forge.random.getBytesSync(16); var iv = forge.random.getBytesSync(16); /* alternatively, generate a password-based 16-byte key var salt = forge.random.getBytesSync(128); var key = forge.pkcs5.pbkdf2('password', salt, numIterations, 16); */ // encrypt some bytes using CBC mode // (other modes include: ECB, CFB, OFB, CTR, and GCM) // Note: CBC and ECB modes use PKCS#7 padding as default var cipher = forge.cipher.createCipher('AES-CBC', key); cipher.start({iv: iv}); cipher.update(forge.util.createBuffer(someBytes)); cipher.finish(); var encrypted = cipher.output; // outputs encrypted hex console.log(encrypted.toHex()); // decrypt some bytes using CBC mode // (other modes include: CFB, OFB, CTR, and GCM) var decipher = forge.cipher.createDecipher('AES-CBC', key); decipher.start({iv: iv}); decipher.update(encrypted); var result = decipher.finish(); // check 'result' for true/false // outputs decrypted hex console.log(decipher.output.toHex()); // decrypt bytes using CBC mode and streaming // Performance can suffer for large multi-MB inputs due to buffer // manipulations. Stream processing in chunks can offer significant // improvement. CPU intensive update() calls could also be performed with // setImmediate/setTimeout to avoid blocking the main browser UI thread (not // shown here). Optimal block size depends on the JavaScript VM and other // factors. Encryption can use a simple technique for increased performance. var encryptedBytes = encrypted.bytes(); var decipher = forge.cipher.createDecipher('AES-CBC', key); decipher.start({iv: iv}); var length = encryptedBytes.length; var chunkSize = 1024 * 64; var index = 0; var decrypted = ''; do { decrypted += decipher.output.getBytes(); var buf = forge.util.createBuffer(encryptedBytes.substr(index, chunkSize)); decipher.update(buf); index += chunkSize; } while(index < length); var result = decipher.finish(); assert(result); decrypted += decipher.output.getBytes(); console.log(forge.util.bytesToHex(decrypted)); // encrypt some bytes using GCM mode var cipher = forge.cipher.createCipher('AES-GCM', key); cipher.start({ iv: iv, // should be a 12-byte binary-encoded string or byte buffer additionalData: 'binary-encoded string', // optional tagLength: 128 // optional, defaults to 128 bits }); cipher.update(forge.util.createBuffer(someBytes)); cipher.finish(); var encrypted = cipher.output; var tag = cipher.mode.tag; // outputs encrypted hex console.log(encrypted.toHex()); // outputs authentication tag console.log(tag.toHex()); // decrypt some bytes using GCM mode var decipher = forge.cipher.createDecipher('AES-GCM', key); decipher.start({ iv: iv, additionalData: 'binary-encoded string', // optional tagLength: 128, // optional, defaults to 128 bits tag: tag // authentication tag from encryption }); decipher.update(encrypted); var pass = decipher.finish(); // pass is false if there was a failure (eg: authentication tag didn't match) if(pass) { // outputs decrypted hex console.log(decipher.output.toHex()); } ``` -------------------------------- ### Process encrypted TLS data with server.process() Source: https://github.com/digitalbazaar/forge/blob/main/README.md Process encrypted TLS data received from a client using the forge TLS server API. This is a minimal example showing the server.process() call. ```javascript // when encrypted TLS data is received from the client, process it server.process(encryptedBytesFromClient); ``` -------------------------------- ### Build regular SocketPool.swf component Source: https://github.com/digitalbazaar/forge/blob/main/flash/README.md Use this npm script to build the standard SocketPool.swf component. ```bash npm run build ``` -------------------------------- ### SSH utility functions for key encoding and fingerprints Source: https://github.com/digitalbazaar/forge/blob/main/README.md SSH utility functions for encoding RSA keys to Putty PPK or OpenSSH formats and getting public key fingerprints. The fingerprint can be returned as a byte buffer or hex-encoded with a delimiter. ```javascript // encodes (and optionally encrypts) a private RSA key as a Putty PPK file forge.ssh.privateKeyToPutty(privateKey, passphrase, comment); // encodes a public RSA key as an OpenSSH file forge.ssh.publicKeyToOpenSSH(key, comment); // encodes a private RSA key as an OpenSSH file forge.ssh.privateKeyToOpenSSH(privateKey, passphrase); // gets the SSH public key fingerprint in a byte buffer forge.ssh.getPublicKeyFingerprint(key); // gets a hex-encoded, colon-delimited SSH public key fingerprint forge.ssh.getPublicKeyFingerprint(key, {encoding: 'hex', delimiter: ':'}); ``` -------------------------------- ### Run coverage testing Source: https://github.com/digitalbazaar/forge/blob/main/README.md Commands to perform coverage testing of the unit tests. Results are placed in the 'coverage/' directory. Note that coverage testing can slow down some tests considerably. ```bash npm install npm run coverage ``` -------------------------------- ### Load forge from unpkg CDN Source: https://github.com/digitalbazaar/forge/blob/main/README.md Include forge in a web page via the unpkg CDN. ```html ``` -------------------------------- ### Build SocketPool.swf with debug support Source: https://github.com/digitalbazaar/forge/blob/main/flash/README.md Use this npm script to build the SocketPool.swf component with additional debug support. ```bash npm run build-debug ``` -------------------------------- ### Decode, parse, and generate PKCS#12 containers with forge.pkcs12 Source: https://github.com/digitalbazaar/forge/blob/main/README.md Decode, parse, and generate PKCS#12 containers with forge.pkcs12. Shows password handling (including non-strict mode, no password, and empty password), retrieving bags by friendlyName/localKeyId/type, and generating p12 with AES (default) or TripleDES ({algorithm: '3des'}) for Chrome/Firefox/iOS compatibility. Ends with base64 encoding and creating a download link. ```javascript // decode p12 from base64 var p12Der = forge.util.decode64(p12b64); // get p12 as ASN.1 object var p12Asn1 = forge.asn1.fromDer(p12Der); // decrypt p12 using the password 'password' var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, 'password'); // decrypt p12 using non-strict parsing mode (resolves some ASN.1 parse errors) var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, false, 'password'); // decrypt p12 using literally no password (eg: Mac OS X/apple push) var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1); // decrypt p12 using an "empty" password (eg: OpenSSL with no password input) var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, ''); // p12.safeContents is an array of safe contents, each of // which contains an array of safeBags // get bags by friendlyName var bags = p12.getBags({friendlyName: 'test'}); // bags are key'd by attribute type (here "friendlyName") // and the key values are an array of matching objects var cert = bags.friendlyName[0]; // get bags by localKeyId var bags = p12.getBags({localKeyId: buffer}); // bags are key'd by attribute type (here "localKeyId") // and the key values are an array of matching objects var cert = bags.localKeyId[0]; // get bags by localKeyId (input in hex) var bags = p12.getBags({localKeyIdHex: '7b59377ff142d0be4565e9ac3d396c01401cd879'}); // bags are key'd by attribute type (here "localKeyId", *not* "localKeyIdHex") // and the key values are an array of matching objects var cert = bags.localKeyId[0]; // get bags by type var bags = p12.getBags({bagType: forge.pki.oids.certBag}); // bags are key'd by bagType and each bagType key's value // is an array of matches (in this case, certificate objects) var cert = bags[forge.pki.oids.certBag][0]; // get bags by friendlyName and filter on bag type var bags = p12.getBags({ friendlyName: 'test', bagType: forge.pki.oids.certBag }); // get key bags var bags = p12.getBags({bagType: forge.pki.oids.keyBag}); // get key var bag = bags[forge.pki.oids.keyBag][0]; var key = bag.key; // if the key is in a format unrecognized by forge then // bag.key will be `null`, use bag.asn1 to get the ASN.1 // representation of the key if(bag.key === null) { var keyAsn1 = bag.asn1; // can now convert back to DER/PEM/etc for export } // generate a p12 using AES (default) var p12Asn1 = forge.pkcs12.toPkcs12Asn1( privateKey, certificateChain, 'password'); // generate a p12 that can be imported by Chrome/Firefox/iOS // (requires the use of Triple DES instead of AES) var p12Asn1 = forge.pkcs12.toPkcs12Asn1( privateKey, certificateChain, 'password', {algorithm: '3des'}); // base64-encode p12 var p12Der = forge.asn1.toDer(p12Asn1).getBytes(); var p12b64 = forge.util.encode64(p12Der); // create download link for p12 var a = document.createElement('a'); a.download = 'example.p12'; a.setAttribute('href', 'data:application/x-pkcs12;base64,' + p12b64); a.appendChild(document.createTextNode('Download')); ``` -------------------------------- ### Include forge.js or forge.min.js in HTML Source: https://github.com/digitalbazaar/forge/blob/main/README.md Include the built forge.js or forge.min.js bundle in a web page. These bundles create a global 'forge' object. ```html ``` ```html ``` -------------------------------- ### Run forge tests with npm test Source: https://github.com/digitalbazaar/forge/blob/main/README.md Run the automated test suite for forge in a Node.js environment. ```bash npm test ```