cosette
Version:
isomorphic Typescript COSE implementation
178 lines • 7.84 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.read = exports.create = exports.aesCbcMac = exports.MACTag = exports.MAC0Tag = void 0;
const cbor = __importStar(require("cbor-web"));
const isomorphic_webcrypto_1 = __importDefault(require("isomorphic-webcrypto"));
const common = __importStar(require("./common"));
const Tagged = cbor.Tagged;
const EMPTY_BUFFER = common.EMPTY_BUFFER;
exports.MAC0Tag = 17;
exports.MACTag = 97;
const CutTo = {
4: 8,
5: 32,
6: 48,
7: 64
};
const context = {};
context[exports.MAC0Tag] = 'MAC0';
context[exports.MACTag] = 'MAC';
function importKey(algname, key) {
return __awaiter(this, void 0, void 0, function* () {
let hash_match = algname.match(/^(?:HS|SHA-)(\d+)/);
if (!hash_match)
throw new Error("Unsupported algorithm, " + algname);
const hash = 'SHA-' + hash_match[1];
return yield isomorphic_webcrypto_1.default.subtle.importKey("raw", key, { name: "HMAC", hash }, false, ["sign"]);
});
}
const iv = new Uint8Array(16);
function aesCbcMac(key, msg, len) {
return __awaiter(this, void 0, void 0, function* () {
const padLen = msg.length % 16 ? 16 - (msg.length % 16) : 0;
const paddedMsg = new Uint8Array(msg.length + padLen);
paddedMsg.set(msg, 0);
const crypto_key = yield isomorphic_webcrypto_1.default.subtle.importKey("raw", key, { name: "AES-CBC" }, false, ["encrypt"]);
const enc = yield isomorphic_webcrypto_1.default.subtle.encrypt({ name: "AES-CBC", iv }, crypto_key, paddedMsg);
const tagStart = enc.byteLength - 16 - 16; // webcrypto always does pkcs7 padding
const tag = enc.slice(tagStart, tagStart + len);
return Buffer.from(tag);
});
}
exports.aesCbcMac = aesCbcMac;
;
function doMac(context, p, externalAAD, payload, algTag, key) {
return __awaiter(this, void 0, void 0, function* () {
const MACstructure = [
context,
p,
externalAAD,
payload // bstr
];
const toBeMACed = cbor.encode(MACstructure);
const algname = common.AlgFromTags(algTag);
const aesMacNum = algname.match(/^AES-MAC-\d+\/(\d+)/);
if (aesMacNum) {
return yield aesCbcMac(Buffer.from(key), Buffer.from(toBeMACed), +aesMacNum[1] / 8);
}
else {
const crypto_key = yield importKey(algname, key);
const buffer = yield isomorphic_webcrypto_1.default.subtle.sign("HMAC", crypto_key, toBeMACed);
return Buffer.from(buffer);
}
});
}
function create(headers, payload, recipients, externalAAD, options) {
return __awaiter(this, void 0, void 0, function* () {
options = options || {};
externalAAD = externalAAD || EMPTY_BUFFER;
const original_u = headers.u || {};
const original_p = headers.p || {};
const p = common.TranslateHeaders(original_p);
const u = common.TranslateHeaders(original_u);
const alg = p.get(common.HeaderParameters.alg) || u.get(common.HeaderParameters.alg);
if (typeof alg !== "number") {
throw new Error('Missing mandatory parameter \'alg\'');
}
const predictableP = (!p.size) ? EMPTY_BUFFER : cbor.encode(p);
if (p.size === 0 && options.encodep === 'empty') {
var p_buffer = EMPTY_BUFFER;
}
else {
var p_buffer = cbor.encode(p);
}
// TODO check crit headers
if (Array.isArray(recipients)) {
if (recipients.length === 0) {
throw new Error('There has to be at least one recipent');
}
if (recipients.length > 1) {
throw new Error('MACing with multiple recipents is not implemented');
}
var [recipient] = recipients;
var context = "MAC";
var tagNum = exports.MACTag;
var after_tag = [[EMPTY_BUFFER, common.TranslateHeaders(recipient.u), EMPTY_BUFFER]];
}
else {
var recipient = recipients;
var context = "MAC0";
var tagNum = exports.MAC0Tag;
var after_tag = null;
}
let tag = yield doMac(context, predictableP, externalAAD, payload, alg, recipient.key);
tag = tag.slice(0, CutTo[alg]);
let maced = [p_buffer, u, payload, tag];
if (after_tag)
maced.push(after_tag);
return cbor.encode(options.excludetag ? maced : new Tagged(tagNum, maced));
});
}
exports.create = create;
;
function read(data, key, externalAAD, options) {
return __awaiter(this, void 0, void 0, function* () {
options = options || {};
externalAAD = externalAAD || EMPTY_BUFFER;
let obj = yield cbor.decodeFirst(data);
let type = options.defaultType ? options.defaultType : exports.MAC0Tag;
if (obj instanceof Tagged) {
if (obj.tag !== exports.MAC0Tag && obj.tag !== exports.MACTag) {
throw new Error('Unexpected cbor tag, \'' + obj.tag + '\'');
}
type = obj.tag;
obj = obj.value;
}
const expected_length = type === exports.MAC0Tag ? 4 : 5;
if (!(Array.isArray(obj) && obj.length === expected_length)) {
throw new Error('Expecting Array of lenght ' + expected_length);
}
let [p, u, payload, tag] = obj;
p = (!p.length) ? EMPTY_BUFFER : cbor.decode(p);
p = (!p.size) ? EMPTY_BUFFER : p;
u = (!u.size) ? EMPTY_BUFFER : u;
// TODO validate protected header
const alg = (p !== EMPTY_BUFFER) ? p.get(common.HeaderParameters.alg) : (u !== EMPTY_BUFFER) ? u.get(common.HeaderParameters.alg) : undefined;
p = (!p.size) ? EMPTY_BUFFER : cbor.encode(p);
let calcTag = yield doMac(context[type], p, externalAAD, payload, alg, key);
calcTag = calcTag.slice(0, CutTo[alg]);
if (!common.uint8ArrayEquals(tag, calcTag)) {
throw new Error('Tag mismatch');
}
return payload;
});
}
exports.read = read;
;
//# sourceMappingURL=mac.js.map