@guarani/jose
Version:
Implementation of the RFCs of the JOSE Working Group.
102 lines (101 loc) • 4.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.A256CBC_HS512 = exports.A192CBC_HS384 = exports.A128CBC_HS256 = void 0;
const crypto_1 = require("crypto");
const invalid_json_web_encryption_exception_1 = require("../../../exceptions/invalid-json-web-encryption.exception");
const jsonwebencryption_contentencryption_algorithm_1 = require("./jsonwebencryption-contentencryption.algorithm");
/**
* Implementation of the AES-CBC JSON Web Encryption Content Encryption Algorithm.
*/
class CBCHS2ContentEncryptionAlgorithm extends jsonwebencryption_contentencryption_algorithm_1.JsonWebEncryptionContentEncryptionAlgorithm {
/**
* Instantiates a new AES-CBC JSON Web Encryption Content Encryption to Encrypt and Decrypt a Plaintext.
*
* @param algorithm Name of the JSON Web Encryption Content Encryption Algorithm.
*/
constructor(algorithm) {
const regex = /^A([0-9]{3})CBC-HS([0-9]{3})$/;
const [keySize, hashSize] = regex
.exec(algorithm)
.slice(1)
.map((value) => Number.parseInt(value));
super(keySize * 2, 128, algorithm);
this.keySize = keySize;
this.hashAlgorithm = `SHA${hashSize}`;
this.cipherAlgorithm = `aes-${keySize}-cbc`;
}
/**
* Encrypts the provided Plaintext.
*
* @param plaintext Plaintext to be Cncrypted.
* @param aad Additional Authenticated Data.
* @param iv Initialization Vector.
* @param key Content Encryption Key used to Encrypt the provided Plaintext.
* @returns Resulting Ciphertext and Authentication Tag.
*/
async encrypt(plaintext, aad, iv, key) {
this.validateInitializationVector(iv);
this.validateContentEncryptionKey(key);
const macKey = key.subarray(0, this.keySize >> 3);
const encKey = key.subarray(this.keySize >> 3);
const cipher = (0, crypto_1.createCipheriv)(this.cipherAlgorithm, encKey, iv);
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
const tag = this.getAuthTag(ciphertext, iv, aad, macKey);
return { ciphertext, tag };
}
/**
* Decrypts the provided Ciphertext back to its original Plaintext.
*
* @param ciphertext Ciphertext to be Decrypted.
* @param aad Additional Authenticated Data.
* @param iv Initialization Vector.
* @param tag Authentication Tag.
* @param key Content Encryption Key used to Decrypt the provided Ciphertext.
* @returns Resulting Plaintext.
*/
async decrypt(ciphertext, aad, iv, tag, key) {
this.validateInitializationVector(iv);
this.validateContentEncryptionKey(key);
const macKey = key.subarray(0, this.keySize >> 3);
const encKey = key.subarray(this.keySize >> 3);
const expectedTag = this.getAuthTag(ciphertext, iv, aad, macKey);
if (!(0, crypto_1.timingSafeEqual)(tag, expectedTag)) {
throw new invalid_json_web_encryption_exception_1.InvalidJsonWebEncryptionException();
}
const decipher = (0, crypto_1.createDecipheriv)(this.cipherAlgorithm, encKey, iv);
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
return plaintext;
}
/**
* Generates the Authentication Tag of the provided Ciphertext.
*
* @param ciphertext Ciphertext to be Decrypted.
* @param iv Initialization Vector.
* @param aad Additional Authenticated Data.
* @param key Content Encryption Key.
* @returns Authentication Tag.
*/
getAuthTag(ciphertext, iv, aad, key) {
const len = aad.length << 3;
const buf = Buffer.alloc(8);
buf.writeUInt32BE(Math.floor(len / 2 ** 32), 0);
buf.writeUInt32BE(len % 2 ** 32, 4);
const data = Buffer.concat([aad, iv, ciphertext, buf]);
return (0, crypto_1.createHmac)(this.hashAlgorithm, key)
.update(data)
.digest()
.slice(0, this.keySize >> 3);
}
}
/**
* AES_128_CBC_HMAC_SHA_256 authenticated encryption algorithm.
*/
exports.A128CBC_HS256 = new CBCHS2ContentEncryptionAlgorithm('A128CBC-HS256');
/**
* AES_192_CBC_HMAC_SHA_384 authenticated encryption algorithm.
*/
exports.A192CBC_HS384 = new CBCHS2ContentEncryptionAlgorithm('A192CBC-HS384');
/**
* AES_256_CBC_HMAC_SHA_512 authenticated encryption algorithm.
*/
exports.A256CBC_HS512 = new CBCHS2ContentEncryptionAlgorithm('A256CBC-HS512');