init project
This commit is contained in:
+9
@@ -0,0 +1,9 @@
|
||||
import { prepareDecrypt, decryptCompact } from '../../lib/jwe_decrypt.js';
|
||||
export async function compactDecrypt(jwe, key, options) {
|
||||
const decrypted = await decryptCompact(jwe, prepareDecrypt(options), key);
|
||||
const result = { plaintext: decrypted.plaintext, protectedHeader: decrypted.parsedProt };
|
||||
if (typeof key === 'function') {
|
||||
return { ...result, key: decrypted.key };
|
||||
}
|
||||
return result;
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import { FlattenedEncrypt } from '../flattened/encrypt.js';
|
||||
export class CompactEncrypt {
|
||||
#flattened;
|
||||
constructor(plaintext) {
|
||||
this.#flattened = new FlattenedEncrypt(plaintext);
|
||||
}
|
||||
setContentEncryptionKey(cek) {
|
||||
this.#flattened.setContentEncryptionKey(cek);
|
||||
return this;
|
||||
}
|
||||
setInitializationVector(iv) {
|
||||
this.#flattened.setInitializationVector(iv);
|
||||
return this;
|
||||
}
|
||||
setProtectedHeader(protectedHeader) {
|
||||
this.#flattened.setProtectedHeader(protectedHeader);
|
||||
return this;
|
||||
}
|
||||
setKeyManagementParameters(parameters) {
|
||||
this.#flattened.setKeyManagementParameters(parameters);
|
||||
return this;
|
||||
}
|
||||
async encrypt(key, options) {
|
||||
const jwe = await this.#flattened.encrypt(key, options);
|
||||
return [jwe.protected, jwe.encrypted_key, jwe.iv, jwe.ciphertext, jwe.tag].join('.');
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { JWEInvalid } from '../../util/errors.js';
|
||||
import { isObject } from '../../lib/type_checks.js';
|
||||
import { prepareDecrypt, decryptJWE, decryptResult, checkShared, checkRecipient, } from '../../lib/jwe_decrypt.js';
|
||||
export async function flattenedDecrypt(jwe, key, options) {
|
||||
if (!isObject(jwe)) {
|
||||
throw new JWEInvalid('Flattened JWE must be an object');
|
||||
}
|
||||
checkShared(jwe);
|
||||
checkRecipient(jwe);
|
||||
return decryptResult(jwe, await decryptJWE(jwe, prepareDecrypt(options), key));
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
import { unprotected, assertNotSet } from '../../lib/helpers.js';
|
||||
import { JWEInvalid } from '../../util/errors.js';
|
||||
import { createJWE } from '../../lib/jwe_encrypt.js';
|
||||
import { validateCritDuplicates } from '../../lib/options.js';
|
||||
export class FlattenedEncrypt {
|
||||
#plaintext;
|
||||
#protectedHeader;
|
||||
#sharedUnprotectedHeader;
|
||||
#unprotectedHeader;
|
||||
#aad;
|
||||
#cek;
|
||||
#iv;
|
||||
#keyManagementParameters;
|
||||
constructor(plaintext) {
|
||||
if (!(plaintext instanceof Uint8Array)) {
|
||||
throw new TypeError('plaintext must be an instance of Uint8Array');
|
||||
}
|
||||
this.#plaintext = plaintext;
|
||||
}
|
||||
setKeyManagementParameters(parameters) {
|
||||
assertNotSet(this.#keyManagementParameters, 'setKeyManagementParameters');
|
||||
this.#keyManagementParameters = parameters;
|
||||
return this;
|
||||
}
|
||||
setProtectedHeader(protectedHeader) {
|
||||
assertNotSet(this.#protectedHeader, 'setProtectedHeader');
|
||||
this.#protectedHeader = protectedHeader;
|
||||
return this;
|
||||
}
|
||||
setSharedUnprotectedHeader(sharedUnprotectedHeader) {
|
||||
assertNotSet(this.#sharedUnprotectedHeader, 'setSharedUnprotectedHeader');
|
||||
this.#sharedUnprotectedHeader = sharedUnprotectedHeader;
|
||||
return this;
|
||||
}
|
||||
setUnprotectedHeader(unprotectedHeader) {
|
||||
assertNotSet(this.#unprotectedHeader, 'setUnprotectedHeader');
|
||||
this.#unprotectedHeader = unprotectedHeader;
|
||||
return this;
|
||||
}
|
||||
setAdditionalAuthenticatedData(aad) {
|
||||
this.#aad = aad;
|
||||
return this;
|
||||
}
|
||||
setContentEncryptionKey(cek) {
|
||||
assertNotSet(this.#cek, 'setContentEncryptionKey');
|
||||
this.#cek = cek;
|
||||
return this;
|
||||
}
|
||||
setInitializationVector(iv) {
|
||||
assertNotSet(this.#iv, 'setInitializationVector');
|
||||
this.#iv = iv;
|
||||
return this;
|
||||
}
|
||||
async encrypt(key, options) {
|
||||
if (!this.#protectedHeader && !this.#unprotectedHeader && !this.#sharedUnprotectedHeader) {
|
||||
throw new JWEInvalid('either setProtectedHeader, setUnprotectedHeader, or sharedUnprotectedHeader must be called before #encrypt()');
|
||||
}
|
||||
validateCritDuplicates(JWEInvalid, this.#protectedHeader);
|
||||
return createJWE({
|
||||
plaintext: this.#plaintext,
|
||||
protectedHeader: this.#protectedHeader,
|
||||
unprotectedHeader: this.#unprotectedHeader,
|
||||
sharedUnprotectedHeader: this.#sharedUnprotectedHeader,
|
||||
aad: this.#aad,
|
||||
cek: this.#cek,
|
||||
iv: this.#iv,
|
||||
keyManagementParameters: this.#keyManagementParameters,
|
||||
crit: options?.crit,
|
||||
unprotectedParameters: options ? unprotected in options : false,
|
||||
}, key);
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
import { prepareDecrypt, shareJWE, decryptRecipient, decryptResult, checkShared, checkRecipient, } from '../../lib/jwe_decrypt.js';
|
||||
import { JWEDecryptionFailed, JWEInvalid } from '../../util/errors.js';
|
||||
import { isObject } from '../../lib/type_checks.js';
|
||||
export async function generalDecrypt(jwe, key, options) {
|
||||
if (!isObject(jwe)) {
|
||||
throw new JWEInvalid('General JWE must be an object');
|
||||
}
|
||||
if (!Array.isArray(jwe.recipients) || !jwe.recipients.every(isObject)) {
|
||||
throw new JWEInvalid('JWE Recipients missing or incorrect type');
|
||||
}
|
||||
if (!jwe.recipients.length) {
|
||||
throw new JWEInvalid('JWE Recipients has no members');
|
||||
}
|
||||
let shared;
|
||||
let token;
|
||||
try {
|
||||
checkShared(jwe);
|
||||
shared = prepareDecrypt(options);
|
||||
token = shareJWE(jwe);
|
||||
}
|
||||
catch {
|
||||
throw new JWEDecryptionFailed();
|
||||
}
|
||||
for (const recipient of jwe.recipients) {
|
||||
try {
|
||||
const flattened = {
|
||||
aad: jwe.aad,
|
||||
ciphertext: jwe.ciphertext,
|
||||
encrypted_key: recipient.encrypted_key,
|
||||
header: recipient.header,
|
||||
iv: jwe.iv,
|
||||
protected: jwe.protected,
|
||||
tag: jwe.tag,
|
||||
unprotected: jwe.unprotected,
|
||||
};
|
||||
checkRecipient(flattened);
|
||||
return decryptResult(flattened, await decryptRecipient(flattened, token, shared, key));
|
||||
}
|
||||
catch {
|
||||
}
|
||||
}
|
||||
throw new JWEDecryptionFailed();
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
import { FlattenedEncrypt } from '../flattened/encrypt.js';
|
||||
import { assertNotSet } from '../../lib/helpers.js';
|
||||
import { JWEInvalid } from '../../util/errors.js';
|
||||
import { generateCek } from '../../lib/content_encryption.js';
|
||||
import { encryptKeyManagement } from '../../lib/key_management.js';
|
||||
import { encode as b64u } from '../../util/base64url.js';
|
||||
import { validateCritDuplicates } from '../../lib/options.js';
|
||||
import { checkEncryptHeaders, encryptJWE } from '../../lib/jwe_encrypt.js';
|
||||
import { prepareKey } from '../../lib/key.js';
|
||||
import { jweAlgorithm } from '../../lib/jwe_algorithms.js';
|
||||
class IndividualRecipient {
|
||||
#parent;
|
||||
unprotectedHeader;
|
||||
keyManagementParameters;
|
||||
key;
|
||||
options;
|
||||
constructor(enc, key, options) {
|
||||
this.#parent = enc;
|
||||
this.key = key;
|
||||
this.options = options;
|
||||
}
|
||||
setUnprotectedHeader(unprotectedHeader) {
|
||||
assertNotSet(this.unprotectedHeader, 'setUnprotectedHeader');
|
||||
this.unprotectedHeader = unprotectedHeader;
|
||||
return this;
|
||||
}
|
||||
setKeyManagementParameters(parameters) {
|
||||
assertNotSet(this.keyManagementParameters, 'setKeyManagementParameters');
|
||||
this.keyManagementParameters = parameters;
|
||||
return this;
|
||||
}
|
||||
addRecipient(...args) {
|
||||
return this.#parent.addRecipient(...args);
|
||||
}
|
||||
encrypt(...args) {
|
||||
return this.#parent.encrypt(...args);
|
||||
}
|
||||
done() {
|
||||
return this.#parent;
|
||||
}
|
||||
}
|
||||
export class GeneralEncrypt {
|
||||
#plaintext;
|
||||
#recipients = [];
|
||||
#protectedHeader;
|
||||
#unprotectedHeader;
|
||||
#aad;
|
||||
constructor(plaintext) {
|
||||
this.#plaintext = plaintext;
|
||||
}
|
||||
addRecipient(key, options) {
|
||||
const recipient = new IndividualRecipient(this, key, { crit: options?.crit });
|
||||
this.#recipients.push(recipient);
|
||||
return recipient;
|
||||
}
|
||||
setProtectedHeader(protectedHeader) {
|
||||
assertNotSet(this.#protectedHeader, 'setProtectedHeader');
|
||||
this.#protectedHeader = protectedHeader;
|
||||
return this;
|
||||
}
|
||||
setSharedUnprotectedHeader(sharedUnprotectedHeader) {
|
||||
assertNotSet(this.#unprotectedHeader, 'setSharedUnprotectedHeader');
|
||||
this.#unprotectedHeader = sharedUnprotectedHeader;
|
||||
return this;
|
||||
}
|
||||
setAdditionalAuthenticatedData(aad) {
|
||||
this.#aad = aad;
|
||||
return this;
|
||||
}
|
||||
async encrypt() {
|
||||
if (!this.#recipients.length) {
|
||||
throw new JWEInvalid('at least one recipient must be added');
|
||||
}
|
||||
if (!(this.#plaintext instanceof Uint8Array)) {
|
||||
throw new TypeError('plaintext must be an instance of Uint8Array');
|
||||
}
|
||||
if (this.#recipients.length === 1) {
|
||||
const [recipient] = this.#recipients;
|
||||
const flattened = await new FlattenedEncrypt(this.#plaintext)
|
||||
.setAdditionalAuthenticatedData(this.#aad)
|
||||
.setProtectedHeader(this.#protectedHeader)
|
||||
.setSharedUnprotectedHeader(this.#unprotectedHeader)
|
||||
.setUnprotectedHeader(recipient.unprotectedHeader)
|
||||
.setKeyManagementParameters(recipient.keyManagementParameters)
|
||||
.encrypt(recipient.key, { ...recipient.options });
|
||||
const jwe = {
|
||||
ciphertext: flattened.ciphertext,
|
||||
iv: flattened.iv,
|
||||
recipients: [{}],
|
||||
tag: flattened.tag,
|
||||
};
|
||||
if (flattened.aad)
|
||||
jwe.aad = flattened.aad;
|
||||
if (flattened.protected)
|
||||
jwe.protected = flattened.protected;
|
||||
if (flattened.unprotected)
|
||||
jwe.unprotected = flattened.unprotected;
|
||||
if (flattened.encrypted_key)
|
||||
jwe.recipients[0].encrypted_key = flattened.encrypted_key;
|
||||
if (flattened.header)
|
||||
jwe.recipients[0].header = flattened.header;
|
||||
return jwe;
|
||||
}
|
||||
validateCritDuplicates(JWEInvalid, this.#protectedHeader);
|
||||
let enc;
|
||||
const inputs = [];
|
||||
const checked = [];
|
||||
for (let i = 0; i < this.#recipients.length; i++) {
|
||||
const recipient = this.#recipients[i];
|
||||
const input = {
|
||||
plaintext: this.#plaintext,
|
||||
protectedHeader: this.#protectedHeader,
|
||||
unprotectedHeader: recipient.unprotectedHeader,
|
||||
sharedUnprotectedHeader: this.#unprotectedHeader,
|
||||
aad: this.#aad,
|
||||
keyManagementParameters: recipient.keyManagementParameters,
|
||||
crit: recipient.options.crit,
|
||||
unprotectedParameters: true,
|
||||
};
|
||||
const headers = checkEncryptHeaders(input);
|
||||
inputs.push(input);
|
||||
checked.push(headers);
|
||||
if (headers.alg === 'dir' || headers.alg === 'ECDH-ES') {
|
||||
throw new JWEInvalid('"dir" and "ECDH-ES" alg may only be used with a single recipient');
|
||||
}
|
||||
if (!enc) {
|
||||
enc = headers.enc;
|
||||
}
|
||||
else if (enc !== headers.enc) {
|
||||
throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter must be the same for all recipients');
|
||||
}
|
||||
}
|
||||
const cek = generateCek(checked[0].encEntry);
|
||||
const jwe = {
|
||||
ciphertext: '',
|
||||
recipients: [],
|
||||
};
|
||||
for (let i = 0; i < this.#recipients.length; i++) {
|
||||
const recipient = this.#recipients[i];
|
||||
const target = {};
|
||||
jwe.recipients.push(target);
|
||||
if (i === 0) {
|
||||
const flattened = await encryptJWE({ ...inputs[0], cek }, checked[0], recipient.key);
|
||||
jwe.ciphertext = flattened.ciphertext;
|
||||
jwe.iv = flattened.iv;
|
||||
jwe.tag = flattened.tag;
|
||||
if (flattened.aad)
|
||||
jwe.aad = flattened.aad;
|
||||
if (flattened.protected)
|
||||
jwe.protected = flattened.protected;
|
||||
if (flattened.unprotected)
|
||||
jwe.unprotected = flattened.unprotected;
|
||||
target.encrypted_key = flattened.encrypted_key;
|
||||
if (flattened.header)
|
||||
target.header = flattened.header;
|
||||
continue;
|
||||
}
|
||||
const { alg } = checked[i];
|
||||
const k = await prepareKey(jweAlgorithm(alg), recipient.key, 'encrypt');
|
||||
const { encryptedKey, parameters } = await encryptKeyManagement(alg, checked[i].encEntry, k, cek, recipient.keyManagementParameters);
|
||||
target.encrypted_key = b64u(encryptedKey);
|
||||
if (recipient.unprotectedHeader || parameters)
|
||||
target.header = { ...recipient.unprotectedHeader, ...parameters };
|
||||
}
|
||||
return jwe;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user