rsa-oaep-encryption
Version:
Pure JavaScript implementation of encryption using the RSA-OAEP algorithm without relying on the Web Crypto API.
1 lines • 214 kB
Source Map (JSON)
{"version":3,"file":"main.cjs","sources":["../src/lib/ByteStringBuffer.ts","../src/lib/asn1.ts","../src/lib/jsbn.ts","../src/lib/util.ts","../src/lib/pem.ts","../src/lib/aes.ts","../src/lib/prng.ts","../src/lib/sha256.ts","../src/lib/random.ts","../src/lib/pkcs1.ts","../src/lib/rsa.ts","../src/lib/sha1.ts","../src/lib/sha512.ts","../src/mod.ts"],"sourcesContent":["/**\n * Constructor for a binary string backed byte buffer.\n *\n * @param [b] the bytes to wrap (either encoded as string, one byte per\n * character, or as an ArrayBuffer or Typed Array).\n */\nexport class ByteStringBuffer {\n // used for v8 optimization\n private _constructedStringLength = 0;\n private data = '';\n\n read = 0;\n\n constructor(b?: string) {\n if (typeof b === 'string') {\n this.data = b;\n }\n }\n\n /* Note: This is an optimization for V8-based browsers. When V8 concatenates\n a string, the strings are only joined logically using a \"cons string\" or\n \"constructed/concatenated string\". These containers keep references to one\n another and can result in very large memory usage. For example, if a 2MB\n string is constructed by concatenating 4 bytes together at a time, the\n memory usage will be ~44MB; so ~22x increase. The strings are only joined\n together when an operation requiring their joining takes place, such as\n substr(). This function is called when adding data to this buffer to ensure\n these types of strings are periodically joined to reduce the memory\n footprint. */\n private _optimizeConstructedString(x: number): void {\n this._constructedStringLength += x;\n }\n\n /**\n * Gets the number of bytes in this buffer.\n *\n * @return the number of bytes in this buffer.\n */\n length(): number {\n return this.data.length - this.read;\n }\n\n /**\n * Puts a byte in this buffer.\n *\n * @param b the byte to put.\n *\n * @return this buffer.\n */\n putByte(b: number): this {\n return this.putBytes(String.fromCharCode(b));\n }\n\n /**\n * Puts bytes in this buffer.\n *\n * @param bytes the bytes (as a binary encoded string) to put.\n *\n * @return this buffer.\n */\n putBytes(bytes: string): this {\n this.data += bytes;\n this._optimizeConstructedString(bytes.length);\n return this;\n }\n\n /**\n * Puts a 32-bit integer in this buffer in big-endian order.\n *\n * @param i the 32-bit integer.\n *\n * @return this buffer.\n */\n putInt32(i: number): this {\n return this.putBytes(\n String.fromCharCode(i >> 24 & 0xFF) +\n String.fromCharCode(i >> 16 & 0xFF) +\n String.fromCharCode(i >> 8 & 0xFF) +\n String.fromCharCode(i & 0xFF));\n }\n\n /**\n * Gets a byte from this buffer and advances the read pointer by 1.\n *\n * @return the byte.\n */\n getByte(): number {\n return this.data.charCodeAt(this.read++);\n }\n\n /**\n * Gets a uint32 from this buffer in big-endian order and advances the read\n * pointer by 4.\n *\n * @return the word.\n */\n getInt32(): number {\n const rval = (\n this.data.charCodeAt(this.read) << 24 ^\n this.data.charCodeAt(this.read + 1) << 16 ^\n this.data.charCodeAt(this.read + 2) << 8 ^\n this.data.charCodeAt(this.read + 3));\n this.read += 4;\n return rval;\n }\n\n /**\n * Gets an n-bit integer from this buffer in big-endian order and advances the\n * read pointer by ceil(n/8).\n *\n * @param n the number of bits in the integer (8, 16, 24, or 32).\n *\n * @return the integer.\n */\n getInt(n: 8 | 16 | 24 | 32): number {\n let rval = 0;\n do {\n // TODO: Use (rval * 0x100) if adding support for 33 to 53 bits.\n rval = (rval << 8) + this.data.charCodeAt(this.read++);\n n -= 8;\n } while (n > 0);\n return rval;\n }\n\n /**\n * Reads bytes out as a binary encoded string and clears them from the\n * buffer. Note that the resulting string is binary encoded (in node.js this\n * encoding is referred to as `binary`, it is *not* `utf8`).\n *\n * @param count the number of bytes to read, undefined or null for all.\n *\n * @return a binary encoded string of bytes.\n */\n getBytes(count?: number): string {\n let rval: string;\n if (count) {\n // read count bytes\n count = Math.min(this.length(), count);\n rval = this.data.slice(this.read, this.read + count);\n this.read += count;\n } else if (count === 0) {\n rval = '';\n } else {\n // read all bytes, optimize to only copy when needed\n rval = this.data;\n this.clear();\n }\n return rval;\n }\n\n /**\n * Gets a binary encoded string of the bytes from this buffer without\n * modifying the read pointer.\n *\n * @param count the number of bytes to get, omit to get all.\n *\n * @return a string full of binary encoded characters.\n */\n bytes(count?: number): string {\n return typeof count === 'number'\n ? this.data.slice(this.read, this.read + count)\n : this.data.slice(this.read);\n }\n\n /**\n * Gets a byte at the given index without modifying the read pointer.\n *\n * @param i the byte index.\n *\n * @return the byte.\n */\n at(i: number): number {\n return this.data.charCodeAt(this.read + i);\n }\n\n /**\n * Compacts this buffer.\n *\n * @return this buffer.\n */\n compact(): this {\n if (this.read > 0) {\n this.data = this.data.slice(this.read);\n this.read = 0;\n }\n return this;\n }\n\n /**\n * Clears this buffer.\n *\n * @return this buffer.\n */\n clear(): this {\n this.data = '';\n this.read = 0;\n return this;\n }\n\n /**\n * Converts this buffer to a hexadecimal string.\n *\n * @return a hexadecimal string.\n */\n toHex(): string {\n let rval = '';\n for (let i = this.read; i < this.data.length; ++i) {\n const b = this.data.charCodeAt(i);\n if (b < 16) {\n rval += '0';\n }\n rval += b.toString(16);\n }\n return rval;\n }\n\n /**\n * Converts this buffer to an ArrayBuffer.\n *\n * @return An ArrayBuffer.\n */\n toArrayBuffer(): ArrayBuffer {\n const ab = new ArrayBuffer(this.length());\n const u8a = new Uint8Array(ab);\n\n for (let i = this.read; i < this.data.length; ++i) {\n u8a[i] = this.data.charCodeAt(i);\n }\n\n return ab;\n }\n}","/**\n * Javascript implementation of Abstract Syntax Notation Number One.\n *\n * @author Dave Longley\n *\n * Copyright (c) 2010-2015 Digital Bazaar, Inc.\n *\n * An API for storing data using the Abstract Syntax Notation Number One\n * format using DER (Distinguished Encoding Rules) encoding. This encoding is\n * commonly used to store data for PKI, i.e. X.509 Certificates, and this\n * implementation exists for that purpose.\n *\n * Abstract Syntax Notation Number One (ASN.1) is used to define the abstract\n * syntax of information without restricting the way the information is encoded\n * for transmission. It provides a standard that allows for open systems\n * communication. ASN.1 defines the syntax of information data and a number of\n * simple data types as well as a notation for describing them and specifying\n * values for them.\n *\n * The RSA algorithm creates public and private keys that are often stored in\n * X.509 or PKCS#X formats -- which use ASN.1 (encoded in DER format). This\n * class provides the most basic functionality required to store and load DSA\n * keys that are encoded according to ASN.1.\n *\n * The most common binary encodings for ASN.1 are BER (Basic Encoding Rules)\n * and DER (Distinguished Encoding Rules). DER is just a subset of BER that\n * has stricter requirements for how data must be encoded.\n *\n * Each ASN.1 structure has a tag (a byte identifying the ASN.1 structure type)\n * and a byte array for the value of this ASN1 structure which may be data or a\n * list of ASN.1 structures.\n *\n * Each ASN.1 structure using BER is (Tag-Length-Value):\n *\n * | byte 0 | bytes X | bytes Y |\n * |--------|---------|----------\n * | tag | length | value |\n *\n * ASN.1 allows for tags to be of \"High-tag-number form\" which allows a tag to\n * be two or more octets, but that is not supported by this class. A tag is\n * only 1 byte. Bits 1-5 give the tag number (ie the data type within a\n * particular 'class'), 6 indicates whether or not the ASN.1 value is\n * constructed from other ASN.1 values, and bits 7 and 8 give the 'class'. If\n * bits 7 and 8 are both zero, the class is UNIVERSAL. If only bit 7 is set,\n * then the class is APPLICATION. If only bit 8 is set, then the class is\n * CONTEXT_SPECIFIC. If both bits 7 and 8 are set, then the class is PRIVATE.\n * The tag numbers for the data types for the class UNIVERSAL are listed below:\n *\n * UNIVERSAL 0 Reserved for use by the encoding rules\n * UNIVERSAL 1 Boolean type\n * UNIVERSAL 2 Integer type\n * UNIVERSAL 3 Bitstring type\n * UNIVERSAL 4 Octetstring type\n * UNIVERSAL 5 Null type\n * UNIVERSAL 6 Object identifier type\n * UNIVERSAL 7 Object descriptor type\n * UNIVERSAL 8 External type and Instance-of type\n * UNIVERSAL 9 Real type\n * UNIVERSAL 10 Enumerated type\n * UNIVERSAL 11 Embedded-pdv type\n * UNIVERSAL 12 UTF8String type\n * UNIVERSAL 13 Relative object identifier type\n * UNIVERSAL 14-15 Reserved for future editions\n * UNIVERSAL 16 Sequence and Sequence-of types\n * UNIVERSAL 17 Set and Set-of types\n * UNIVERSAL 18-22, 25-30 Character string types\n * UNIVERSAL 23-24 Time types\n *\n * The length of an ASN.1 structure is specified after the tag identifier.\n * There is a definite form and an indefinite form. The indefinite form may\n * be used if the encoding is constructed and not all immediately available.\n * The indefinite form is encoded using a length byte with only the 8th bit\n * set. The end of the constructed object is marked using end-of-contents\n * octets (two zero bytes).\n *\n * The definite form looks like this:\n *\n * The length may take up 1 or more bytes, it depends on the length of the\n * value of the ASN.1 structure. DER encoding requires that if the ASN.1\n * structure has a value that has a length greater than 127, more than 1 byte\n * will be used to store its length, otherwise just one byte will be used.\n * This is strict.\n *\n * In the case that the length of the ASN.1 value is less than 127, 1 octet\n * (byte) is used to store the \"short form\" length. The 8th bit has a value of\n * 0 indicating the length is \"short form\" and not \"long form\" and bits 7-1\n * give the length of the data. (The 8th bit is the left-most, most significant\n * bit: also known as big endian or network format).\n *\n * In the case that the length of the ASN.1 value is greater than 127, 2 to\n * 127 octets (bytes) are used to store the \"long form\" length. The first\n * byte's 8th bit is set to 1 to indicate the length is \"long form.\" Bits 7-1\n * give the number of additional octets. All following octets are in base 256\n * with the most significant digit first (typical big-endian binary unsigned\n * integer storage). So, for instance, if the length of a value was 257, the\n * first byte would be set to:\n *\n * 10000010 = 130 = 0x82.\n *\n * This indicates there are 2 octets (base 256) for the length. The second and\n * third bytes (the octets just mentioned) would store the length in base 256:\n *\n * octet 2: 00000001 = 1 * 256^1 = 256\n * octet 3: 00000001 = 1 * 256^0 = 1\n * total = 257\n *\n * The algorithm for converting a js integer value of 257 to base-256 is:\n *\n * const value = 257;\n * const bytes = [];\n * bytes[0] = (value >>> 8) & 0xFF; // most significant byte first\n * bytes[1] = value & 0xFF; // least significant byte last\n *\n * On the ASN.1 UNIVERSAL Object Identifier (OID) type:\n *\n * An OID can be written like: \"value1.value2.value3...valueN\"\n *\n * The DER encoding rules:\n *\n * The first byte has the value 40 * value1 + value2.\n * The following bytes, if any, encode the remaining values. Each value is\n * encoded in base 128, most significant digit first (big endian), with as\n * few digits as possible, and the most significant bit of each byte set\n * to 1 except the last in each value's encoding. For example: Given the\n * OID \"1.2.840.113549\", its DER encoding is (remember each byte except the\n * last one in each encoding is OR'd with 0x80):\n *\n * byte 1: 40 * 1 + 2 = 42 = 0x2A.\n * bytes 2-3: 128 * 6 + 72 = 840 = 6 72 = 6 72 = 0x0648 = 0x8648\n * bytes 4-6: 16384 * 6 + 128 * 119 + 13 = 6 119 13 = 0x06770D = 0x86F70D\n *\n * The final value is: 0x2A864886F70D.\n * The full OID (including ASN.1 tag and length of 6 bytes) is:\n * 0x06062A864886F70D\n */\n\nimport { ByteStringBuffer } from './ByteStringBuffer.ts';\n\nexport interface ASN1 {\n constructed: boolean;\n tagClass: number;\n type: number;\n value: string | ASN1[],\n bitStringContents?: string;\n}\n\ninterface Validator {\n constructed: boolean;\n tagClass: number;\n type: number;\n value?: Validator[];\n}\n\n/**\n * ASN.1 classes.\n */\nconst Class = {\n UNIVERSAL: 0x00,\n APPLICATION: 0x40,\n CONTEXT_SPECIFIC: 0x80,\n PRIVATE: 0xC0,\n} as const;\n\n/**\n * ASN.1 types. Not all types are supported by this implementation, only\n * those necessary to implement a simple PKI are implemented.\n */\nconst Type = {\n NONE: 0,\n BOOLEAN: 1,\n INTEGER: 2,\n BITSTRING: 3,\n OCTETSTRING: 4,\n NULL: 5,\n OID: 6,\n ODESC: 7,\n EXTERNAL: 8,\n REAL: 9,\n ENUMERATED: 10,\n EMBEDDED: 11,\n UTF8: 12,\n ROID: 13,\n SEQUENCE: 16,\n SET: 17,\n PRINTABLESTRING: 19,\n IA5STRING: 22,\n UTCTIME: 23,\n GENERALIZEDTIME: 24,\n BMPSTRING: 30,\n} as const;\n\n// validator for an RSA public key\nconst RSAPublicKeyValidator = {\n // RSAPublicKey\n // name: 'RSAPublicKey',\n tagClass: Class.UNIVERSAL,\n type: Type.SEQUENCE,\n constructed: true,\n value: [{\n // modulus (n)\n // name: 'RSAPublicKey.modulus',\n tagClass: Class.UNIVERSAL,\n type: Type.INTEGER,\n constructed: false,\n // capture: 'publicKeyModulus'\n }, {\n // publicExponent (e)\n // name: 'RSAPublicKey.exponent',\n tagClass: Class.UNIVERSAL,\n type: Type.INTEGER,\n constructed: false,\n // capture: 'publicKeyExponent'\n }]\n};\n\n// validator for an SubjectPublicKeyInfo structure\n// Note: Currently only works with an RSA public key\nconst PublicKeyValidator = {\n // name: 'SubjectPublicKeyInfo',\n tagClass: Class.UNIVERSAL,\n type: Type.SEQUENCE,\n constructed: true,\n // captureAsn1: 'subjectPublicKeyInfo',\n value: [{\n // name: 'SubjectPublicKeyInfo.AlgorithmIdentifier',\n tagClass: Class.UNIVERSAL,\n type: Type.SEQUENCE,\n constructed: true,\n value: [{\n tagClass: Class.UNIVERSAL,\n type: Type.NULL,\n constructed: false,\n }, {\n // name: 'AlgorithmIdentifier.algorithm',\n tagClass: Class.UNIVERSAL,\n type: Type.OID,\n constructed: false,\n // capture: 'publicKeyOid'\n }]\n }, {\n // subjectPublicKey\n // name: 'SubjectPublicKeyInfo.subjectPublicKey',\n tagClass: Class.UNIVERSAL,\n type: Type.BITSTRING,\n constructed: false,\n value: [{\n // RSAPublicKey\n // name: 'SubjectPublicKeyInfo.subjectPublicKey.RSAPublicKey',\n tagClass: Class.UNIVERSAL,\n type: Type.SEQUENCE,\n constructed: true,\n // optional: true,\n // captureAsn1: 'rsaPublicKey'\n }]\n }]\n};\n\n/**\n * Deconstructing a public key from an ASN.1 object.\n * @param obj the ASN.1 object to deconstruct.\n * @returns publicKeyOid and rsaPublicKey or null when the object is invalid.\n */\nexport function deconstructPublicKey(obj: ASN1) {\n if (validate(obj, PublicKeyValidator) && PublicKeyValidator.value.every((x, i) => {\n return validate(obj.value[i] as ASN1, x);\n })) {\n return {\n publicKeyOid: ((obj.value[0] as ASN1).value[0] as ASN1).value as string,\n rsaPublicKey: (obj.value[1] as ASN1).value[0] as ASN1,\n };\n }\n\n return null;\n}\n\n/**\n * Deconstructing a RSA public key from an ASN.1 object.\n * @param obj the ASN.1 object to deconstruct.\n * @returns publicKeyModulus and publicKeyExponent or null when the object is invalid.\n */\nexport function deconstructRSAPublicKey(obj: ASN1) {\n if (validate(obj, RSAPublicKeyValidator) && RSAPublicKeyValidator.value.every((x, i) => {\n return validate(obj.value[i] as ASN1, x);\n })) {\n return {\n publicKeyModulus: (obj.value[0] as ASN1).value as string,\n publicKeyExponent: (obj.value[1] as ASN1).value as string,\n };\n }\n\n return null;\n}\n\n/**\n * Validates that the given ASN.1 object is at least a super set of the\n * given ASN.1 structure. Only tag classes and types are checked. An\n * optional map may also be provided to capture ASN.1 values while the\n * structure is checked.\n *\n * To capture an ASN.1 value, set an object in the validator's 'capture'\n * parameter to the key to use in the capture map. To capture the full\n * ASN.1 object, specify 'captureAsn1'. To capture BIT STRING bytes, including\n * the leading unused bits counter byte, specify 'captureBitStringContents'.\n * To capture BIT STRING bytes, without the leading unused bits counter byte,\n * specify 'captureBitStringValue'.\n *\n * Objects in the validator may set a field 'optional' to true to indicate\n * that it isn't necessary to pass validation.\n *\n * @param obj the ASN.1 object to validate.\n * @param v the ASN.1 structure validator.\n *\n * @return true on success, false on failure.\n */\nfunction validate(obj: ASN1, v: Validator): boolean {\n return obj.tagClass === v.tagClass\n && obj.type === v.type\n // ensure constructed flag is the same if specified\n && obj.constructed === v.constructed\n && (!v.value || obj.value.length === v.value.length);\n}\n\n/**\n * Parses an asn1 object from a byte buffer in DER format.\n *\n * @param bytes the byte buffer to parse from.\n * @param [strict] true to be strict when checking value lengths, false to\n * allow truncated values (default: true).\n * @param [options] object with options or boolean strict flag\n * [strict] true to be strict when checking value lengths, false to\n * allow truncated values (default: true).\n * [decodeBitStrings] true to attempt to decode the content of\n * BIT STRINGs (not OCTET STRINGs) using strict mode. Note that\n * without schema support to understand the data context this can\n * erroneously decode values that happen to be valid ASN.1. This\n * flag will be deprecated or removed as soon as schema support is\n * available. (default: true)\n *\n * @throws Will throw an error for various malformed input conditions.\n *\n * @return the parsed asn1 object.\n */\nexport function fromDer(bytes: string): ASN1 {\n const value = _fromDer(new ByteStringBuffer(bytes), 0, {\n strict: true,\n decodeBitStrings: true,\n });\n return value;\n}\n\n/**\n * Converts a DER-encoded byte buffer to an OID dot-separated string. The\n * byte buffer should contain only the DER-encoded value, not any tag or\n * length bytes.\n *\n * @param bytes the byte buffer.\n *\n * @return the OID dot-separated string.\n */\nexport function derToOid(bytes: string): string {\n const buffer = new ByteStringBuffer(bytes);\n\n // first byte is 40 * value1 + value2\n let b = buffer.getByte();\n let oid = Math.floor(b / 40) + '.' + (b % 40);\n\n // other bytes are each value in base 128 with 8th bit set except for\n // the last byte for each value\n let value = 0;\n while (buffer.length() > 0) {\n b = buffer.getByte();\n value = value << 7;\n // not the last byte for the value\n if (b & 0x80) {\n value += b & 0x7F;\n } else {\n // last byte\n oid += '.' + (value + b);\n value = 0;\n }\n }\n\n return oid;\n}\n\n/**\n * Gets the length of a BER-encoded ASN.1 value.\n *\n * In case the length is not specified, undefined is returned.\n *\n * @param bytes the byte buffer to parse from.\n *\n * @return the length of the BER-encoded ASN.1 value or undefined.\n */\nfunction _getValueLength(bytes: ByteStringBuffer): number {\n // TODO: move this function and related DER/BER functions to a der.js\n // file; better abstract ASN.1 away from der/ber.\n // fromDer already checked that this byte exists\n const b2 = bytes.getByte();\n\n // see if the length is \"short form\" or \"long form\" (bit 8 set)\n let length: number;\n const longForm = b2 & 0x80;\n if (!longForm) {\n // length is just the first byte\n length = b2;\n } else {\n // the number of bytes the length is specified in bits 7 through 1\n // and each length byte is in big-endian base-256\n const longFormBytes = b2 & 0x7F;\n // bypass tsc error\n length = bytes.getInt(longFormBytes << 3 as 8);\n }\n return length;\n}\n\n/**\n * Internal function to parse an asn1 object from a byte buffer in DER format.\n *\n * @param bytes the byte buffer to parse from.\n * @param depth the current parsing depth.\n * @param options object with same options as fromDer().\n *\n * @return the parsed asn1 object.\n */\nfunction _fromDer(bytes: ByteStringBuffer, depth: number, options: {\n strict: boolean;\n decodeBitStrings: boolean;\n}): ASN1 {\n // get the first byte\n const b1 = bytes.getByte();\n\n // get the tag class\n const tagClass = (b1 & 0xC0);\n\n // get the type (bits 1-5)\n const type = b1 & 0x1F;\n\n // get the variable value length and adjust remaining bytes\n let start = bytes.length();\n let length = _getValueLength(bytes);\n\n // value storage\n let value: string | ASN1[] | undefined;\n // possible BIT STRING contents storage\n let bitStringContents: string | undefined;\n\n // constructed flag is bit 6 (32 = 0x20) of the first byte\n const constructed = ((b1 & 0x20) === 0x20);\n if (constructed) {\n // parse child asn1 objects from the value\n value = [];\n // parsing asn1 object of definite length\n while (length > 0) {\n start = bytes.length();\n value.push(_fromDer(bytes, depth + 1, options));\n length -= start - bytes.length();\n }\n }\n\n // if a BIT STRING, save the contents including padding\n if (value === undefined && tagClass === Class.UNIVERSAL &&\n type === Type.BITSTRING) {\n bitStringContents = bytes.bytes(length);\n }\n\n // determine if a non-constructed value should be decoded as a composed\n // value that contains other ASN.1 objects. BIT STRINGs (and OCTET STRINGs)\n // can be used this way.\n if (value === undefined && options.decodeBitStrings &&\n tagClass === Class.UNIVERSAL &&\n // FIXME: OCTET STRINGs not yet supported here\n // .. other parts of forge expect to decode OCTET STRINGs manually\n (type === Type.BITSTRING /*|| type === Type.OCTETSTRING*/) &&\n length > 1) {\n // save read position\n let unused = 0;\n if (type === Type.BITSTRING) {\n unused = bytes.getByte();\n }\n // if all bits are used, maybe the BIT/OCTET STRING holds ASN.1 objs\n if (unused === 0) {\n // attempt to parse child asn1 object from the value\n // (stored in array to signal composed value)\n start = bytes.length();\n const subOptions = {\n // enforce strict mode to avoid parsing ASN.1 from plain data\n strict: true,\n decodeBitStrings: true\n };\n const composed = _fromDer(bytes, depth + 1, subOptions);\n let used = start - bytes.length();\n if (type === Type.BITSTRING) {\n used++;\n }\n\n // if the data all decoded and the class indicates UNIVERSAL or\n // CONTEXT_SPECIFIC then assume we've got an encapsulated ASN.1 object\n if (used === length) {\n value = [composed];\n }\n }\n }\n\n if (value === undefined) {\n // asn1 not constructed or composed, get raw value\n // TODO: do DER to OID conversion and vice-versa in .toDer?\n\n value = bytes.getBytes(length);\n }\n\n // add BIT STRING contents if available\n // create and return asn1 object\n return create(tagClass, type, constructed, value, bitStringContents);\n}\n\n/**\n * Creates a new asn1 object.\n *\n * @param tagClass the tag class for the object.\n * @param type the data type (tag number) for the object.\n * @param constructed true if the asn1 object is in constructed form.\n * @param value the value for the object, if it is not constructed.\n * @param [options] the options to use:\n * [bitStringContents] the plain BIT STRING content including padding\n * byte.\n *\n * @return the asn1 object.\n */\nfunction create(tagClass: number, type: number, constructed: boolean, value: string | ASN1[], bitStringContents?: string): ASN1 {\n /* An asn1 object has a tagClass, a type, a constructed flag, and a\n value. The value's type depends on the constructed flag. If\n constructed, it will contain a list of other asn1 objects. If not,\n it will contain the ASN.1 value as an array of bytes formatted\n according to the ASN.1 data type. */\n\n // remove undefined values\n if (Array.isArray(value)) {\n value = value.filter(x => x != null);\n }\n\n const obj: ASN1 = {\n constructed,\n tagClass,\n type,\n value,\n };\n if (bitStringContents) {\n obj.bitStringContents = bitStringContents;\n }\n return obj;\n}\n","// Copyright (c) 2005 Tom Wu\n// All Rights Reserved.\n// See \"LICENSE\" for details.\n\n// Basic JavaScript BN library - subset useful for RSA encryption.\n\n/*\nLicensing (LICENSE)\n-------------------\n\nThis software is covered under the following copyright:\n*/\n/*\n * Copyright (c) 2003-2005 Tom Wu\n * All Rights Reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS-IS\" AND WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY\n * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.\n *\n * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,\n * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER\n * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF\n * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT\n * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n * In addition, the following condition applies:\n *\n * All redistributions must retain an intact copy of this copyright notice\n * and disclaimer.\n */\n/*\nAddress all questions regarding this license to:\n\n Tom Wu\n tjw@cs.Stanford.EDU\n*/\n\n// Bits per digit\nconst dbits = 28;\n\nconst BI_FP = 52;\n\n// (public) Constructor\nexport class BigInteger {\n private s = 0;\n t = 0;\n data: number[] = [];\n DB = dbits;\n DM = (1 << dbits) - 1;\n private DV = 1 << dbits;\n private FV = Math.pow(2, BI_FP);\n private F1 = BI_FP - dbits;\n private F2 = 2 * dbits - BI_FP;\n\n constructor(a?: string) {\n if (a != null) {\n this.fromString(a);\n }\n }\n\n am(i: number, x: number, w: BigInteger, j: number, c: number, n: number): number {\n const xl = x & 0x3fff,\n xh = x >> 14;\n while (--n >= 0) {\n let l = this.data[i] & 0x3fff;\n const h = this.data[i++] >> 14;\n const m = xh * l + h * xl;\n l = xl * l + ((m & 0x3fff) << 14) + w.data[j] + c;\n c = (l >> 28) + (m >> 14) + xh * h;\n w.data[j++] = l & 0xfffffff;\n }\n return c;\n }\n\n // (public) return the number of bits in \"this\"\n bitLength(): number {\n return (\n this.DB * (this.t - 1) + nbits(this.data[this.t - 1] ^ (this.s & this.DM))\n );\n }\n\n // (protected) r = this << n*DB\n dlShiftTo(n: number, r: BigInteger): void {\n let i = this.t - 1;\n for (; i >= 0; --i) r.data[i + n] = this.data[i];\n for (i = n - 1; i >= 0; --i) r.data[i] = 0;\n r.t = this.t + n;\n r.s = this.s;\n }\n\n // (protected) r = this >> n*DB\n drShiftTo(n: number, r: BigInteger): void {\n for (let i = n; i < this.t; ++i) r.data[i - n] = this.data[i];\n r.t = Math.max(this.t - n, 0);\n r.s = this.s;\n }\n\n // (protected) r = this << n\n lShiftTo(n: number, r: BigInteger): void {\n const bs = n % this.DB;\n const cbs = this.DB - bs;\n const bm = (1 << cbs) - 1;\n const ds = Math.floor(n / this.DB);\n let c = (this.s << bs) & this.DM;\n let i = this.t - 1;\n for (; i >= 0; --i) {\n r.data[i + ds + 1] = (this.data[i] >> cbs) | c;\n c = (this.data[i] & bm) << bs;\n }\n r.data[ds] = c;\n r.t = this.t + ds + 1;\n r.s = this.s;\n r.clamp();\n }\n\n // (protected) r = this >> n\n rShiftTo(n: number, r: BigInteger): void {\n r.s = this.s;\n const ds = Math.floor(n / this.DB);\n const bs = n % this.DB;\n const cbs = this.DB - bs;\n const bm = (1 << bs) - 1;\n r.data[0] = this.data[ds] >> bs;\n for (let i = ds + 1; i < this.t; ++i) {\n r.data[i - ds - 1] |= (this.data[i] & bm) << cbs;\n r.data[i - ds] = this.data[i] >> bs;\n }\n if (bs > 0) r.data[this.t - ds - 1] |= (this.s & bm) << cbs;\n r.t = this.t - ds;\n r.clamp();\n }\n\n // (protected) r = this - a\n subTo(a: BigInteger, r: BigInteger): void {\n let i = 0;\n let c = 0;\n const m = Math.min(a.t, this.t);\n while (i < m) {\n c += this.data[i] - a.data[i];\n r.data[i++] = c & this.DM;\n c >>= this.DB;\n }\n c -= a.s;\n while (i < this.t) {\n c += this.data[i];\n r.data[i++] = c & this.DM;\n c >>= this.DB;\n }\n r.t = i;\n r.clamp();\n }\n\n // (protected) r = this * a, r != this,a (HAC 14.12)\n // \"this\" should be the larger one if appropriate.\n multiplyTo(a: BigInteger, r: BigInteger): void {\n const x = this.abs(),\n y = a.abs();\n let i = x.t;\n r.t = i + y.t;\n while (--i >= 0) r.data[i] = 0;\n for (i = 0; i < y.t; ++i) r.data[i + x.t] = x.am(0, y.data[i], r, i, 0, x.t);\n r.s = 0;\n r.clamp();\n }\n\n // (protected) r = this^2, r != this (HAC 14.16)\n squareTo(r: BigInteger): void {\n const x = this.abs();\n let i = (r.t = 2 * x.t);\n while (--i >= 0) r.data[i] = 0;\n for (i = 0; i < x.t - 1; ++i) {\n const c = x.am(i, x.data[i], r, 2 * i, 0, 1);\n if (\n (r.data[i + x.t] += x.am(\n i + 1,\n 2 * x.data[i],\n r,\n 2 * i + 1,\n c,\n x.t - i - 1\n )) >= x.DV\n ) {\n r.data[i + x.t] -= x.DV;\n r.data[i + x.t + 1] = 1;\n }\n }\n if (r.t > 0) r.data[r.t - 1] += x.am(i, x.data[i], r, 2 * i, 0, 1);\n r.s = 0;\n r.clamp();\n }\n\n // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)\n // r != q, this != m. q or r may be null.\n divRemTo(m: BigInteger, r: BigInteger): void {\n const pm = m.abs();\n const pt = this.abs();\n const y = nbi()\n const nsh = this.DB - nbits(pm.data[pm.t - 1]); // normalize modulus\n pm.lShiftTo(nsh, y);\n pt.lShiftTo(nsh, r);\n const ys = y.t;\n const y0 = y.data[ys - 1];\n const yt = y0 * (1 << this.F1) + (y.data[ys - 2] >> this.F2);\n const d1 = this.FV / yt,\n d2 = (1 << this.F1) / yt,\n e = 1 << this.F2;\n let i = r.t;\n let j = i - ys;\n const t = nbi();\n y.dlShiftTo(j, t);\n BigIntegerONE.dlShiftTo(ys, t);\n t.subTo(y, y); // \"negative\" y so we can replace sub with am later\n while (--j >= 0) {\n // Estimate quotient digit\n --i;\n const qd = Math.floor(r.data[i] * d1 + (r.data[i - 1] + e) * d2);\n r.data[i] += y.am(0, qd, r, j, 0, ys);\n }\n r.t = ys;\n r.clamp();\n if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder\n }\n\n // (protected) return \"-1/this % 2^DB\"; useful for Mont. reduction\n // justification:\n // xy == 1 (mod m)\n // xy = 1+km\n // xy(2-xy) = (1+km)(1-km)\n // x[y(2-xy)] = 1-k^2m^2\n // x[y(2-xy)] == 1 (mod m^2)\n // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2\n // should reduce x and y(2-xy) by m^2 at each step to keep size bounded.\n // JS multiply \"overflows\" differently from C/C++, so care is needed here.\n invDigit(): number {\n const x = this.data[0];\n let y = x & 3; // y == 1/x mod 2^2\n y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4\n y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8\n y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16\n // last step - calculate inverse mod DV directly;\n // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints\n y = (y * (2 - ((x * y) % this.DV))) % this.DV; // y == 1/x mod 2^dbits\n // we really want the negative inverse, and -DV < y < DV\n return -y;\n }\n\n // (protected) copy this to r\n copyTo(r: BigInteger): void {\n for (let i = this.t - 1; i >= 0; --i) r.data[i] = this.data[i];\n r.t = this.t;\n r.s = this.s;\n }\n\n // (protected) set from integer value x, -DV <= x < DV\n fromInt(x: number): void {\n this.t = 1;\n this.s = 0;\n this.data[0] = x;\n }\n\n // (protected) set from string and radix\n fromString(s: string): void {\n const k = 4;\n this.t = 0;\n this.s = 0;\n let i = s.length;\n let sh = 0;\n while (--i >= 0) {\n const x = intAt(s, i);\n if (sh === 0) this.data[this.t++] = x;\n else this.data[this.t - 1] |= x << sh;\n sh += k;\n if (sh >= this.DB) sh -= this.DB;\n }\n this.clamp();\n }\n\n // (protected) clamp off excess high words\n clamp(): void {\n const c = this.s & this.DM;\n while (this.t > 0 && this.data[this.t - 1] === c) --this.t;\n }\n\n // (public) return string representation in given radix\n toString(): string {\n const k = 4;\n const km = (1 << k) - 1;\n let d,\n m = false,\n r = '',\n i = this.t;\n let p = this.DB - ((i * this.DB) % k);\n if (i-- > 0) {\n while (i >= 0) {\n d = (this.data[i] >> (p -= k)) & km;\n if (p <= 0) {\n p += this.DB;\n --i;\n }\n if (d > 0) m = true;\n if (m) r += int2char(d);\n }\n }\n return r;\n }\n\n // (public) |this|\n abs(): this {\n return this;\n }\n\n //(public) this^e % m (HAC 14.85)\n modPow(e: BigInteger, m: BigInteger): BigInteger {\n let i = e.bitLength();\n let r = nbv(1);\n const k = 1;\n const z = new Montgomery(m);\n\n // precomputation\n const g = [];\n let n = 3;\n const k1 = k - 1,\n km = (1 << k) - 1;\n g[1] = z.convert(this);\n\n let j = e.t - 1,\n w,\n is1 = true,\n r2 = nbi(),\n t;\n i = nbits(e.data[j]) - 1;\n while (j >= 0) {\n w = (e.data[j] >> (i - k1)) & km;\n\n n = k;\n if ((i -= n) < 0) {\n i += this.DB;\n --j;\n }\n if (is1) {\n // ret == 1, don't bother squaring or multiplying it\n g[w].copyTo(r);\n is1 = false;\n } else {\n z.sqrTo(r, r2);\n z.mulTo(r2, g[w], r);\n }\n\n while (j >= 0 && (e.data[j] & (1 << i)) === 0) {\n z.sqrTo(r, r2);\n t = r;\n r = r2;\n r2 = t;\n i--;\n }\n }\n return z.revert(r);\n }\n}\n\n//BigInteger interfaces not implemented in jsbn:\n\n//BigInteger(int signum, byte[] magnitude)\n//double doubleValue()\n//float floatValue()\n//int hashCode()\n//long longValue()\n//static BigInteger valueOf(long val)\n\n// \"constants\"\nconst BigIntegerONE = nbv(1);\n\n// return new, unset BigInteger\nfunction nbi(): BigInteger {\n return new BigInteger();\n}\n\n// return bigint initialized to value\nfunction nbv(i: number): BigInteger {\n const r = nbi();\n r.fromInt(i);\n return r;\n}\n\n// Digit conversions\nconst BI_RM = '0123456789abcdefghijklmnopqrstuvwxyz';\nconst BI_RC: number[] = [];\nlet vv: number;\nlet rr = '0'.charCodeAt(0);\nfor (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;\nrr = 'a'.charCodeAt(0);\nfor (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;\n\nfunction int2char(n: number): string {\n return BI_RM.charAt(n);\n}\nfunction intAt(s: string, i: number): number {\n const c = BI_RC[s.charCodeAt(i)];\n return c;\n}\n\n// returns bit length of the integer x\nfunction nbits(x: number): number {\n let r = 1,\n t;\n if ((t = x >>> 16) != 0) {\n x = t;\n r += 16;\n }\n if ((t = x >> 2) != 0) {\n x = t;\n r += 2;\n }\n if ((t = x >> 1) != 0) {\n x = t;\n r += 1;\n }\n return r;\n}\n\n// Montgomery reduction\nclass Montgomery {\n private m: BigInteger;\n private mp: number;\n private mpl: number;\n private mph: number;\n private um: number;\n private mt2: number;\n\n constructor(m: BigInteger) {\n this.m = m;\n this.mp = m.invDigit();\n this.mpl = this.mp & 0x7fff;\n this.mph = this.mp >> 15;\n this.um = (1 << (m.DB - 15)) - 1;\n this.mt2 = 2 * m.t;\n }\n\n // xR mod m\n convert(x: BigInteger): BigInteger {\n const r = nbi();\n x.abs().dlShiftTo(this.m.t, r);\n r.divRemTo(this.m, r);\n return r;\n }\n\n // x/R mod m\n revert(x: BigInteger): BigInteger {\n const r = nbi();\n x.copyTo(r);\n this.reduce(r);\n return r;\n }\n\n // x = x/R mod m (HAC 14.32)\n reduce(x: BigInteger): void {\n while (x.t <= this.mt2)\n // pad x so am has enough room later\n x.data[x.t++] = 0;\n for (let i = 0; i < this.m.t; ++i) {\n // faster way of calculating u0 = x.data[i]*mp mod DV\n let j = x.data[i] & 0x7fff;\n const u0 =\n (j * this.mpl +\n (((j * this.mph + (x.data[i] >> 15) * this.mpl) & this.um) << 15)) &\n x.DM;\n // use am to combine the multiply-shift-add into one call\n j = i + this.m.t;\n x.data[j] += this.m.am(0, u0, x, i, 0, this.m.t);\n // propagate carry\n }\n x.clamp();\n x.drShiftTo(this.m.t, x);\n }\n\n // r = \"x^2/R mod m\"; x != r\n sqrTo(x: BigInteger, r: BigInteger): void {\n x.squareTo(r);\n this.reduce(r);\n }\n\n // r = \"xy/R mod m\"; x,y != r\n mulTo(x: BigInteger, y: BigInteger, r: BigInteger): void {\n x.multiplyTo(y, r);\n this.reduce(r);\n }\n}\n","/**\n * Utility functions for web applications.\n *\n * @author Dave Longley\n *\n * Copyright (c) 2010-2018 Digital Bazaar, Inc.\n */\n\n/**\n * Performs a per byte XOR between two byte strings and returns the result as a\n * string of bytes.\n *\n * @param s1 first string of bytes.\n * @param s2 second string of bytes.\n * @param n the number of bytes to XOR.\n *\n * @return the XOR'd result.\n */\nexport function xorBytes(s1: string, s2: string, n: number): string {\n let s3 = '';\n let b = 0;\n let t = '';\n let i = 0;\n let c = 0;\n for (; n > 0; --n, ++i) {\n b = s1.charCodeAt(i) ^ s2.charCodeAt(i);\n if (c >= 10) {\n s3 += t;\n t = '';\n c = 0;\n }\n t += String.fromCharCode(b);\n ++c;\n }\n s3 += t;\n return s3;\n}\n\nconst Base64Idx = [\n /*43 -43 = 0*/\n /*'+', 1, 2, 3,'/' */\n 62, -1, -1, -1, 63,\n\n /*'0','1','2','3','4','5','6','7','8','9' */\n 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,\n\n /*15, 16, 17,'=', 19, 20, 21 */\n -1, -1, -1, 64, -1, -1, -1,\n\n /*65 - 43 = 22*/\n /*'A','B','C','D','E','F','G','H','I','J','K','L','M', */\n 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\n\n /*'N','O','P','Q','R','S','T','U','V','W','X','Y','Z' */\n 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,\n\n /*91 - 43 = 48 */\n /*48, 49, 50, 51, 52, 53 */\n -1, -1, -1, -1, -1, -1,\n\n /*97 - 43 = 54*/\n /*'a','b','c','d','e','f','g','h','i','j','k','l','m' */\n 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,\n\n /*'n','o','p','q','r','s','t','u','v','w','x','y','z' */\n 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,\n];\n\n/**\n * Base64 decodes a string into a 'binary' encoded string of bytes.\n *\n * @param input the base64-encoded input.\n *\n * @return the binary encoded string.\n */\nexport function decode64(input: string): string {\n // TODO: deprecate: \"Deprecated. Use util.binary.base64.decode instead.\"\n\n // remove all non-base64 characters\n input = input.replace(/[^A-Za-z0-9+/=]/g, '');\n\n let output = '';\n let enc1: number;\n let enc2: number;\n let enc3: number;\n let enc4: number;\n let i = 0;\n\n while (i < input.length) {\n enc1 = Base64Idx[input.charCodeAt(i++) - 43];\n enc2 = Base64Idx[input.charCodeAt(i++) - 43];\n enc3 = Base64Idx[input.charCodeAt(i++) - 43];\n enc4 = Base64Idx[input.charCodeAt(i++) - 43];\n\n output += String.fromCharCode((enc1 << 2) | (enc2 >> 4));\n if (enc3 !== 64) {\n // decoded at least 2 bytes\n output += String.fromCharCode(((enc2 & 15) << 4) | (enc3 >> 2));\n if (enc4 !== 64) {\n // decoded 3 bytes\n output += String.fromCharCode(((enc3 & 3) << 6) | enc4);\n }\n }\n }\n\n return output;\n}\n","/**\n * Javascript implementation of basic PEM (Privacy Enhanced Mail) algorithms.\n *\n * See: RFC 1421.\n *\n * @author Dave Longley\n *\n * Copyright (c) 2013-2014 Digital Bazaar, Inc.\n *\n * A Forge PEM object has the following fields:\n *\n * type: identifies the type of message (eg: \"RSA PRIVATE KEY\").\n *\n * procType: identifies the type of processing performed on the message,\n * it has two subfields: version and type, eg: 4,ENCRYPTED.\n *\n * contentDomain: identifies the type of content in the message, typically\n * only uses the value: \"RFC822\".\n *\n * dekInfo: identifies the message encryption algorithm and mode and includes\n * any parameters for the algorithm, it has two subfields: algorithm and\n * parameters, eg: DES-CBC,F8143EDE5960C597.\n *\n * headers: contains all other PEM encapsulated headers -- where order is\n * significant (for pairing data like recipient ID + key info).\n *\n * body: the binary-encoded body.\n */\n\nimport { decode64 } from './util.ts';\n\n/**\n * Decodes (deserializes) all PEM messages found in the given string.\n *\n * @param pem the PEM-formatted string to decode.\n *\n * @return the PEM message objects in an array.\n */\nexport function pemDecode(pem: string): string {\n // split string into PEM messages (be lenient w/EOF on BEGIN line)\n const rMessage = /\\s*-----BEGIN ([A-Z0-9- ]+)-----\\r?\\n?([\\x21-\\x7e\\s]+?(?:\\r?\\n\\r?\\n))?([:A-Za-z0-9+/=\\s]+?)-----END \\1-----/g;\n const match = rMessage.exec(pem);\n if (!match) {\n throw new Error('Invalid PEM formatted message.');\n }\n\n return decode64(match[3]);\n}\n","/**\n * Advanced Encryption Standard (AES) implementation.\n *\n * This implementation is based on the public domain library 'jscrypto' which\n * was written by:\n *\n * Emily Stark (estark@stanford.edu)\n * Mike Hamburg (mhamburg@stanford.edu)\n * Dan Boneh (dabo@cs.stanford.edu)\n *\n * Parts of this code are based on the OpenSSL implementation of AES:\n * http://www.openssl.org\n *\n * @author Dave Longley\n *\n * Copyright (c) 2010-2014 Digital Bazaar, Inc.\n */\n\n/**\n * Expands a key. Typically only used for testing.\n *\n * @param key the symmetric key to expand, as an array of 32-bit words.\n *\n * @return the expanded key.\n */\nexport function expandKey(key: number[]): number[] {\n if (!init) {\n initialize();\n }\n return _expandKey(key);\n}\n\n/** AES implementation **/\n\nlet init = false; // not yet initialized\nconst Nb = 4; // number of words comprising the state (AES = 4)\nlet sbox: number[]; // non-linear substitution table used in key expansion\nlet isbox: number[]; // inversion of sbox\nlet rcon: number[]; // round constant word array\nlet mix: number[][]; // mix-columns table\nlet imix: number[][]; // inverse mix-columns table\n\n/**\n * Performs initialization, ie: precomputes tables to optimize for speed.\n *\n * One way to understand how AES works is to imagine that 'addition' and\n * 'multiplication' are interfaces that require certain mathematical\n * properties to hold true (ie: they are associative) but they might have\n * different implementations and produce different kinds of results ...\n * provided that their mathematical properties remain true. AES defines\n * its own methods of addition and multiplication but keeps some important\n * properties the same, ie: associativity and distributivity. The\n * explanation below tries to shed some light on how AES defines addition\n * and multiplication of bytes and 32-bit words in order to perform its\n * encryption and decryption algorithms.\n *\n * The basics:\n *\n * The AES algorithm views bytes as binary representations of polynomials\n * that have either 1 or 0 as the coefficients. It defines the addition\n * or subtraction of two bytes as the XOR operation. It also defines the\n * multiplication of two bytes as a finite field referred to as GF(2^8)\n * (Note: 'GF' means \"Galois Field\" which is a field that contains a finite\n * number of elements so GF(2^8) has 256 elements).\n *\n * This means that any two bytes can be represented as binary polynomials;\n * when they multiplied together and modularly reduced by an irreducible\n * polynomial of the 8th degree, the results are the field GF(2^8). The\n * specific irreducible polynomial that AES uses in hexadecimal is 0x11b.\n * This multiplication is associative with 0x01 as the identity:\n *\n * (b * 0x01 = GF(b, 0x01) = b).\n *\n * The operation GF(b, 0x02) can be performed at the byte level by left\n * shifting b once and then XOR'ing it (to perform the modular reduction)\n * with 0x11b if b is >= 128. Repeated application of the multiplication\n * of 0x02 can be used to implement the multiplication of any two bytes.\n *\n * For instance, multiplying 0x57 and 0x13, denoted as GF(0x57, 0x13), can\n * be performed by factoring 0x13 into 0x01, 0x02, and 0x10. Then these\n * factors can each be multiplied by 0x57 and then added together. To do\n * the multiplication, values for 0x57 multiplied by each of these 3 factors\n * can be precomputed and stored in a table. To add them, the values from\n * the table are XOR'd together.\n *\n * AES also defines addition and multiplication of words, that is 4-byte\n * numbers represented as polyn