immersive2/src/integration/encryption.ts

90 lines
2.5 KiB
TypeScript

import {createSHA256, pbkdf2} from "hash-wasm";
import aes from 'js-crypto-aes';
import {decode, encode} from "uint8-to-b64";
export class Encryption {
private _key: Uint8Array | null = null;
private _salt: Uint8Array | null = null;
private _iv: Uint8Array | null = null;
private _encrypted: Uint8Array | null = null;
constructor() {
}
private _ready: boolean = false;
public get ready() {
return this._ready;
}
public async setPassword(password: string, saltString?: string) {
if (saltString) {
this._salt = decode(saltString);
} else {
const salt = new Uint8Array(16);
window.crypto.getRandomValues(salt);
this._salt = salt;
}
this._key = await pbkdf2({
password: password,
salt: this._salt,
iterations: 10000,
hashLength: 32,
hashFunction: createSHA256(),
outputType: "binary"
});
this._ready = true;
}
public async encryptObject(obj: any) {
return await this.encrypt(JSON.stringify(obj));
}
public async decryptToObject(msg: string, iv: string) {
return JSON.parse(await this.decrypt(msg, iv));
}
public async encrypt(msg: string) {
if (!this._key) {
throw new Error('No password key set');
}
const iv = new Uint8Array(12);
window.crypto.getRandomValues(iv);
this._iv = iv;
const arr: Uint8Array = await aes.encrypt(
new TextEncoder().encode(msg), this._key, {name: 'AES-GCM', iv: this._iv, tagLength: 16});
this._encrypted = arr;
return this._encrypted;
}
public async decrypt(msg: string, iv: string) {
if (!this._key) {
throw new Error('No key set');
}
this._iv = decode(iv);
const msgArray = decode(msg);
//Uint8Array.from(atob(decode(msg)), c => c.charCodeAt(0));
const output = await aes.decrypt(msgArray, this._key, {name: 'AES-GCM', iv: this._iv, tagLength: 16});
return new TextDecoder().decode(output);
}
public getEncrypted() {
if (
!this._encrypted ||
!this._iv ||
!this._salt
) {
return null;
} else {
return {
encrypted: encode(this._encrypted),
salt: encode(this._salt),
iv: encode(this._iv)
}
}
}
}