UNPKG

one

Version:

One is a React framework for web, iOS, and Android apps.

319 lines (316 loc) • 11.2 kB
import { base64ToBytes, bytesToBase64, bytesToHex, concatBytes, exactBytes, hexToBytes } from "./bytes.native.js"; function _class_call_check(instance, Constructor) { if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _create_class(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _define_property(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true }); } else obj[key] = value; return obj; } var KEY_SIZES = [ 128, 192, 256 ]; var TAG_LENGTHS = [ 16, 15, 14, 13, 12, 8, 4 ]; var DEFAULT_IV_LENGTH = 12; var DEFAULT_TAG_LENGTH = 16; function assertTagLength(tagLength, verb) { if (!TAG_LENGTHS.includes(tagLength)) { throw new Error(`${verb}: tagLength must be one of: ${TAG_LENGTHS.join(", ")}`); } } function toBytes(input, verb) { if (typeof input === "string") return base64ToBytes(input, verb); if (input instanceof ArrayBuffer) return new Uint8Array(input.slice(0)); if (ArrayBuffer.isView(input) && input.buffer instanceof ArrayBuffer) { return exactBytes(new Uint8Array(input.buffer, input.byteOffset, input.byteLength)); } throw new TypeError(`${verb}: expected a base64 string, Uint8Array, or ArrayBuffer`); } var sealedParts = /* @__PURE__ */ new WeakMap(); var keyBytes = /* @__PURE__ */ new WeakMap(); function encodeParts(bytes, encoding) { return encoding === "base64" ? bytesToBase64(bytes) : exactBytes(bytes); } function createAesApi(engine) { var AESEncryptionKey = /* @__PURE__ */ (function() { "use strict"; function AESEncryptionKey2(bytes) { _class_call_check(this, AESEncryptionKey2); _define_property(this, "size", void 0); if (!KEY_SIZES.includes(bytes.length * 8)) { throw new Error(`Crypto.AESEncryptionKey: key must be 128, 192, or 256 bits, got ${bytes.length * 8}`); } this.size = bytes.length * 8; keyBytes.set(this, exactBytes(bytes)); } _create_class(AESEncryptionKey2, [{ key: "bytes", value: async function bytes() { return exactBytes(keyBytes.get(this)); } }, { key: "encoded", value: async function encoded(encoding) { var bytes = keyBytes.get(this); if (encoding === "hex") return bytesToHex(bytes); if (encoding === "base64") return bytesToBase64(bytes); throw new Error(`Crypto.AESEncryptionKey.encoded: encoding must be 'hex' or 'base64'`); } }], [{ key: "generate", value: async function generate() { var size = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : 256; if (!KEY_SIZES.includes(size)) { throw new Error(`Crypto.AESEncryptionKey.generate: size must be one of: ${KEY_SIZES.join(", ")}`); } var bytes = new Uint8Array(size / 8); engine.random(bytes); return new AESEncryptionKey2(bytes); } }, { key: "import", value: async function _import(input, encoding) { var verb = "Crypto.AESEncryptionKey.import"; var bytes; if (typeof input === "string") { if (encoding === "hex") bytes = hexToBytes(input, verb); else if (encoding === "base64") bytes = base64ToBytes(input, verb); else throw new Error(`${verb}: encoding must be 'hex' or 'base64'`); } else if (input instanceof Uint8Array) { bytes = exactBytes(input); } else { throw new TypeError(`${verb}: expected bytes or an encoded string`); } if (!KEY_SIZES.includes(bytes.length * 8)) { throw new Error(`${verb}: key must be 128, 192, or 256 bits, got ${bytes.length * 8}`); } return new AESEncryptionKey2(bytes); } }]); return AESEncryptionKey2; })(); var AESSealedData = /* @__PURE__ */ (function() { "use strict"; function AESSealedData2(parts) { _class_call_check(this, AESSealedData2); if (parts.iv.length === 0) throw new Error("Crypto.AESSealedData: iv must not be empty"); assertTagLength(parts.tag.length, "Crypto.AESSealedData"); sealedParts.set(this, parts); } _create_class(AESSealedData2, [ { key: "ivSize", get: function get() { return sealedParts.get(this).iv.length; } }, { key: "tagSize", get: function get() { return sealedParts.get(this).tag.length; } }, { key: "combinedSize", get: function get() { var parts = sealedParts.get(this); return parts.iv.length + parts.ciphertext.length + parts.tag.length; } }, { key: "iv", value: async function iv(encoding) { return encodeParts(sealedParts.get(this).iv, encoding); } }, { key: "tag", value: async function tag(encoding) { return encodeParts(sealedParts.get(this).tag, encoding); } }, { key: "ciphertext", value: async function ciphertext(options) { var parts = sealedParts.get(this); var bytes = (options === null || options === void 0 ? void 0 : options.includeTag) ? concatBytes([parts.ciphertext, parts.tag]) : parts.ciphertext; return encodeParts(bytes, options === null || options === void 0 ? void 0 : options.encoding); } }, { key: "combined", value: async function combined(encoding) { var parts = sealedParts.get(this); return encodeParts(concatBytes([ parts.iv, parts.ciphertext, parts.tag ]), encoding); } } ], [ { key: "fromCombined", value: function fromCombined(combined) { var config = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}; var _config_ivLength, _config_tagLength; var verb = "Crypto.AESSealedData.fromCombined"; var ivLength = (_config_ivLength = config.ivLength) !== null && _config_ivLength !== void 0 ? _config_ivLength : DEFAULT_IV_LENGTH; var tagLength = (_config_tagLength = config.tagLength) !== null && _config_tagLength !== void 0 ? _config_tagLength : DEFAULT_TAG_LENGTH; assertTagLength(tagLength, verb); if (!Number.isInteger(ivLength) || ivLength <= 0) { throw new Error(`${verb}: ivLength must be a positive integer`); } var bytes = toBytes(combined, verb); if (bytes.length < ivLength + tagLength) { throw new Error(`${verb}: combined data is shorter than its iv and tag`); } return new AESSealedData2({ iv: exactBytes(bytes.subarray(0, ivLength)), ciphertext: exactBytes(bytes.subarray(ivLength, bytes.length - tagLength)), tag: exactBytes(bytes.subarray(bytes.length - tagLength)) }); } }, { key: "fromParts", value: function fromParts(ivInput, ciphertextInput, tagOrLength) { var verb = "Crypto.AESSealedData.fromParts"; var iv = toBytes(ivInput, verb); var ciphertext = toBytes(ciphertextInput, verb); if (tagOrLength === void 0 || typeof tagOrLength === "number") { var tagLength = tagOrLength !== null && tagOrLength !== void 0 ? tagOrLength : DEFAULT_TAG_LENGTH; assertTagLength(tagLength, verb); if (ciphertext.length < tagLength) { throw new Error(`${verb}: ciphertext is shorter than its tag`); } return new AESSealedData2({ iv, ciphertext: exactBytes(ciphertext.subarray(0, ciphertext.length - tagLength)), tag: exactBytes(ciphertext.subarray(ciphertext.length - tagLength)) }); } var tag = toBytes(tagOrLength, verb); assertTagLength(tag.length, verb); return new AESSealedData2({ iv, ciphertext, tag }); } }, { key: "fromSeal", value: (function fromSeal(iv, ciphertextWithTag, tagLength) { return new AESSealedData2({ iv, ciphertext: exactBytes(ciphertextWithTag.subarray(0, ciphertextWithTag.length - tagLength)), tag: exactBytes(ciphertextWithTag.subarray(ciphertextWithTag.length - tagLength)) }); }) } ]); return AESSealedData2; })(); async function keyMaterial(key, verb) { var own = keyBytes.get(key); if (own) return exactBytes(own); if (key && typeof key.bytes === "function") return exactBytes(await key.bytes()); throw new TypeError(`${verb}: expected an AESEncryptionKey`); } async function partsOf(sealed, verb) { var own = sealedParts.get(sealed); if (own) { return { iv: exactBytes(own.iv), ciphertext: exactBytes(own.ciphertext), tag: exactBytes(own.tag) }; } if (sealed && typeof sealed.iv === "function" && typeof sealed.combined === "function") { var iv = exactBytes(await sealed.iv()); var tag = exactBytes(await sealed.tag()); var ciphertext = exactBytes(await sealed.ciphertext({ encoding: "bytes", includeTag: false })); return { iv, ciphertext, tag }; } throw new TypeError(`${verb}: expected an AESSealedData`); } async function aesEncrypt(plaintext, key) { var options = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {}; var _options_tagLength; var verb = "Crypto.aesEncrypt"; var tagLength = (_options_tagLength = options.tagLength) !== null && _options_tagLength !== void 0 ? _options_tagLength : DEFAULT_TAG_LENGTH; assertTagLength(tagLength, verb); var iv; var nonce = options.nonce; if (nonce && "bytes" in nonce && nonce.bytes !== void 0) { iv = toBytes(nonce.bytes, verb); if (iv.length === 0) throw new Error(`${verb}: nonce bytes must not be empty`); } else { var length = nonce && "length" in nonce && nonce.length !== void 0 ? nonce.length : DEFAULT_IV_LENGTH; if (!Number.isInteger(length) || length <= 0) { throw new Error(`${verb}: nonce length must be a positive integer`); } iv = new Uint8Array(length); engine.random(iv); } var additionalData = options.additionalData === void 0 ? void 0 : toBytes(options.additionalData, verb); var plainBytes = toBytes(plaintext, verb); var sealed = await engine.seal(await keyMaterial(key, verb), iv, plainBytes, additionalData, tagLength); var actualTag = sealed.length - plainBytes.length; return AESSealedData.fromSeal(iv, sealed, actualTag > 0 ? actualTag : tagLength); } async function aesDecrypt(sealedData, key) { var options = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {}; var verb = "Crypto.aesDecrypt"; var parts = await partsOf(sealedData, verb); var additionalData = options.additionalData === void 0 ? void 0 : toBytes(options.additionalData, verb); var plaintext = await engine.open(await keyMaterial(key, verb), parts.iv, concatBytes([parts.ciphertext, parts.tag]), additionalData, parts.tag.length); return options.output === "base64" ? bytesToBase64(plaintext) : plaintext; } return { AESEncryptionKey, AESSealedData, aesEncrypt, aesDecrypt }; } export { assertTagLength, createAesApi, toBytes }; //# sourceMappingURL=aes.native.js.map