mirror of
https://github.com/bitwarden/jslib
synced 2025-12-16 00:03:38 +00:00
Add encrypt and decrypt example of EncObject
This commit is contained in:
79
common/spec/services/crypto.service.spec.ts
Normal file
79
common/spec/services/crypto.service.spec.ts
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import { Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
||||||
|
|
||||||
|
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
|
||||||
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
import { Utils } from "jslib-common/misc/utils";
|
||||||
|
import { EncArrayBuffer } from "jslib-common/models/domain/encArrayBuffer";
|
||||||
|
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
|
||||||
|
import { CryptoService } from "jslib-common/services/crypto.service";
|
||||||
|
import { WebCryptoFunctionService } from "jslib-common/services/webCryptoFunction.service";
|
||||||
|
|
||||||
|
import { makeStaticByteArray } from "../utils";
|
||||||
|
|
||||||
|
describe("Crypto Service", () => {
|
||||||
|
let cryptoFunctionService: CryptoFunctionService;
|
||||||
|
let platformUtilsService: SubstituteOf<PlatformUtilsService>;
|
||||||
|
let logService: SubstituteOf<LogService>;
|
||||||
|
let stateService: SubstituteOf<StateService>;
|
||||||
|
|
||||||
|
let cryptoService: CryptoService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
cryptoFunctionService = new WebCryptoFunctionService(window);
|
||||||
|
platformUtilsService = Substitute.for<PlatformUtilsService>();
|
||||||
|
logService = Substitute.for<LogService>();
|
||||||
|
stateService = Substitute.for<StateService>();
|
||||||
|
|
||||||
|
cryptoService = new CryptoService(
|
||||||
|
cryptoFunctionService,
|
||||||
|
platformUtilsService,
|
||||||
|
logService,
|
||||||
|
stateService
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("encrypt EncObject", async () => {
|
||||||
|
const data = {
|
||||||
|
name: "Random",
|
||||||
|
};
|
||||||
|
|
||||||
|
const spy = jest
|
||||||
|
.spyOn(cryptoFunctionService, "randomBytes")
|
||||||
|
.mockImplementation(() => Promise.resolve(makeStaticByteArray(16)));
|
||||||
|
|
||||||
|
const key = makeStaticByteArray(32);
|
||||||
|
const symKey = new SymmetricCryptoKey(key.buffer);
|
||||||
|
|
||||||
|
const encrypted = await cryptoService.encryptObject(data, symKey);
|
||||||
|
|
||||||
|
expect(encrypted).toEqual({
|
||||||
|
encryptionType: 0,
|
||||||
|
data: "HQjAyiEJss8N3xwNqJen8R4aE/XToFeV7LIBI7SYkTc=",
|
||||||
|
iv: "AAECAwQFBgcICQoLDA0ODw==",
|
||||||
|
mac: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
spy.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("decrypt EncObject", async () => {
|
||||||
|
const key = makeStaticByteArray(32);
|
||||||
|
const symKey = new SymmetricCryptoKey(key.buffer);
|
||||||
|
|
||||||
|
const decrypted = await cryptoService.decryptObject(
|
||||||
|
{
|
||||||
|
encryptionType: 0,
|
||||||
|
data: "HQjAyiEJss8N3xwNqJen8R4aE/XToFeV7LIBI7SYkTc=",
|
||||||
|
iv: "AAECAwQFBgcICQoLDA0ODw==",
|
||||||
|
mac: null,
|
||||||
|
},
|
||||||
|
symKey
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(decrypted).toEqual({
|
||||||
|
name: "Random",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { EncObject } from "jslib-common/models/domain/encObject";
|
||||||
|
|
||||||
import { HashPurpose } from "../enums/hashPurpose";
|
import { HashPurpose } from "../enums/hashPurpose";
|
||||||
import { KdfType } from "../enums/kdfType";
|
import { KdfType } from "../enums/kdfType";
|
||||||
import { KeySuffixOptions } from "../enums/keySuffixOptions";
|
import { KeySuffixOptions } from "../enums/keySuffixOptions";
|
||||||
@@ -75,12 +77,14 @@ export abstract class CryptoService {
|
|||||||
encKey?: SymmetricCryptoKey
|
encKey?: SymmetricCryptoKey
|
||||||
) => Promise<[SymmetricCryptoKey, EncString]>;
|
) => Promise<[SymmetricCryptoKey, EncString]>;
|
||||||
encrypt: (plainValue: string | ArrayBuffer, key?: SymmetricCryptoKey) => Promise<EncString>;
|
encrypt: (plainValue: string | ArrayBuffer, key?: SymmetricCryptoKey) => Promise<EncString>;
|
||||||
|
encryptObject: <T>(plainValue: T, key?: SymmetricCryptoKey) => Promise<EncObject<T>>;
|
||||||
encryptToBytes: (plainValue: ArrayBuffer, key?: SymmetricCryptoKey) => Promise<EncArrayBuffer>;
|
encryptToBytes: (plainValue: ArrayBuffer, key?: SymmetricCryptoKey) => Promise<EncArrayBuffer>;
|
||||||
rsaEncrypt: (data: ArrayBuffer, publicKey?: ArrayBuffer) => Promise<EncString>;
|
rsaEncrypt: (data: ArrayBuffer, publicKey?: ArrayBuffer) => Promise<EncString>;
|
||||||
rsaDecrypt: (encValue: string, privateKeyValue?: ArrayBuffer) => Promise<ArrayBuffer>;
|
rsaDecrypt: (encValue: string, privateKeyValue?: ArrayBuffer) => Promise<ArrayBuffer>;
|
||||||
decryptToBytes: (encString: EncString, key?: SymmetricCryptoKey) => Promise<ArrayBuffer>;
|
decryptToBytes: (encString: EncString, key?: SymmetricCryptoKey) => Promise<ArrayBuffer>;
|
||||||
decryptToUtf8: (encString: EncString, key?: SymmetricCryptoKey) => Promise<string>;
|
decryptToUtf8: (encString: EncString, key?: SymmetricCryptoKey) => Promise<string>;
|
||||||
decryptFromBytes: (encBuf: ArrayBuffer, key: SymmetricCryptoKey) => Promise<ArrayBuffer>;
|
decryptFromBytes: (encBuf: ArrayBuffer, key: SymmetricCryptoKey) => Promise<ArrayBuffer>;
|
||||||
|
decryptObject: <T>(encrypted: EncObject<T>, key?: SymmetricCryptoKey) => Promise<T>;
|
||||||
randomNumber: (min: number, max: number) => Promise<number>;
|
randomNumber: (min: number, max: number) => Promise<number>;
|
||||||
validateKey: (key: SymmetricCryptoKey) => Promise<boolean>;
|
validateKey: (key: SymmetricCryptoKey) => Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ export class EncObject<T> {
|
|||||||
* @param mac
|
* @param mac
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
private encryptionType: EncryptionType,
|
public encryptionType: EncryptionType,
|
||||||
private data: string,
|
public data: string,
|
||||||
private iv: string,
|
public iv: string,
|
||||||
private mac: string
|
public mac: string
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import * as bigInt from "big-integer";
|
import * as bigInt from "big-integer";
|
||||||
|
|
||||||
|
import { EncObject } from "jslib-common/models/domain/encObject";
|
||||||
|
|
||||||
import { CryptoService as CryptoServiceAbstraction } from "../abstractions/crypto.service";
|
import { CryptoService as CryptoServiceAbstraction } from "../abstractions/crypto.service";
|
||||||
import { CryptoFunctionService } from "../abstractions/cryptoFunction.service";
|
import { CryptoFunctionService } from "../abstractions/cryptoFunction.service";
|
||||||
import { LogService } from "../abstractions/log.service";
|
import { LogService } from "../abstractions/log.service";
|
||||||
@@ -522,6 +524,39 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
return new EncString(encObj.key.encType, data, iv, mac);
|
return new EncString(encObj.key.encType, data, iv, mac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async encryptObject<T>(obj: T, key?: SymmetricCryptoKey): Promise<EncObject<T>> {
|
||||||
|
if (obj == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const json = JSON.stringify(obj);
|
||||||
|
const plainBuf = Utils.fromUtf8ToArray(json).buffer;
|
||||||
|
|
||||||
|
const encObj = await this.aesEncrypt(plainBuf, key);
|
||||||
|
const iv = Utils.fromBufferToB64(encObj.iv);
|
||||||
|
const data = Utils.fromBufferToB64(encObj.data);
|
||||||
|
const mac = encObj.mac != null ? Utils.fromBufferToB64(encObj.mac) : null;
|
||||||
|
return new EncObject(encObj.key.encType, data, iv, mac);
|
||||||
|
}
|
||||||
|
|
||||||
|
async decryptObject<T>(obj: EncObject<T>, key?: SymmetricCryptoKey): Promise<T> {
|
||||||
|
if (obj == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const decryptedJson = await this.aesDecryptToUtf8(
|
||||||
|
obj.encryptionType,
|
||||||
|
obj.data,
|
||||||
|
obj.iv,
|
||||||
|
obj.mac,
|
||||||
|
key
|
||||||
|
);
|
||||||
|
|
||||||
|
const decrypted = JSON.parse(decryptedJson);
|
||||||
|
|
||||||
|
return decrypted;
|
||||||
|
}
|
||||||
|
|
||||||
async encryptToBytes(plainValue: ArrayBuffer, key?: SymmetricCryptoKey): Promise<EncArrayBuffer> {
|
async encryptToBytes(plainValue: ArrayBuffer, key?: SymmetricCryptoKey): Promise<EncArrayBuffer> {
|
||||||
const encValue = await this.aesEncrypt(plainValue, key);
|
const encValue = await this.aesEncrypt(plainValue, key);
|
||||||
let macLen = 0;
|
let macLen = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user