82 lines
2.6 KiB
TypeScript
82 lines
2.6 KiB
TypeScript
import { PBKDF2Params, AESKey, AESEncryptionParams } from "./crypto";
|
|
import { Err, ErrorCode } from "./error";
|
|
import { sjcl } from "../vendor/sjcl";
|
|
|
|
// Shorthands for codec functions
|
|
const bytesToBits = sjcl.codec.bytes.toBits;
|
|
const bitsToBytes = sjcl.codec.bytes.fromBits;
|
|
|
|
/**
|
|
* [[CrypoProvider]] implemenation using the [SJCL](https://github.com/bitwiseshiftleft/sjcl)
|
|
* library. This is used to decrypt legacy (<3.x) Padlock containers that use AES in CCM mode
|
|
* which is unfortunately not supported by the WebCrypto standard. Only
|
|
* supports encryption/decryption using AES-CCM.
|
|
*/
|
|
const SJCLProvider = {
|
|
isAvailable() {
|
|
return true;
|
|
},
|
|
|
|
randomBytes(_bytes: number): Uint8Array {
|
|
throw new Err(ErrorCode.NOT_SUPPORTED);
|
|
},
|
|
|
|
async deriveKey(_password: string, _params: PBKDF2Params): Promise<AESKey> {
|
|
throw new Err(ErrorCode.NOT_SUPPORTED);
|
|
},
|
|
|
|
async randomKey(_n = 256) {
|
|
throw new Err(ErrorCode.NOT_SUPPORTED);
|
|
},
|
|
|
|
async decrypt(key: AESKey, ct: Uint8Array, params: AESEncryptionParams): Promise<Uint8Array> {
|
|
if (params.algorithm !== "AES-CCM") {
|
|
throw new Err(ErrorCode.INVALID_ENCRYPTION_PARAMS);
|
|
}
|
|
|
|
// Only AES and CCM are supported
|
|
const algorithm = "aes";
|
|
const mode = "ccm";
|
|
|
|
try {
|
|
const cipher = new sjcl.cipher[algorithm](bytesToBits(key));
|
|
const pt = sjcl.mode[mode].decrypt(
|
|
cipher,
|
|
bytesToBits(ct),
|
|
bytesToBits(params.iv!),
|
|
bytesToBits(params.additionalData!),
|
|
params.tagSize
|
|
);
|
|
return new Uint8Array(bitsToBytes(pt));
|
|
} catch (e) {
|
|
throw new Err(ErrorCode.DECRYPTION_FAILED);
|
|
}
|
|
},
|
|
|
|
async encrypt(key: AESKey, pt: Uint8Array, params: AESEncryptionParams): Promise<Uint8Array> {
|
|
if (params.algorithm !== "AES-CCM") {
|
|
throw new Err(ErrorCode.INVALID_ENCRYPTION_PARAMS);
|
|
}
|
|
|
|
// Only AES and CCM are supported
|
|
const algorithm = "aes";
|
|
const mode = "ccm";
|
|
|
|
try {
|
|
const cipher = new sjcl.cipher[algorithm](bytesToBits(key));
|
|
var ct = sjcl.mode[mode].encrypt(
|
|
cipher,
|
|
bytesToBits(pt),
|
|
bytesToBits(params.iv!),
|
|
bytesToBits(params.additionalData!),
|
|
params.tagSize
|
|
);
|
|
return new Uint8Array(bitsToBytes(ct));
|
|
} catch (e) {
|
|
throw new Err(ErrorCode.ENCRYPTION_FAILED);
|
|
}
|
|
},
|
|
};
|
|
|
|
export default SJCLProvider;
|