From a5e75620665496cbcde9cdee73d3fea280509fc1 Mon Sep 17 00:00:00 2001 From: Mahrud Sayrafi Date: Thu, 8 Mar 2018 17:55:44 -0800 Subject: [PATCH] Many documentation improvements; more to come --- src/config/config.js | 104 ++++++++--- src/config/localStorage.js | 1 + src/crypto/aes_kw.js | 23 ++- src/crypto/cfb.js | 9 +- src/crypto/cipher/aes.js | 1 - src/crypto/cipher/blowfish.js | 5 - src/crypto/cipher/cast5.js | 2 - src/crypto/cipher/des.js | 4 - src/crypto/cipher/index.js | 68 ++++++- src/crypto/cipher/twofish.js | 21 +-- src/crypto/crypto.js | 2 + src/crypto/hash/index.js | 23 ++- src/crypto/hash/md5.js | 6 +- src/crypto/pkcs1.js | 202 +++++++++++---------- src/crypto/pkcs5.js | 6 +- src/crypto/public_key/index.js | 16 +- src/crypto/public_key/rsa.js | 48 ++--- src/crypto/random.js | 1 + src/crypto/signature.js | 5 +- src/keyring/keyring.js | 1 + src/keyring/localstore.js | 1 + src/packet/all_packets.js | 2 +- src/packet/packet.js | 1 + src/packet/packetlist.js | 1 + src/packet/public_key.js | 4 +- src/packet/public_subkey.js | 5 + src/packet/secret_key.js | 3 + src/packet/secret_subkey.js | 2 + src/packet/sym_encrypted_aead_protected.js | 8 +- src/packet/trust.js | 13 ++ src/type/keyid.js | 2 +- src/util.js | 5 +- src/worker/async_proxy.js | 14 ++ src/worker/worker.js | 9 + 34 files changed, 400 insertions(+), 218 deletions(-) diff --git a/src/config/config.js b/src/config/config.js index 8af675bf..301e41b8 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -16,66 +16,124 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * This object contains global configuration values. + * Global configuration values. * @requires enums - * @module config/config */ import enums from '../enums'; export default { - /** @property {Integer} prefer_hash_algorithm Default hash algorithm {@link module:enums.hash} */ + /** + * @memberof module:config + * @property {Integer} prefer_hash_algorithm Default hash algorithm {@link module:enums.hash} + */ prefer_hash_algorithm: enums.hash.sha256, - /** @property {Integer} encryption_cipher Default encryption cipher {@link module:enums.symmetric} */ + /** + * @memberof module:config + * @property {Integer} encryption_cipher Default encryption cipher {@link module:enums.symmetric} + */ encryption_cipher: enums.symmetric.aes256, - /** @property {Integer} compression Default compression algorithm {@link module:enums.compression} */ + /** + * @memberof module:config + * @property {Integer} compression Default compression algorithm {@link module:enums.compression} + */ compression: enums.compression.uncompressed, - /** @property {Integer} deflate_level Default zip/zlib compression level, between 1 and 9 */ + /** + * @memberof module:config + * @property {Integer} deflate_level Default zip/zlib compression level, between 1 and 9 + */ deflate_level: 6, /** * Use Authenticated Encryption with Additional Data (AEAD) protection for symmetric encryption. * **NOT INTEROPERABLE WITH OTHER OPENPGP IMPLEMENTATIONS** + * @memberof module:config * @property {Boolean} aead_protect */ aead_protect: false, /** Use integrity protection for symmetric encryption - * @property {Boolean} integrity_protect */ + * @memberof module:config + * @property {Boolean} integrity_protect + */ integrity_protect: true, - /** @property {Boolean} ignore_mdc_error Fail on decrypt if message is not integrity protected */ + /** + * @memberof module:config + * @property {Boolean} ignore_mdc_error Fail on decrypt if message is not integrity protected + */ ignore_mdc_error: false, - /** @property {Boolean} checksum_required Do not throw error when armor is missing a checksum */ + /** + * @memberof module:config + * @property {Boolean} checksum_required Do not throw error when armor is missing a checksum + */ checksum_required: false, - /** @property {Boolean} rsa_blinding */ + /** + * @memberof module:config + * @property {Boolean} rsa_blinding + */ rsa_blinding: true, - /** Work-around for rare GPG decryption bug when encrypting with multiple passwords - * Slower and slightly less secure + /** + * Work-around for rare GPG decryption bug when encrypting with multiple passwords. + * **Slower and slightly less secure** + * @memberof module:config * @property {Boolean} password_collision_check */ password_collision_check: false, - /** @property {Boolean} revocations_expire If true, expired revocation signatures are ignored */ + /** + * @memberof module:config + * @property {Boolean} revocations_expire If true, expired revocation signatures are ignored + */ revocations_expire: false, - /** @property {Boolean} use_native Use native Node.js crypto/zlib and WebCrypto APIs when available */ + /** + * @memberof module:config + * @property {Boolean} use_native Use native Node.js crypto/zlib and WebCrypto APIs when available + */ use_native: true, - /** @property {Boolean} Use transferable objects between the Web Worker and main thread */ + /** + * @memberof module:config + * @property {Boolean} Use transferable objects between the Web Worker and main thread + */ zero_copy: false, - /** @property {Boolean} debug If enabled, debug messages will be printed */ + /** + * @memberof module:config + * @property {Boolean} debug If enabled, debug messages will be printed + */ debug: false, - /** @property {Boolean} tolerant Ignore unsupported/unrecognizable packets instead of throwing an error */ + /** + * @memberof module:config + * @property {Boolean} tolerant Ignore unsupported/unrecognizable packets instead of throwing an error + */ tolerant: true, - /** @property {Boolean} show_version Whether to include {@link module:config/config.versionstring} in armored messages */ + /** + * @memberof module:config + * @property {Boolean} show_version Whether to include {@link module:config/config.versionstring} in armored messages + */ show_version: true, - /** @property {Boolean} show_comment Whether to include {@link module:config/config.commentstring} in armored messages */ + /** + * @memberof module:config + * @property {Boolean} show_comment Whether to include {@link module:config/config.commentstring} in armored messages + */ show_comment: true, - /** @property {String} versionstring A version string to be included in armored messages */ + /** + * @memberof module:config + * @property {String} versionstring A version string to be included in armored messages + */ versionstring: "OpenPGP.js VERSION", - /** @property {String} commentstring A comment string to be included in armored messages */ + /** + * @memberof module:config + * @property {String} commentstring A comment string to be included in armored messages + */ commentstring: "https://openpgpjs.org", - /** @property {String} keyserver */ + /** + * @memberof module:config + * @property {String} keyserver + */ keyserver: "https://keyserver.ubuntu.com", - /** @property {String} node_store */ + /** + * @memberof module:config + * @property {String} node_store + */ node_store: "./openpgp.store" }; diff --git a/src/config/localStorage.js b/src/config/localStorage.js index 1bf61a1b..e6671e0a 100644 --- a/src/config/localStorage.js +++ b/src/config/localStorage.js @@ -1,4 +1,5 @@ /** + * @fileoverview Provides functions for storing and retrieving configuration from HTML5 local storage. * @module config/localStorage */ diff --git a/src/crypto/aes_kw.js b/src/crypto/aes_kw.js index 73a69f36..d82c5745 100644 --- a/src/crypto/aes_kw.js +++ b/src/crypto/aes_kw.js @@ -15,7 +15,13 @@ // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -// Implementation of RFC 3394 AES Key Wrap & Key Unwrap funcions +/** + * @fileoverview Implementation of RFC 3394 AES Key Wrap & Key Unwrap funcions + * @see module:crypto/public_key/elliptic/ecdh + * @requires crypto/cipher + * @requires util + * @module crypto/aes_kw + */ import cipher from './cipher'; import util from '../util'; @@ -127,6 +133,21 @@ function pack() { } export default { + /** + * AES key wrap + * @function + * @param {String} key + * @param {String} data + * @returns {Uint8Array} + */ wrap, + /** + * AES key unwrap + * @function + * @param {String} key + * @param {String} data + * @returns {Uint8Array} + * @throws {Error} + */ unwrap }; diff --git a/src/crypto/cfb.js b/src/crypto/cfb.js index e71446dd..87e3dbcf 100644 --- a/src/crypto/cfb.js +++ b/src/crypto/cfb.js @@ -27,8 +27,8 @@ import cipher from './cipher'; export default { /** - * This function encrypts a given with the specified prefixrandom - * using the specified blockcipher to encrypt a message + * This function encrypts a given plaintext with the specified prefixrandom + * using the specified blockcipher * @param {Uint8Array} prefixrandom random bytes of block_size length * to be used in prefixing the data * @param {String} cipherfn the algorithm cipher class to encrypt @@ -163,9 +163,9 @@ export default { result[iblock.length + 1] = ablock[1] ^ ciphertext[block_size + 1]; return result; }, + /** - * This function decrypts a given plaintext using the specified - * blockcipher to decrypt a message + * This function decrypts a given ciphertext using the specified blockcipher * @param {String} cipherfn the algorithm cipher class to decrypt * data in one block_size encryption, {@link module:crypto/cipher}. * @param {Uint8Array} key Uint8Array representation of key to be used to decrypt the ciphertext. @@ -177,7 +177,6 @@ export default { * encryptedintegrityprotecteddata packet is not resyncing the IV. * @returns {Uint8Array} the plaintext data */ - decrypt: function(cipherfn, key, ciphertext, resync) { cipherfn = new cipher[cipherfn](key); const block_size = cipherfn.blockSize; diff --git a/src/crypto/cipher/aes.js b/src/crypto/cipher/aes.js index 2049879d..55505cfd 100644 --- a/src/crypto/cipher/aes.js +++ b/src/crypto/cipher/aes.js @@ -1,6 +1,5 @@ /** * @requires asmcrypto.js - * @module crypto/cipher/aes */ import { AES_ECB } from 'asmcrypto.js/src/aes/ecb/exports'; diff --git a/src/crypto/cipher/blowfish.js b/src/crypto/cipher/blowfish.js index 35c476e5..e75e634f 100644 --- a/src/crypto/cipher/blowfish.js +++ b/src/crypto/cipher/blowfish.js @@ -3,10 +3,6 @@ * Originally written by nklein software (nklein.com) */ -/** - * @module crypto/cipher/blowfish - */ - /* * Javascript implementation based on Bruce Schneier's reference implementation. * @@ -387,7 +383,6 @@ Blowfish.prototype.init = function(key) { }; // added by Recurity Labs - function BF(key) { this.bf = new Blowfish(); this.bf.init(key); diff --git a/src/crypto/cipher/cast5.js b/src/crypto/cipher/cast5.js index 1304c277..821fb607 100644 --- a/src/crypto/cipher/cast5.js +++ b/src/crypto/cipher/cast5.js @@ -14,8 +14,6 @@ // CAST5 constructor -/** @module crypto/cipher/cast5 */ - function OpenpgpSymencCast5() { this.BlockSize = 8; this.KeySize = 16; diff --git a/src/crypto/cipher/des.js b/src/crypto/cipher/des.js index fd9ebab7..b8598e6c 100644 --- a/src/crypto/cipher/des.js +++ b/src/crypto/cipher/des.js @@ -21,10 +21,6 @@ //des //this takes the key, the message, and whether to encrypt or decrypt -/** - * @module crypto/cipher/des - */ - function des(keys, message, encrypt, mode, iv, padding) { //declaring this locally speeds things up a bit const spfunction1 = new Array( diff --git a/src/crypto/cipher/index.js b/src/crypto/cipher/index.js index 0f11a73d..4fc22641 100644 --- a/src/crypto/cipher/index.js +++ b/src/crypto/cipher/index.js @@ -15,21 +15,75 @@ import twofish from './twofish'; import blowfish from './blowfish'; export default { - /** @see module:crypto/cipher/aes */ + /** + * AES-128 encryption and decryption (ID 7) + * @function + * @param {String} key 128-bit key + * @see {@link https://github.com/asmcrypto/asmcrypto.js|asmCrypto} + * @see {@link https://csrc.nist.gov/publications/fips/fips197/fips-197.pdf|NIST FIPS-197} + * @returns {Object} + * @requires asmcrypto.js + */ aes128: aes(128), + /** + * AES-128 Block Cipher (ID 8) + * @function + * @param {String} key 192-bit key + * @see {@link https://github.com/asmcrypto/asmcrypto.js|asmCrypto} + * @see {@link https://csrc.nist.gov/publications/fips/fips197/fips-197.pdf|NIST FIPS-197} + * @returns {Object} + * @requires asmcrypto.js + */ aes192: aes(192), + /** + * AES-128 Block Cipher (ID 9) + * @function + * @param {String} key 256-bit key + * @see {@link https://github.com/asmcrypto/asmcrypto.js|asmCrypto} + * @see {@link https://csrc.nist.gov/publications/fips/fips197/fips-197.pdf|NIST FIPS-197} + * @returns {Object} + * @requires asmcrypto.js + */ aes256: aes(256), - /** @see module:crypto/cipher/des~DES */ + // Not in OpenPGP specifications des: des.DES, - /** @see module:crypto/cipher/des~TripleDES */ + /** + * Triple DES Block Cipher (ID 2) + * @function + * @param {String} key 192-bit key + * @see {@link https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-67r2.pdf|NIST SP 800-67} + * @returns {Object} + */ tripledes: des.TripleDES, - /** @see module:crypto/cipher/cast5 */ + /** + * CAST-128 Block Cipher (ID 3) + * @function + * @param {String} key 128-bit key + * @see {@link https://tools.ietf.org/html/rfc2144|The CAST-128 Encryption Algorithm} + * @returns {Object} + */ cast5: cast5, - /** @see module:crypto/cipher/twofish */ + /** + * Twofish Block Cipher (ID 10) + * @function + * @param {String} key 256-bit key + * @see {@link https://tools.ietf.org/html/rfc4880#ref-TWOFISH|TWOFISH} + * @returns {Object} + */ twofish: twofish, - /** @see module:crypto/cipher/blowfish */ + /** + * Blowfish Block Cipher (ID 4) + * @function + * @param {String} key 128-bit key + * @see {@link https://tools.ietf.org/html/rfc4880#ref-BLOWFISH|BLOWFISH} + * @returns {Object} + */ blowfish: blowfish, - /** Not implemented */ + /** + * Not implemented + * @function + * @throws {Error} + */ idea: function() { throw new Error('IDEA symmetric-key algorithm not implemented'); } diff --git a/src/crypto/cipher/twofish.js b/src/crypto/cipher/twofish.js index 1602ff23..2b3d77dd 100644 --- a/src/crypto/cipher/twofish.js +++ b/src/crypto/cipher/twofish.js @@ -1,3 +1,5 @@ +/* eslint-disable no-mixed-operators */ + /* Modified by Recurity Labs GmbH * * Cipher.js @@ -18,12 +20,6 @@ * */ -/** - * @module crypto/cipher/twofish - */ - - /* eslint-disable no-mixed-operators */ - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Math //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -339,22 +335,13 @@ function createTwofish() { function TF(key) { this.tf = createTwofish(); - this.tf.open(toArray(key), 0); + this.tf.open(Array.from(key), 0); this.encrypt = function(block) { - return this.tf.encrypt(toArray(block), 0); + return this.tf.encrypt(Array.from(block), 0); }; } -function toArray(typedArray) { - // Array.apply([], typedArray) does not work in PhantomJS 1.9 - const result = []; - for (let i = 0; i < typedArray.length; i++) { - result[i] = typedArray[i]; - } - return result; -} - TF.keySize = TF.prototype.keySize = 32; TF.blockSize = TF.prototype.blockSize = 16; diff --git a/src/crypto/crypto.js b/src/crypto/crypto.js index 377f88e7..9bc5f52e 100644 --- a/src/crypto/crypto.js +++ b/src/crypto/crypto.js @@ -18,6 +18,8 @@ // The GPG4Browsers crypto interface /** + * @fileoverview Provides functions for asymmetric encryption and decryption as + * well as key generation and parameter handling for all public-key cryptosystems. * @requires crypto/public_key * @requires crypto/cipher * @requires crypto/random diff --git a/src/crypto/hash/index.js b/src/crypto/hash/index.js index 269a050f..a8501a77 100644 --- a/src/crypto/hash/index.js +++ b/src/crypto/hash/index.js @@ -1,5 +1,8 @@ /** - * @fileoverview Hashing functions + * @fileoverview Provides an interface to hashing functions available in Node.js or external libraries. + * @see {@link https://github.com/srijs/rusha|Rusha} + * @see {@link https://github.com/asmcrypto/asmcrypto.js|asmCrypto} + * @see {@link https://github.com/indutny/hash.js|hash.js} * @requires rusha * @requires asmcrypto.js * @requires hash.js @@ -31,7 +34,7 @@ function node_hash(type) { function hashjs_hash(hash) { return function(data) { - return util.str_to_Uint8Array(util.hex_to_str(hash().update(data).digest('hex'))); + return util.hex_to_Uint8Array(hash().update(data).digest('hex')); }; } @@ -48,34 +51,34 @@ if (nodeCrypto) { // Use Node native crypto for all hash functions }; } else { // Use JS fallbacks hash_fns = { - /** @see module:./md5 */ md5: md5, - /** @see module:rusha */ sha1: function(data) { - return util.str_to_Uint8Array(util.hex_to_str(rusha.digest(data))); + return util.hex_to_Uint8Array(rusha.digest(data)); }, - /** @see module:hash.js */ sha224: hashjs_hash(sha224), - /** @see module:asmcrypto */ sha256: SHA256.bytes, - /** @see module:hash.js */ sha384: hashjs_hash(sha384), // TODO, benchmark this vs asmCrypto's SHA512 - /** @see module:hash.js */ sha512: hashjs_hash(sha512), - /** @see module:hash.js */ ripemd: hashjs_hash(ripemd160) }; } export default { + /** @see module:md5 */ md5: hash_fns.md5, + /** @see rusha */ sha1: hash_fns.sha1, + /** @see hash.js */ sha224: hash_fns.sha224, + /** @see asmCrypto */ sha256: hash_fns.sha256, + /** @see hash.js */ sha384: hash_fns.sha384, + /** @see hash.js */ sha512: hash_fns.sha512, + /** @see hash.js */ ripemd: hash_fns.ripemd, /** diff --git a/src/crypto/hash/md5.js b/src/crypto/hash/md5.js index 3a36ebf3..5b0e71f4 100644 --- a/src/crypto/hash/md5.js +++ b/src/crypto/hash/md5.js @@ -14,15 +14,11 @@ /** * @requires util - * @module crypto/hash/md5 */ import util from '../../util'; -/** - * MD5 hash - * @param {String} entree string to hash - */ +// MD5 Digest function md5(entree) { const digest = md51(util.Uint8Array_to_str(entree)); return util.hex_to_Uint8Array(hex(digest)); diff --git a/src/crypto/pkcs1.js b/src/crypto/pkcs1.js index 2fc05285..78f8901a 100644 --- a/src/crypto/pkcs1.js +++ b/src/crypto/pkcs1.js @@ -16,7 +16,10 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** - * PKCS1 encoding + * @fileoverview Provides EME-PKCS1-v1_5 encoding and decoding and EMSA-PKCS1-v1_5 encoding function + * @see module:crypto/public_key/rsa + * @see module:crypto/public_key/elliptic/ecdh + * @see module:packet/public_key_encrypted_session_key * @requires crypto/random * @requires crypto/hash * @requires util @@ -27,8 +30,14 @@ import random from './random'; import hash from './hash'; import util from '../util'; +/** @namespace */ +const eme = {}; +/** @namespace */ +const emsa = {}; + /** - * ASN1 object identifiers for hashes (See {@link https://tools.ietf.org/html/rfc4880#section-5.2.2}) + * ASN1 object identifiers for hashes + * @see {@link https://tools.ietf.org/html/rfc4880#section-5.2.2} */ const hash_headers = []; hash_headers[1] = [0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, @@ -65,100 +74,99 @@ async function getPkcs1Padding(length) { return result; } - -export default { - eme: { - /** - * create a EME-PKCS1-v1_5 padding (See {@link https://tools.ietf.org/html/rfc4880#section-13.1.1|RFC 4880 13.1.1}) - * @param {String} M message to be encoded - * @param {Integer} k the length in octets of the key modulus - * @returns {Promise} EME-PKCS1 padded message - * @async - */ - encode: async function(M, k) { - const mLen = M.length; - // length checking - if (mLen > k - 11) { - throw new Error('Message too long'); - } - // Generate an octet string PS of length k - mLen - 3 consisting of - // pseudo-randomly generated nonzero octets - const PS = await getPkcs1Padding(k - mLen - 3); - // Concatenate PS, the message M, and other padding to form an - // encoded message EM of length k octets as EM = 0x00 || 0x02 || PS || 0x00 || M. - return String.fromCharCode(0) + - String.fromCharCode(2) + - PS + - String.fromCharCode(0) + - M; - }, - /** - * decodes a EME-PKCS1-v1_5 padding (See {@link https://tools.ietf.org/html/rfc4880#section-13.1.2|RFC 4880 13.1.2}) - * @param {String} EM encoded message, an octet string - * @returns {String} message, an octet string - */ - decode: function(EM) { - // leading zeros truncated by bn.js - if (EM.charCodeAt(0) !== 0) { - EM = String.fromCharCode(0) + EM; - } - const firstOct = EM.charCodeAt(0); - const secondOct = EM.charCodeAt(1); - let i = 2; - while (EM.charCodeAt(i) !== 0 && i < EM.length) { - i++; - } - const psLen = i - 2; - const separator = EM.charCodeAt(i++); - if (firstOct === 0 && secondOct === 2 && psLen >= 8 && separator === 0) { - return EM.substr(i); - } - throw new Error('Decryption error'); - } - }, - - emsa: { - /** - * create a EMSA-PKCS1-v1_5 padding (See {@link https://tools.ietf.org/html/rfc4880#section-13.1.3|RFC 4880 13.1.3}) - * @param {Integer} algo Hash algorithm type used - * @param {String} M message to be encoded - * @param {Integer} emLen intended length in octets of the encoded message - * @returns {String} encoded message - */ - encode: function(algo, M, emLen) { - let i; - // Apply the hash function to the message M to produce a hash value H - const H = util.Uint8Array_to_str(hash.digest(algo, util.str_to_Uint8Array(M))); - if (H.length !== hash.getHashByteLength(algo)) { - throw new Error('Invalid hash length'); - } - // produce an ASN.1 DER value for the hash function used. - // Let T be the full hash prefix - let T = ''; - for (i = 0; i < hash_headers[algo].length; i++) { - T += String.fromCharCode(hash_headers[algo][i]); - } - // add hash value to prefix - T += H; - // and let tLen be the length in octets of T - const tLen = T.length; - if (emLen < tLen + 11) { - throw new Error('Intended encoded message length too short'); - } - // an octet string PS consisting of emLen - tLen - 3 octets with hexadecimal value 0xFF - // The length of PS will be at least 8 octets - let PS = ''; - for (i = 0; i < (emLen - tLen - 3); i++) { - PS += String.fromCharCode(0xff); - } - // Concatenate PS, the hash prefix T, and other padding to form the - // encoded message EM as EM = 0x00 || 0x01 || PS || 0x00 || T. - const EM = String.fromCharCode(0x00) + - String.fromCharCode(0x01) + - PS + - String.fromCharCode(0x00) + - T; - return util.str_to_hex(EM); - } +/** + * Create a EME-PKCS1-v1_5 padded message + * @see {@link https://tools.ietf.org/html/rfc4880#section-13.1.1|RFC 4880 13.1.1} + * @param {String} M message to be encoded + * @param {Integer} k the length in octets of the key modulus + * @returns {Promise} EME-PKCS1 padded message + * @async + */ +eme.encode = async function(M, k) { + const mLen = M.length; + // length checking + if (mLen > k - 11) { + throw new Error('Message too long'); } + // Generate an octet string PS of length k - mLen - 3 consisting of + // pseudo-randomly generated nonzero octets + const PS = await getPkcs1Padding(k - mLen - 3); + // Concatenate PS, the message M, and other padding to form an + // encoded message EM of length k octets as EM = 0x00 || 0x02 || PS || 0x00 || M. + return String.fromCharCode(0) + + String.fromCharCode(2) + + PS + + String.fromCharCode(0) + + M; }; + +/** + * Decode a EME-PKCS1-v1_5 padded message + * @see {@link https://tools.ietf.org/html/rfc4880#section-13.1.2|RFC 4880 13.1.2} + * @param {String} EM encoded message, an octet string + * @returns {String} message, an octet string + */ +eme.decode = function(EM) { + // leading zeros truncated by bn.js + if (EM.charCodeAt(0) !== 0) { + EM = String.fromCharCode(0) + EM; + } + const firstOct = EM.charCodeAt(0); + const secondOct = EM.charCodeAt(1); + let i = 2; + while (EM.charCodeAt(i) !== 0 && i < EM.length) { + i++; + } + const psLen = i - 2; + const separator = EM.charCodeAt(i++); + if (firstOct === 0 && secondOct === 2 && psLen >= 8 && separator === 0) { + return EM.substr(i); + } + throw new Error('Decryption error'); +}; + +/** + * Create a EMSA-PKCS1-v1_5 padded message + * @see {@link https://tools.ietf.org/html/rfc4880#section-13.1.3|RFC 4880 13.1.3} + * @param {Integer} algo Hash algorithm type used + * @param {String} M message to be encoded + * @param {Integer} emLen intended length in octets of the encoded message + * @returns {String} encoded message + */ +emsa.encode = function(algo, M, emLen) { + let i; + // Apply the hash function to the message M to produce a hash value H + const H = util.Uint8Array_to_str(hash.digest(algo, util.str_to_Uint8Array(M))); + if (H.length !== hash.getHashByteLength(algo)) { + throw new Error('Invalid hash length'); + } + // produce an ASN.1 DER value for the hash function used. + // Let T be the full hash prefix + let T = ''; + for (i = 0; i < hash_headers[algo].length; i++) { + T += String.fromCharCode(hash_headers[algo][i]); + } + // add hash value to prefix + T += H; + // and let tLen be the length in octets of T + const tLen = T.length; + if (emLen < tLen + 11) { + throw new Error('Intended encoded message length too short'); + } + // an octet string PS consisting of emLen - tLen - 3 octets with hexadecimal value 0xFF + // The length of PS will be at least 8 octets + let PS = ''; + for (i = 0; i < (emLen - tLen - 3); i++) { + PS += String.fromCharCode(0xff); + } + // Concatenate PS, the hash prefix T, and other padding to form the + // encoded message EM as EM = 0x00 || 0x01 || PS || 0x00 || T. + const EM = String.fromCharCode(0x00) + + String.fromCharCode(0x01) + + PS + + String.fromCharCode(0x00) + + T; + return util.str_to_hex(EM); +}; + +export default { eme, emsa }; diff --git a/src/crypto/pkcs5.js b/src/crypto/pkcs5.js index 6697842b..3bb7a125 100644 --- a/src/crypto/pkcs5.js +++ b/src/crypto/pkcs5.js @@ -15,7 +15,11 @@ // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -// Functions to add and remove PKCS5 padding +/** + * @fileoverview Functions to add and remove PKCS5 padding + * @see module:packet/public_key_encrypted_session_key + * @module crypto/pkcs5 + */ /** * Add pkcs5 padding to a text. diff --git a/src/crypto/public_key/index.js b/src/crypto/public_key/index.js index d3cd1012..bd8656ff 100644 --- a/src/crypto/public_key/index.js +++ b/src/crypto/public_key/index.js @@ -1,24 +1,24 @@ /** * @fileoverview Asymmetric cryptography functions - * @see module:crypto/public_key/dsa - * @see module:crypto/public_key/elgamal - * @see module:crypto/public_key/elliptic - * @see module:crypto/public_key/rsa + * @requires crypto/public_key/dsa + * @requires crypto/public_key/elgamal + * @requires crypto/public_key/elliptic + * @requires crypto/public_key/rsa * @module crypto/public_key */ -/** @see module:crypto/public_key/rsa */ import rsa from './rsa'; -/** @see module:crypto/public_key/elgamal */ import elgamal from './elgamal'; -/** @see module:crypto/public_key/elliptic */ import elliptic from './elliptic'; -/** @see module:crypto/public_key/dsa */ import dsa from './dsa'; export default { + /** @see module:crypto/public_key/rsa */ rsa: rsa, + /** @see module:crypto/public_key/elgamal */ elgamal: elgamal, + /** @see module:crypto/public_key/elliptic */ elliptic: elliptic, + /** @see module:crypto/public_key/dsa */ dsa: dsa }; diff --git a/src/crypto/public_key/rsa.js b/src/crypto/public_key/rsa.js index 9a02795b..219962b3 100644 --- a/src/crypto/public_key/rsa.js +++ b/src/crypto/public_key/rsa.js @@ -49,11 +49,11 @@ function promisifyIE11Op(keyObj, err) { export default { /** Create signature - * @param m message as BN - * @param n public MPI part as BN - * @param e public MPI part as BN - * @param d private MPI part as BN - * @returns BN + * @param {BN} m message + * @param {BN} n RSA public modulus + * @param {BN} e RSA public exponent + * @param {BN} d RSA private exponent + * @returns {BN} RSA Signature * @async */ sign: async function(m, n, e, d) { @@ -66,10 +66,10 @@ export default { /** * Verify signature - * @param s signature as BN - * @param n public MPI part as BN - * @param e public MPI part as BN - * @returns BN + * @param {BN} s signature + * @param {BN} n RSA public modulus + * @param {BN} e RSA public exponent + * @returns {BN} * @async */ verify: async function(s, n, e) { @@ -82,10 +82,10 @@ export default { /** * Encrypt message - * @param m message as BN - * @param n public MPI part as BN - * @param e public MPI part as BN - * @returns BN + * @param {BN} m message + * @param {BN} n RSA public modulus + * @param {BN} e RSA public exponent + * @returns {BN} RSA Ciphertext * @async */ encrypt: async function(m, n, e) { @@ -98,14 +98,14 @@ export default { /** * Decrypt RSA message - * @param m message as BN - * @param n RSA public modulus n as BN - * @param e RSA public exponent as BN - * @param d RSA d as BN - * @param p RSA p as BN - * @param q RSA q as BN - * @param u RSA u as BN - * @returns {BN} The decrypted value of the message + * @param {BN} m message + * @param {BN} n RSA public modulus + * @param {BN} e RSA public exponent + * @param {BN} d RSA private exponent + * @param {BN} p RSA private prime p + * @param {BN} q RSA private prime q + * @param {BN} u RSA private inverse of prime q + * @returns {BN} RSA Plaintext * @async */ decrypt: async function(m, n, e, d, p, q, u) { @@ -141,7 +141,11 @@ export default { }, /** - * Generate a new random private key B bits long with public exponent E + * Generate a new random private key B bits long with public exponent E. + * + * When possible, webCrypto is used. Otherwise, primes are generated using + * 40 rounds of the Miller-Rabin probabilistic random prime generation algorithm. + * @see module:crypto/public_key/prime * @param {Integer} B RSA bit length * @param {String} E RSA public exponent in hex string * @returns {{n: BN, e: BN, d: BN, diff --git a/src/crypto/random.js b/src/crypto/random.js index 11532473..b4dc75ea 100644 --- a/src/crypto/random.js +++ b/src/crypto/random.js @@ -18,6 +18,7 @@ // The GPG4Browsers crypto interface /** + * @fileoverview Provides tools for retrieving secure randomness from browsers or Node.js * @requires bn.js * @requires type/mpi * @requires util diff --git a/src/crypto/signature.js b/src/crypto/signature.js index edcf247e..41866c4e 100644 --- a/src/crypto/signature.js +++ b/src/crypto/signature.js @@ -1,4 +1,5 @@ /** + * @fileoverview Provides functions for asymmetric signing and signature verification * @requires bn.js * @requires crypto/public_key * @requires crypto/pkcs1 @@ -24,7 +25,7 @@ export default { * @param {Array} msg_MPIs Algorithm-specific signature parameters * @param {Array} pub_MPIs Algorithm-specific public key parameters * @param {Uint8Array} data Data for which the signature was created - * @returns {Boolean} True if signature is valid + * @returns {Boolean} True if signature is valid * @async */ verify: async function(algo, hash_algo, msg_MPIs, pub_MPIs, data) { @@ -77,7 +78,7 @@ export default { * @param {module:enums.hash} hash_algo Hash algorithm * @param {Array} key_params Algorithm-specific public and private key parameters * @param {Uint8Array} data Data to be signed - * @returns {Uint8Array} Signature + * @returns {Uint8Array} Signature * @async */ sign: async function(algo, hash_algo, key_params, data) { diff --git a/src/keyring/keyring.js b/src/keyring/keyring.js index 7461a655..3284dcfe 100644 --- a/src/keyring/keyring.js +++ b/src/keyring/keyring.js @@ -16,6 +16,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** + * @fileoverview Provides the Keyring class * @requires key * @requires keyring/localstore * @module keyring/keyring diff --git a/src/keyring/localstore.js b/src/keyring/localstore.js index 7a45818d..fe8e075c 100644 --- a/src/keyring/localstore.js +++ b/src/keyring/localstore.js @@ -16,6 +16,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** + * @fileoverview Provides the LocalStore class * @requires config * @requires key * @requires util diff --git a/src/packet/all_packets.js b/src/packet/all_packets.js index ebdc1077..f54b0e67 100644 --- a/src/packet/all_packets.js +++ b/src/packet/all_packets.js @@ -1,6 +1,6 @@ /** * @requires enums - * @module packet + * @module packet/all_packets */ import enums from '../enums.js'; diff --git a/src/packet/packet.js b/src/packet/packet.js index 1060d5a4..f3290796 100644 --- a/src/packet/packet.js +++ b/src/packet/packet.js @@ -16,6 +16,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /** + * @fileoverview Functions for reading and writing packets * @requires enums * @requires util * @module packet/packet diff --git a/src/packet/packetlist.js b/src/packet/packetlist.js index 9c463524..d2d34761 100644 --- a/src/packet/packetlist.js +++ b/src/packet/packetlist.js @@ -1,5 +1,6 @@ /* eslint-disable callback-return */ /** + * @fileoverview Provides a class for representing lists of OpenPGP packets. * @requires util * @requires enums * @requires packet diff --git a/src/packet/public_key.js b/src/packet/public_key.js index f51efab3..db058770 100644 --- a/src/packet/public_key.js +++ b/src/packet/public_key.js @@ -36,6 +36,8 @@ import type_keyid from '../type/keyid'; import type_mpi from '../type/mpi'; /** + * A Public-Key packet starts a series of packets that forms an OpenPGP + * key (sometimes called an OpenPGP certificate). * @constructor */ function PublicKey() { @@ -159,7 +161,7 @@ PublicKey.prototype.getKeyId = function () { } this.keyid = new type_keyid(); if (this.version === 4) { - this.keyid.read(util.str_to_Uint8Array(util.hex_to_str(this.getFingerprint()).substr(12, 8))); + this.keyid.read(util.hex_to_Uint8Array(this.getFingerprint()).subarray(12, 20)); } else if (this.version === 3) { const arr = this.params[0].write(); this.keyid.read(arr.subarray(arr.length - 8, arr.length)); diff --git a/src/packet/public_subkey.js b/src/packet/public_subkey.js index 6f38b68e..75f0f228 100644 --- a/src/packet/public_subkey.js +++ b/src/packet/public_subkey.js @@ -25,6 +25,11 @@ import publicKey from './public_key.js'; import enums from '../enums.js'; /** + * A Public-Subkey packet (tag 14) has exactly the same format as a + * Public-Key packet, but denotes a subkey. One or more subkeys may be + * associated with a top-level key. By convention, the top-level key + * provides signature services, and the subkeys provide encryption + * services. * @constructor * @extends module:packet/public_key */ diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js index 2d22a283..bc7a024e 100644 --- a/src/packet/secret_key.js +++ b/src/packet/secret_key.js @@ -39,6 +39,9 @@ import type_s2k from '../type/s2k.js'; import type_keyid from '../type/keyid.js'; /** + * A Secret-Key packet contains all the information that is found in a + * Public-Key packet, including the public-key material, but also + * includes the secret-key material after all the public-key fields. * @constructor * @extends module:packet/public_key */ diff --git a/src/packet/secret_subkey.js b/src/packet/secret_subkey.js index 3423a980..f88ade59 100644 --- a/src/packet/secret_subkey.js +++ b/src/packet/secret_subkey.js @@ -25,6 +25,8 @@ import secretKey from './secret_key.js'; import enums from '../enums.js'; /** + * A Secret-Subkey packet (tag 7) is the subkey analog of the Secret + * Key packet and has exactly the same format. * @constructor * @extends module:packet/secret_key */ diff --git a/src/packet/sym_encrypted_aead_protected.js b/src/packet/sym_encrypted_aead_protected.js index 4e2449fb..cc98f965 100644 --- a/src/packet/sym_encrypted_aead_protected.js +++ b/src/packet/sym_encrypted_aead_protected.js @@ -21,17 +21,21 @@ * * {@link https://tools.ietf.org/html/draft-ford-openpgp-format-00#section-2.1}: * AEAD Protected Data Packet + * @requires crypto + * @requires enums + * @requires util + * @module packet/sym_encrypted_aead_protected */ -import util from '../util'; import crypto from '../crypto'; import enums from '../enums'; +import util from '../util'; const VERSION = 1; // A one-octet version number of the data packet. const IV_LEN = crypto.gcm.ivLength; // currently only AES-GCM is supported /** - * @class + * @constructor */ function SymEncryptedAEADProtected() { this.tag = enums.packet.symEncryptedAEADProtected; diff --git a/src/packet/trust.js b/src/packet/trust.js index 9877ec89..d251f24a 100644 --- a/src/packet/trust.js +++ b/src/packet/trust.js @@ -1,4 +1,17 @@ /** + * Implementation of the Trust Packet (Tag 12) + * + * {@link https://tools.ietf.org/html/rfc4880#section-5.10|RFC4880 5.10}: + * The Trust packet is used only within keyrings and is not normally + * exported. Trust packets contain data that record the user's + * specifications of which key holders are trustworthy introducers, + * along with other information that implementing software uses for + * trust information. The format of Trust packets is defined by a given + * implementation. + * + * Trust packets SHOULD NOT be emitted to output streams that are + * transferred to other users, and they SHOULD be ignored on any input + * other than local keyring files. * @requires enums * @module packet/trust */ diff --git a/src/type/keyid.js b/src/type/keyid.js index c7f77cce..d962b30b 100644 --- a/src/type/keyid.js +++ b/src/type/keyid.js @@ -81,7 +81,7 @@ Keyid.fromClone = function (clone) { Keyid.fromId = function (hex) { const keyid = new Keyid(); - keyid.read(util.str_to_Uint8Array(util.hex_to_str(hex))); + keyid.read(util.hex_to_Uint8Array(hex)); return keyid; }; diff --git a/src/util.js b/src/util.js index 3bf569df..a9afee83 100644 --- a/src/util.js +++ b/src/util.js @@ -23,9 +23,10 @@ */ import config from './config'; +import util from './util'; // re-import module to access util functions import b64 from './encoding/base64'; -const util = { +export default { isString: function(data) { return typeof data === 'string' || String.prototype.isPrototypeOf(data); @@ -534,5 +535,3 @@ const util = { return /$/.test(data); } }; - -export default util; diff --git a/src/worker/async_proxy.js b/src/worker/async_proxy.js index 6d13b3ba..2c08e242 100644 --- a/src/worker/async_proxy.js +++ b/src/worker/async_proxy.js @@ -15,6 +15,18 @@ // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/** + * @fileoverview Provides functions for maintaining browser workers + * @see module:openpgp.initWorker + * @see module:openpgp.getWorker + * @see module:openpgp.destroyWorker + * @see module:worker/worker + * @requires util + * @requires crypto + * @requires packet + * @module worker/async_proxy + */ + import util from '../util.js'; import crypto from '../crypto'; import packet from '../packet'; @@ -98,6 +110,7 @@ AsyncProxy.prototype.getID = function() { /** * Send message to worker with random data * @param {Integer} size Number of bytes to send + * @async */ AsyncProxy.prototype.seedRandom = async function(workerId, size) { const buf = await crypto.random.getRandomBytes(size); @@ -118,6 +131,7 @@ AsyncProxy.prototype.terminate = function() { * @param {String} method the public api function to be delegated to the worker thread * @param {Object} options the api function's options * @returns {Promise} see the corresponding public api functions for their return types + * @async */ AsyncProxy.prototype.delegate = function(method, options) { diff --git a/src/worker/worker.js b/src/worker/worker.js index 2c595cf9..6e6f3d6a 100644 --- a/src/worker/worker.js +++ b/src/worker/worker.js @@ -19,6 +19,15 @@ /* eslint-disable no-var */ /* eslint-disable vars-on-top */ +/** + * @fileoverview Provides functions for communicating with workers + * @see module:openpgp.initWorker + * @see module:openpgp.getWorker + * @see module:openpgp.destroyWorker + * @see module:worker/async_proxy + * @module worker/worker + */ + self.window = {}; // to make UMD bundles work importScripts('openpgp.js');