cose-kit
Version:
**DEPRECATED:** Use [@auth0/cose](https://www.npmjs.com/package/@auth0/cose).
190 lines (189 loc) • 9.5 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Recipient = exports.Encrypt = void 0;
const cbor_js_1 = require("../cbor.js");
const COSEBase_js_1 = require("./COSEBase.js");
const errors = __importStar(require("../util/errors.js"));
const validate_algorithms_js_1 = __importDefault(require("../lib/validate_algorithms.js"));
const headers_js_1 = require("../headers.js");
const decode_js_1 = require("./decode.js");
const decrypt_js_1 = __importDefault(require("#runtime/decrypt.js"));
const index_js_1 = require("../key/index.js");
const COSEKey_js_1 = require("../key/COSEKey.js");
const buffer_utils_js_1 = require("../lib/buffer_utils.js");
const iv_js_1 = __importDefault(require("../lib/iv.js"));
const encrypt_js_1 = __importDefault(require("#runtime/encrypt.js"));
class Encrypt extends COSEBase_js_1.COSEBase {
constructor(protectedHeaders, unprotectedHeaders, ciphertext, recipients) {
super(protectedHeaders, unprotectedHeaders);
this.ciphertext = ciphertext;
this.recipients = recipients;
}
static createAAD(protectedHeaders, externalAAD) {
return cbor_js_1.encoder.encode([
'Encrypt',
protectedHeaders,
externalAAD
]);
}
getContentForEncoding() {
const mapRecipient = (r) => {
var _a;
const result = [
r.protectedHeaders,
r.unprotectedHeaders,
(_a = r.ciphertext) !== null && _a !== void 0 ? _a : new Uint8Array(),
];
if (r.recipients && Array.isArray(r.recipients)) {
result.push(r.recipients.map(mapRecipient));
}
return result;
};
return [
this.encodedProtectedHeaders,
this.unprotectedHeaders,
this.ciphertext,
this.recipients.map(mapRecipient),
];
}
static decode(cose) {
return (0, decode_js_1.decode)(cose, Encrypt);
}
async decrypt(key, options) {
var _a, _b, _c;
if (this.recipients.length > 1 || this.recipients.some(r => r.unprotectedHeaders.get(headers_js_1.Headers.Algorithm) !== -6)) {
throw new Error('Multiple recipients or recipient with non-direct algorithm not supported');
}
const ciphertextWithTag = (_a = options === null || options === void 0 ? void 0 : options.detachedPayload) !== null && _a !== void 0 ? _a : this.ciphertext;
const aad = Encrypt.createAAD((_b = this.encodedProtectedHeaders) !== null && _b !== void 0 ? _b : new Uint8Array(), (_c = options === null || options === void 0 ? void 0 : options.externalAAD) !== null && _c !== void 0 ? _c : new Uint8Array());
if (!this.alg || !this.algName || !headers_js_1.EncryptionAlgorithmNames.has(this.alg)) {
throw new errors.COSEInvalid(`Unsupported encryption algorithm ${this.alg}`);
}
const algorithms = options && (0, validate_algorithms_js_1.default)('algorithms', options.algorithms);
if (algorithms && !algorithms.has(this.alg)) {
throw new errors.COSEAlgNotAllowed(`[${headers_js_1.Headers.Algorithm}] (algorithm) Header Parameter not allowed`);
}
let iv;
if (this.unprotectedHeaders.has(headers_js_1.Headers.IV) && this.unprotectedHeaders.has(headers_js_1.Headers.PartialIV)) {
throw new errors.COSEInvalid('IV and Partial IV must not both be present in the COSE message.');
}
else if (this.unprotectedHeaders.has(headers_js_1.Headers.PartialIV)) {
if (!(key instanceof COSEKey_js_1.COSEKey) || !key.has(index_js_1.COSEKeyParam.BaseIV)) {
throw new errors.COSEInvalid('Key must be a COSEKey instance with Base IV to use Partial IV');
}
iv = (0, buffer_utils_js_1.concat)(key.get(index_js_1.COSEKeyParam.BaseIV), this.unprotectedHeaders.get(headers_js_1.Headers.PartialIV));
}
else if (this.unprotectedHeaders.has(headers_js_1.Headers.IV)) {
iv = this.unprotectedHeaders.get(headers_js_1.Headers.IV);
}
else {
throw new errors.COSEInvalid('IV or Partial IV must be present in the COSE message.');
}
const tag = ciphertextWithTag.slice(-16);
const ciphertext = ciphertextWithTag.slice(0, -16);
const decryptKey = key instanceof COSEKey_js_1.COSEKey ? (await key.toKeyLike()) : key;
return (0, decrypt_js_1.default)(this.algName, decryptKey, ciphertext, iv, tag, aad);
}
get alg() {
return this.protectedHeaders.get(headers_js_1.Headers.Algorithm) ||
this.unprotectedHeaders.get(headers_js_1.Headers.Algorithm);
}
get algName() {
return this.alg ? headers_js_1.EncryptionAlgorithmNames.get(this.alg) : undefined;
}
hasSupportedAlg() {
return !!this.algName;
}
static async encrypt(protectedHeaders, unprotectedHeaders, content, key, externalAAD = new Uint8Array(), recipients) {
if (recipients.length > 1 || recipients.some(r => r.unprotectedHeaders.get(headers_js_1.Headers.Algorithm) !== -6)) {
throw new Error('Multiple recipients or recipient with non-direct algorithm not supported');
}
const wProtectedHeaders = headers_js_1.EncryptProtectedHeaders.wrap(protectedHeaders);
const alg = headers_js_1.EncryptionAlgorithmNames.get(wProtectedHeaders.get(headers_js_1.Headers.Algorithm));
if (!alg) {
throw new Error(`The protected header [${headers_js_1.Headers.Algorithm}] (Algorithm) must be valid.`);
}
const wUnprotectedHeaders = headers_js_1.UnprotectedHeaders.wrap([...(unprotectedHeaders || [])]);
let iv = wUnprotectedHeaders.get(headers_js_1.Headers.IV);
if (!iv) {
const partialIV = wUnprotectedHeaders.get(headers_js_1.Headers.PartialIV);
if (partialIV) {
if (!(key instanceof COSEKey_js_1.COSEKey) || !key.has(index_js_1.COSEKeyParam.BaseIV)) {
throw new errors.COSEInvalid('Key must be a COSEKey instance with Base IV to use Partial IV');
}
iv = (0, buffer_utils_js_1.concat)(key.get(index_js_1.COSEKeyParam.BaseIV), partialIV);
}
else {
iv = (0, iv_js_1.default)(alg);
wUnprotectedHeaders.set(headers_js_1.Headers.IV, iv);
}
}
const aad = Encrypt.createAAD(cbor_js_1.encoder.encode(wProtectedHeaders.esMap), externalAAD);
const encryptKey = key instanceof COSEKey_js_1.COSEKey ? (await key.toKeyLike()) : key;
const { ciphertext, tag } = await (0, encrypt_js_1.default)(alg, content, encryptKey, iv, aad);
const r = (0, buffer_utils_js_1.concat)(ciphertext, tag);
return new Encrypt(wProtectedHeaders.esMap, wUnprotectedHeaders.esMap, r, recipients);
}
}
exports.Encrypt = Encrypt;
Encrypt.tag = 96;
class Recipient extends COSEBase_js_1.COSEBase {
constructor(protectedHeaders, unprotectedHeaders, ciphertext, recipients) {
super(protectedHeaders, unprotectedHeaders);
this.ciphertext = ciphertext;
this.recipients = recipients;
}
static create(protectedHeaders, unprotectedHeaders) {
const wProtectedHeaders = headers_js_1.EncryptProtectedHeaders.wrap(protectedHeaders);
const wUnprotectedHeaders = headers_js_1.UnprotectedHeaders.wrap(unprotectedHeaders);
return new Recipient(wProtectedHeaders.esMap, wUnprotectedHeaders.esMap);
}
get alg() {
return this.protectedHeaders.get(headers_js_1.Headers.Algorithm) ||
this.unprotectedHeaders.get(headers_js_1.Headers.Algorithm);
}
get algName() {
return this.alg && this.alg !== -6 ? headers_js_1.EncryptionAlgorithmNames.get(this.alg) : undefined;
}
hasSupportedAlg() {
return !!this.algName;
}
}
exports.Recipient = Recipient;
(0, cbor_js_1.addExtension)({
Class: Encrypt,
tag: Encrypt.tag,
encode(instance, encodeFn) {
return encodeFn(instance.getContentForEncoding());
},
decode: (data) => {
const recipients = data[3].map(rec => new Recipient(rec[0], rec[1], rec[2], rec[3]));
return new Encrypt(data[0], data[1], data[2], recipients);
}
});