lib6/encryption/local-key-encapsulation.js
/**
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [https://neo4j.com]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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());
});
};
import { newError } from '../error';
import CryptoProvider from './node/crypto';
function u8ToB64(u) {
return btoa(String.fromCharCode(...u));
}
function b64Tou8(b) {
return Uint8Array.from(atob(b), (c) => c.charCodeAt(0));
}
/**
* An implementation of {@link KeyEncapsulationService} that uses a local, 256-bit, AES-GCM Key Encryption Key (KEK) to encrypt keys.
*
* @experimental Part of the Client-Side Encrytion preview feature
*/
export class LocalKeyEncapsulationService {
constructor(kek) {
if (kek.byteLength !== 32) {
throw newError(`LocalKeyEncapsualationService master key must be of byteLength 32 (256 bits), got ${kek.byteLength} (${kek.byteLength * 8} bits)`);
}
this._kek = kek;
this._cryptoProvider = new CryptoProvider();
}
/**
* Creates a new key, encapsulates it with the local KEK and returns the result.
*
* @param {KeyEncapsulationOptions} options the encapsulation options, depends on the implementation
* @return {Promise<EncapsulationResult>} a promise that resolves to the encapsulation result
* @experimental Part of the Client-Side Encrytion preview feature
*/
encapsulate(options) {
return __awaiter(this, void 0, void 0, function* () {
const DEK = this._cryptoProvider.getRandomValues(32);
const encapulatedDEK = yield this._cryptoProvider.encrypt(this._kek, DEK.buffer, undefined);
return new LocalEncapsulationResult(DEK, new Int8Array(encapulatedDEK.cyphertext), { iv: u8ToB64(encapulatedDEK.iv) });
});
}
/**
* Decapsulates encapsulated bytes with the local KEK.
*
* @param {Int8Array} encapsulation the encapsulated byte}
* @param {KeyEncapsulationOptions} metadata the key metadata
* @return {Promise<Uint8Array>} a promise that resolves to the decapsulated key
* @experimental Part of the Client-Side Encrytion preview feature
*/
decapsulate(encapsulation, metadata) {
return __awaiter(this, void 0, void 0, function* () {
return new Uint8Array(yield this._cryptoProvider.decrypt(this._kek, b64Tou8(metadata.iv), encapsulation.buffer, undefined));
});
}
}
/**
* @private
*/
export class LocalEncapsulationResult {
constructor(DEK, encapsulation, options) {
this._dek = DEK;
this._encapsulation = encapsulation;
this._options = options;
}
encapsulation() {
return this._encapsulation;
}
options() {
return this._options;
}
key() {
return this._dek;
}
}
/**
* Returns a new {@link KeyEncapsulationService} implementation that uses the provided AES-256
* {@link SecretKey} as a master key for encapsulating and decapsulating data keys.
*
* @param {Uint8Array} masterKey the AES-256 master key
* @return {KeyEncapsulationService} the new key encapsulation service
* @experimental Part of the Client-Side Encrytion preview feature
*/
export function localKeyEncapsulationService(masterKey) {
return new LocalKeyEncapsulationService(masterKey);
}