commit
ae9ac92c9e
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"plugins": [
|
||||||
|
"@typescript-eslint"
|
||||||
|
],
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/eslint-recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"plugin:import/errors",
|
||||||
|
"plugin:import/warnings",
|
||||||
|
"plugin:import/typescript"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"@typescript-eslint/ban-ts-ignore": 0,
|
||||||
|
"@typescript-eslint/camelcase": 0,
|
||||||
|
"@typescript-eslint/explicit-function-return-type": 0,
|
||||||
|
"@typescript-eslint/interface-name-prefix": 0,
|
||||||
|
"@typescript-eslint/no-explicit-any": 0,
|
||||||
|
"@typescript-eslint/semi": 1,
|
||||||
|
"semi": "off",
|
||||||
|
"import/order": ["error", {
|
||||||
|
"groups": ["builtin", "external", "internal"],
|
||||||
|
"alphabetize": {
|
||||||
|
"order": "asc",
|
||||||
|
"caseInsensitive": true
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
|
@ -18,8 +18,8 @@
|
||||||
"clear": "rimraf build/*",
|
"clear": "rimraf build/*",
|
||||||
"rebuild": "npm run clear && npm run build",
|
"rebuild": "npm run clear && npm run build",
|
||||||
"build:module": "rollup -c",
|
"build:module": "rollup -c",
|
||||||
"lint": "tslint -p .",
|
"lint": "eslint . --ext .ts",
|
||||||
"lint:fix": "tslint --fix -p .",
|
"lint:fix": "eslint --fix . --ext .ts",
|
||||||
"prepub": "npm run lint && npm run rebuild",
|
"prepub": "npm run lint && npm run rebuild",
|
||||||
"pub": "npm version patch && npm publish",
|
"pub": "npm version patch && npm publish",
|
||||||
"postpub": "git push && git push --tags origin master",
|
"postpub": "git push && git push --tags origin master",
|
||||||
|
@ -47,18 +47,21 @@
|
||||||
"url": "https://github.com/PeculiarVentures/webcrypto/issues"
|
"url": "https://github.com/PeculiarVentures/webcrypto/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/PeculiarVentures/webcrypto#readme",
|
"homepage": "https://github.com/PeculiarVentures/webcrypto#readme",
|
||||||
"banner": "// Copyright (c) 2019, Peculiar Ventures, All rights reserved.",
|
"banner": "// Copyright (c) 2020, Peculiar Ventures, All rights reserved.",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^7.0.2",
|
||||||
"@types/node": "^12.12.29",
|
"@types/node": "^12.12.30",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^2.23.0",
|
||||||
|
"@typescript-eslint/parser": "^2.23.0",
|
||||||
"coveralls": "^3.0.9",
|
"coveralls": "^3.0.9",
|
||||||
"mocha": "^6.2.2",
|
"eslint": "^6.8.0",
|
||||||
|
"eslint-plugin-import": "^2.20.1",
|
||||||
|
"mocha": "^7.1.0",
|
||||||
"nyc": "^14.1.1",
|
"nyc": "^14.1.1",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"rollup": "^1.32.1",
|
"rollup": "^2.0.6",
|
||||||
"rollup-plugin-typescript2": "^0.25.3",
|
"rollup-plugin-typescript2": "^0.26.0",
|
||||||
"ts-node": "^8.6.2",
|
"ts-node": "^8.6.2",
|
||||||
"tslint": "^5.20.1",
|
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -87,5 +90,10 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.12.0"
|
"node": ">=10.12.0"
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"require": "ts-node/register",
|
||||||
|
"extension": ["ts"],
|
||||||
|
"files": "test/**/*.ts"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { AsnIntegerConverter, AsnParser, AsnProp, AsnPropTypes, AsnSerializer, IAsnConverter } from "@peculiar/asn1-schema";
|
import { AsnIntegerConverter, AsnProp, AsnPropTypes, AsnSerializer } from "@peculiar/asn1-schema";
|
||||||
import { IJsonConvertible } from "@peculiar/json-schema";
|
import { IJsonConvertible } from "@peculiar/json-schema";
|
||||||
import { Convert } from "pvtsutils";
|
import { Convert } from "pvtsutils";
|
||||||
import { EcPublicKey } from "./ec_public_key";
|
import { EcPublicKey } from "./ec_public_key";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { AsnIntegerArrayBufferConverter, AsnProp, AsnPropTypes, IAsnConverter } from "@peculiar/asn1-schema";
|
import { AsnProp, AsnPropTypes, IAsnConverter } from "@peculiar/asn1-schema";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import * as asn1 from "asn1js";
|
import * as asn1 from "asn1js";
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { CryptoKey } from "./keys";
|
export { CryptoKey } from "webcrypto-core";
|
||||||
export { Crypto } from "./crypto";
|
export { Crypto } from "./crypto";
|
||||||
|
|
|
@ -7,7 +7,7 @@ export class CryptoKey extends core.CryptoKey {
|
||||||
public algorithm: KeyAlgorithm = { name: "" };
|
public algorithm: KeyAlgorithm = { name: "" };
|
||||||
|
|
||||||
@JsonProp({ name: "ext", type: JsonPropTypes.Boolean, optional: true })
|
@JsonProp({ name: "ext", type: JsonPropTypes.Boolean, optional: true })
|
||||||
public extractable: boolean = false;
|
public extractable = false;
|
||||||
|
|
||||||
public type: KeyType = "secret";
|
public type: KeyType = "secret";
|
||||||
|
|
||||||
|
@ -15,8 +15,8 @@ export class CryptoKey extends core.CryptoKey {
|
||||||
public usages: KeyUsage[] = [];
|
public usages: KeyUsage[] = [];
|
||||||
|
|
||||||
@JsonProp({ type: JsonPropTypes.String })
|
@JsonProp({ type: JsonPropTypes.String })
|
||||||
protected kty: string = "oct";
|
protected kty = "oct";
|
||||||
|
|
||||||
@JsonProp({ type: JsonPropTypes.String })
|
@JsonProp({ type: JsonPropTypes.String })
|
||||||
protected alg: string = "";
|
protected alg = "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
|
import { getCryptoKey, setCryptoKey } from "../storage";
|
||||||
import { AesCrypto } from "./crypto";
|
import { AesCrypto } from "./crypto";
|
||||||
import { AesCryptoKey } from "./key";
|
import { AesCryptoKey } from "./key";
|
||||||
|
|
||||||
|
@ -13,28 +14,29 @@ export class AesCbcProvider extends core.AesCbcProvider {
|
||||||
extractable,
|
extractable,
|
||||||
keyUsages);
|
keyUsages);
|
||||||
|
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return AesCrypto.encrypt(algorithm, key, new Uint8Array(data));
|
return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return AesCrypto.decrypt(algorithm, key, new Uint8Array(data));
|
return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||||
return AesCrypto.exportKey(format, key);
|
return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||||
return AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
const key = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
||||||
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof AesCryptoKey)) {
|
if (!(getCryptoKey(key) instanceof AesCryptoKey)) {
|
||||||
throw new TypeError("key: Is not a AesCryptoKey");
|
throw new TypeError("key: Is not a AesCryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import * as crypto from "crypto";
|
import * as crypto from "crypto";
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { AesCrypto } from "./crypto";
|
import { AesCrypto } from "./crypto";
|
||||||
import { AesCryptoKey } from "./key";
|
import { AesCryptoKey } from "./key";
|
||||||
|
|
||||||
|
@ -34,6 +35,35 @@ function xor(a: Buffer, b: Buffer) {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function aes(key: Buffer, message: Buffer) {
|
||||||
|
const cipher = crypto.createCipheriv(`aes${key.length << 3}`, key, zero);
|
||||||
|
const result = cipher.update(message);
|
||||||
|
cipher.final();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMessageBlock(message: Buffer, blockIndex: number) {
|
||||||
|
const block = Buffer.alloc(blockSize);
|
||||||
|
const start = blockIndex * blockSize;
|
||||||
|
const end = start + blockSize;
|
||||||
|
|
||||||
|
message.copy(block, 0, start, end);
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPaddedMessageBlock(message: Buffer, blockIndex: number) {
|
||||||
|
const block = Buffer.alloc(blockSize);
|
||||||
|
const start = blockIndex * blockSize;
|
||||||
|
const end = message.length;
|
||||||
|
|
||||||
|
block.fill(0);
|
||||||
|
message.copy(block, 0, start, end);
|
||||||
|
block[end - start] = 0x80;
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
function generateSubkeys(key: Buffer) {
|
function generateSubkeys(key: Buffer) {
|
||||||
const l = aes(key, zero);
|
const l = aes(key, zero);
|
||||||
|
|
||||||
|
@ -50,19 +80,11 @@ function generateSubkeys(key: Buffer) {
|
||||||
return { subkey1, subkey2 };
|
return { subkey1, subkey2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
function aes(key: Buffer, message: Buffer) {
|
|
||||||
const cipher = crypto.createCipheriv(`aes${key.length << 3}`, key, zero);
|
|
||||||
const result = cipher.update(message);
|
|
||||||
cipher.final();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function aesCmac(key: Buffer, message: Buffer) {
|
function aesCmac(key: Buffer, message: Buffer) {
|
||||||
const subkeys = generateSubkeys(key);
|
const subkeys = generateSubkeys(key);
|
||||||
let blockCount = Math.ceil(message.length / blockSize);
|
let blockCount = Math.ceil(message.length / blockSize);
|
||||||
let lastBlockCompleteFlag: boolean;
|
let lastBlockCompleteFlag: boolean;
|
||||||
let lastBlock: Buffer;
|
let lastBlock: Buffer;
|
||||||
let lastBlockIndex: number;
|
|
||||||
|
|
||||||
if (blockCount === 0) {
|
if (blockCount === 0) {
|
||||||
blockCount = 1;
|
blockCount = 1;
|
||||||
|
@ -70,7 +92,7 @@ function aesCmac(key: Buffer, message: Buffer) {
|
||||||
} else {
|
} else {
|
||||||
lastBlockCompleteFlag = (message.length % blockSize === 0);
|
lastBlockCompleteFlag = (message.length % blockSize === 0);
|
||||||
}
|
}
|
||||||
lastBlockIndex = blockCount - 1;
|
const lastBlockIndex = blockCount - 1;
|
||||||
|
|
||||||
if (lastBlockCompleteFlag) {
|
if (lastBlockCompleteFlag) {
|
||||||
lastBlock = xor(getMessageBlock(message, lastBlockIndex), subkeys.subkey1);
|
lastBlock = xor(getMessageBlock(message, lastBlockIndex), subkeys.subkey1);
|
||||||
|
@ -89,28 +111,6 @@ function aesCmac(key: Buffer, message: Buffer) {
|
||||||
return aes(key, y);
|
return aes(key, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMessageBlock(message: Buffer, blockIndex: number) {
|
|
||||||
const block = new Buffer(blockSize);
|
|
||||||
const start = blockIndex * blockSize;
|
|
||||||
const end = start + blockSize;
|
|
||||||
|
|
||||||
message.copy(block, 0, start, end);
|
|
||||||
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPaddedMessageBlock(message: Buffer, blockIndex: number) {
|
|
||||||
const block = new Buffer(blockSize);
|
|
||||||
const start = blockIndex * blockSize;
|
|
||||||
const end = message.length;
|
|
||||||
|
|
||||||
block.fill(0);
|
|
||||||
message.copy(block, 0, start, end);
|
|
||||||
block[end - start] = 0x80;
|
|
||||||
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AesCmacProvider extends core.AesCmacProvider {
|
export class AesCmacProvider extends core.AesCmacProvider {
|
||||||
|
|
||||||
public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||||
|
@ -122,11 +122,11 @@ export class AesCmacProvider extends core.AesCmacProvider {
|
||||||
extractable,
|
extractable,
|
||||||
keyUsages);
|
keyUsages);
|
||||||
|
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onSign(algorithm: AesCmacParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onSign(algorithm: AesCmacParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
const result = aesCmac(key.data, Buffer.from(data));
|
const result = aesCmac(getCryptoKey(key).data, Buffer.from(data));
|
||||||
return new Uint8Array(result).buffer;
|
return new Uint8Array(result).buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,16 +136,17 @@ export class AesCmacProvider extends core.AesCmacProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||||
return AesCrypto.exportKey(format, key);
|
return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||||
return AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
||||||
|
return setCryptoKey(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof AesCryptoKey)) {
|
if (!(getCryptoKey(key) instanceof AesCryptoKey)) {
|
||||||
throw new TypeError("key: Is not a AesCryptoKey");
|
throw new TypeError("key: Is not a AesCryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { AesCrypto } from "./crypto";
|
import { AesCrypto } from "./crypto";
|
||||||
import { AesCryptoKey } from "./key";
|
import { AesCryptoKey } from "./key";
|
||||||
|
|
||||||
|
@ -13,28 +14,29 @@ export class AesCtrProvider extends core.AesCtrProvider {
|
||||||
extractable,
|
extractable,
|
||||||
keyUsages);
|
keyUsages);
|
||||||
|
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onEncrypt(algorithm: AesCtrParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onEncrypt(algorithm: AesCtrParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return AesCrypto.encrypt(algorithm, key, new Uint8Array(data));
|
return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onDecrypt(algorithm: AesCtrParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onDecrypt(algorithm: AesCtrParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return AesCrypto.decrypt(algorithm, key, new Uint8Array(data));
|
return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||||
return AesCrypto.exportKey(format, key);
|
return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||||
return AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
||||||
|
return setCryptoKey(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof AesCryptoKey)) {
|
if (!(getCryptoKey(key) instanceof AesCryptoKey)) {
|
||||||
throw new TypeError("key: Is not a AesCryptoKey");
|
throw new TypeError("key: Is not a AesCryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { AesCrypto } from "./crypto";
|
import { AesCrypto } from "./crypto";
|
||||||
import { AesCryptoKey } from "./key";
|
import { AesCryptoKey } from "./key";
|
||||||
|
|
||||||
|
@ -13,28 +14,29 @@ export class AesEcbProvider extends core.AesEcbProvider {
|
||||||
extractable,
|
extractable,
|
||||||
keyUsages);
|
keyUsages);
|
||||||
|
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return AesCrypto.encrypt(algorithm, key, new Uint8Array(data));
|
return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return AesCrypto.decrypt(algorithm, key, new Uint8Array(data));
|
return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||||
return AesCrypto.exportKey(format, key);
|
return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||||
return AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
||||||
|
return setCryptoKey(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof AesCryptoKey)) {
|
if (!(getCryptoKey(key) instanceof AesCryptoKey)) {
|
||||||
throw new TypeError("key: Is not a AesCryptoKey");
|
throw new TypeError("key: Is not a AesCryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { AesCrypto } from "./crypto";
|
import { AesCrypto } from "./crypto";
|
||||||
import { AesCryptoKey } from "./key";
|
import { AesCryptoKey } from "./key";
|
||||||
|
|
||||||
|
@ -13,28 +14,29 @@ export class AesGcmProvider extends core.AesGcmProvider {
|
||||||
extractable,
|
extractable,
|
||||||
keyUsages);
|
keyUsages);
|
||||||
|
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onEncrypt(algorithm: AesGcmParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onEncrypt(algorithm: AesGcmParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return AesCrypto.encrypt(algorithm, key, new Uint8Array(data));
|
return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onDecrypt(algorithm: AesGcmParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onDecrypt(algorithm: AesGcmParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return AesCrypto.decrypt(algorithm, key, new Uint8Array(data));
|
return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||||
return AesCrypto.exportKey(format, key);
|
return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||||
return AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
||||||
|
return setCryptoKey(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof AesCryptoKey)) {
|
if (!(getCryptoKey(key) instanceof AesCryptoKey)) {
|
||||||
throw new TypeError("key: Is not a AesCryptoKey");
|
throw new TypeError("key: Is not a AesCryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { AesCrypto } from "./crypto";
|
import { AesCrypto } from "./crypto";
|
||||||
import { AesCryptoKey } from "./key";
|
import { AesCryptoKey } from "./key";
|
||||||
|
|
||||||
export class AesKwProvider extends core.AesKwProvider {
|
export class AesKwProvider extends core.AesKwProvider {
|
||||||
|
|
||||||
public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||||
return await AesCrypto.generateKey(
|
const res = await AesCrypto.generateKey(
|
||||||
{
|
{
|
||||||
name: this.name,
|
name: this.name,
|
||||||
length: algorithm.length,
|
length: algorithm.length,
|
||||||
|
@ -13,27 +14,29 @@ export class AesKwProvider extends core.AesKwProvider {
|
||||||
extractable,
|
extractable,
|
||||||
keyUsages,
|
keyUsages,
|
||||||
);
|
);
|
||||||
|
return setCryptoKey(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||||
return AesCrypto.exportKey(format, key);
|
return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||||
return AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
||||||
|
return setCryptoKey(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return AesCrypto.encrypt(algorithm, key, new Uint8Array(data));
|
return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return AesCrypto.decrypt(algorithm, key, new Uint8Array(data));
|
return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof AesCryptoKey)) {
|
if (!(getCryptoKey(key) instanceof AesCryptoKey)) {
|
||||||
throw new TypeError("key: Is not a AesCryptoKey");
|
throw new TypeError("key: Is not a AesCryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
|
||||||
import crypto, { CipherGCM, DecipherGCM } from "crypto";
|
import crypto, { CipherGCM, DecipherGCM } from "crypto";
|
||||||
|
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
import { CryptoKey } from "../../keys";
|
import { CryptoKey } from "../../keys";
|
||||||
import { AesCryptoKey } from "./key";
|
import { AesCryptoKey } from "./key";
|
||||||
|
|
||||||
const WRONG_KEY_TYPE = `Key must be instance of ${AesCryptoKey.name}`;
|
|
||||||
|
|
||||||
export class AesCrypto {
|
export class AesCrypto {
|
||||||
|
|
||||||
public static AES_KW_IV = Buffer.from("A6A6A6A6A6A6A6A6", "hex");
|
public static AES_KW_IV = Buffer.from("A6A6A6A6A6A6A6A6", "hex");
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
|
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
import { DesParams } from "webcrypto-core";
|
import { DesParams } from "webcrypto-core";
|
||||||
import { CryptoKey } from "../../keys";
|
import { CryptoKey } from "../../keys";
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
import { CryptoKey } from "../../keys";
|
import { CryptoKey } from "../../keys";
|
||||||
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { DesCrypto } from "./crypto";
|
import { DesCrypto } from "./crypto";
|
||||||
import { DesCryptoKey } from "./key";
|
import { DesCryptoKey } from "./key";
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ export class DesCbcProvider extends core.DesProvider {
|
||||||
public ivSize = 8;
|
public ivSize = 8;
|
||||||
public name = "DES-CBC";
|
public name = "DES-CBC";
|
||||||
|
|
||||||
public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
|
||||||
const key = await DesCrypto.generateKey(
|
const key = await DesCrypto.generateKey(
|
||||||
{
|
{
|
||||||
name: this.name,
|
name: this.name,
|
||||||
|
@ -20,32 +21,32 @@ export class DesCbcProvider extends core.DesProvider {
|
||||||
extractable,
|
extractable,
|
||||||
keyUsages);
|
keyUsages);
|
||||||
|
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onEncrypt(algorithm: DesCbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onEncrypt(algorithm: DesCbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return DesCrypto.encrypt(algorithm, key, new Uint8Array(data));
|
return DesCrypto.encrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onDecrypt(algorithm: DesCbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onDecrypt(algorithm: DesCbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return DesCrypto.decrypt(algorithm, key, new Uint8Array(data));
|
return DesCrypto.decrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||||
return DesCrypto.exportKey(format, key);
|
return DesCrypto.exportKey(format, getCryptoKey(key) as DesCryptoKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
|
||||||
const key = await DesCrypto.importKey(format, keyData, { name: this.name, length: this.keySizeBits }, extractable, keyUsages);
|
const key = await DesCrypto.importKey(format, keyData, { name: this.name, length: this.keySizeBits }, extractable, keyUsages);
|
||||||
if (key.data.length !== (this.keySizeBits >> 3)) {
|
if (key.data.length !== (this.keySizeBits >> 3)) {
|
||||||
throw new core.OperationError("keyData: Wrong key size");
|
throw new core.OperationError("keyData: Wrong key size");
|
||||||
}
|
}
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof DesCryptoKey)) {
|
if (!(getCryptoKey(key) instanceof DesCryptoKey)) {
|
||||||
throw new TypeError("key: Is not a DesCryptoKey");
|
throw new TypeError("key: Is not a DesCryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
import { CryptoKey } from "../../keys";
|
import { CryptoKey } from "../../keys";
|
||||||
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { DesCrypto } from "./crypto";
|
import { DesCrypto } from "./crypto";
|
||||||
import { DesCryptoKey } from "./key";
|
import { DesCryptoKey } from "./key";
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ export class DesEde3CbcProvider extends core.DesProvider {
|
||||||
public ivSize = 8;
|
public ivSize = 8;
|
||||||
public name = "DES-EDE3-CBC";
|
public name = "DES-EDE3-CBC";
|
||||||
|
|
||||||
public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
|
||||||
const key = await DesCrypto.generateKey(
|
const key = await DesCrypto.generateKey(
|
||||||
{
|
{
|
||||||
name: this.name,
|
name: this.name,
|
||||||
|
@ -20,32 +21,32 @@ export class DesEde3CbcProvider extends core.DesProvider {
|
||||||
extractable,
|
extractable,
|
||||||
keyUsages);
|
keyUsages);
|
||||||
|
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onEncrypt(algorithm: DesEde3CbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onEncrypt(algorithm: DesEde3CbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return DesCrypto.encrypt(algorithm, key, new Uint8Array(data));
|
return DesCrypto.encrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onDecrypt(algorithm: DesEde3CbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onDecrypt(algorithm: DesEde3CbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return DesCrypto.decrypt(algorithm, key, new Uint8Array(data));
|
return DesCrypto.decrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||||
return DesCrypto.exportKey(format, key);
|
return DesCrypto.exportKey(format, getCryptoKey(key) as DesCryptoKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
|
||||||
const key = await DesCrypto.importKey(format, keyData, { name: this.name, length: this.keySizeBits }, extractable, keyUsages);
|
const key = await DesCrypto.importKey(format, keyData, { name: this.name, length: this.keySizeBits }, extractable, keyUsages);
|
||||||
if (key.data.length !== (this.keySizeBits >> 3)) {
|
if (key.data.length !== (this.keySizeBits >> 3)) {
|
||||||
throw new core.OperationError("keyData: Wrong key size");
|
throw new core.OperationError("keyData: Wrong key size");
|
||||||
}
|
}
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof DesCryptoKey)) {
|
if (!(getCryptoKey(key) instanceof DesCryptoKey)) {
|
||||||
throw new TypeError("key: Is not a DesCryptoKey");
|
throw new TypeError("key: Is not a DesCryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
import crypto from "crypto";
|
||||||
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
|
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
|
||||||
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||||
import crypto from "crypto";
|
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
import * as asn from "../../asn";
|
import * as asn from "../../asn";
|
||||||
import { ObjectIdentifier } from "../../asn";
|
import { ObjectIdentifier } from "../../asn";
|
||||||
|
@ -116,9 +116,10 @@ export class EcCrypto {
|
||||||
case "pkcs8":
|
case "pkcs8":
|
||||||
case "spki":
|
case "spki":
|
||||||
return new Uint8Array(key.data).buffer;
|
return new Uint8Array(key.data).buffer;
|
||||||
case "raw":
|
case "raw": {
|
||||||
const publicKeyInfo = AsnParser.parse(key.data, asn.PublicKeyInfo);
|
const publicKeyInfo = AsnParser.parse(key.data, asn.PublicKeyInfo);
|
||||||
return publicKeyInfo.publicKey;
|
return publicKeyInfo.publicKey;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw new core.OperationError("format: Must be 'jwk', 'raw', pkcs8' or 'spki'");
|
throw new core.OperationError("format: Must be 'jwk', 'raw', pkcs8' or 'spki'");
|
||||||
}
|
}
|
||||||
|
@ -126,7 +127,7 @@ export class EcCrypto {
|
||||||
|
|
||||||
public static async importKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public static async importKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||||
switch (format.toLowerCase()) {
|
switch (format.toLowerCase()) {
|
||||||
case "jwk":
|
case "jwk": {
|
||||||
const jwk = keyData as JsonWebKey;
|
const jwk = keyData as JsonWebKey;
|
||||||
if (jwk.d) {
|
if (jwk.d) {
|
||||||
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: asn.EcPrivateKey });
|
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: asn.EcPrivateKey });
|
||||||
|
@ -135,6 +136,7 @@ export class EcCrypto {
|
||||||
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: asn.EcPublicKey });
|
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: asn.EcPublicKey });
|
||||||
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
|
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
case "raw": {
|
case "raw": {
|
||||||
const asnKey = new asn.EcPublicKey(keyData as ArrayBuffer);
|
const asnKey = new asn.EcPublicKey(keyData as ArrayBuffer);
|
||||||
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
|
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
import { CryptoKey } from "../../keys";
|
import { CryptoKey } from "../../keys";
|
||||||
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { EcCrypto } from "./crypto";
|
import { EcCrypto } from "./crypto";
|
||||||
import { EcPrivateKey } from "./private_key";
|
import { EcPrivateKey } from "./private_key";
|
||||||
import { EcPublicKey } from "./public_key";
|
import { EcPublicKey } from "./public_key";
|
||||||
|
@ -7,7 +8,7 @@ import { EcPublicKey } from "./public_key";
|
||||||
export class EcdhProvider extends core.EcdhProvider {
|
export class EcdhProvider extends core.EcdhProvider {
|
||||||
|
|
||||||
public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||||
const key = await EcCrypto.generateKey(
|
const keys = await EcCrypto.generateKey(
|
||||||
{
|
{
|
||||||
...algorithm,
|
...algorithm,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
|
@ -15,27 +16,31 @@ export class EcdhProvider extends core.EcdhProvider {
|
||||||
extractable,
|
extractable,
|
||||||
keyUsages);
|
keyUsages);
|
||||||
|
|
||||||
return key;
|
return {
|
||||||
|
privateKey: setCryptoKey(keys.privateKey as CryptoKey),
|
||||||
|
publicKey: setCryptoKey(keys.publicKey as CryptoKey),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||||
return EcCrypto.exportKey(format, key);
|
return EcCrypto.exportKey(format, getCryptoKey(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
|
||||||
const key = await EcCrypto.importKey(format, keyData, {...algorithm, name: this.name}, extractable, keyUsages);
|
const key = await EcCrypto.importKey(format, keyData, {...algorithm, name: this.name}, extractable, keyUsages);
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof EcPrivateKey || key instanceof EcPublicKey)) {
|
const internalKey = getCryptoKey(key);
|
||||||
|
if (!(internalKey instanceof EcPrivateKey || internalKey instanceof EcPublicKey)) {
|
||||||
throw new TypeError("key: Is not EC CryptoKey");
|
throw new TypeError("key: Is not EC CryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onDeriveBits(algorithm: EcdhKeyDeriveParams, baseKey: CryptoKey, length: number): Promise<ArrayBuffer> {
|
public async onDeriveBits(algorithm: EcdhKeyDeriveParams, baseKey: CryptoKey, length: number): Promise<ArrayBuffer> {
|
||||||
const bits = await EcCrypto.deriveBits(algorithm, baseKey, length);
|
const bits = await EcCrypto.deriveBits({...algorithm, public: getCryptoKey(algorithm.public)}, getCryptoKey(baseKey), length);
|
||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
import { CryptoKey } from "../../keys";
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { EcCrypto } from "./crypto";
|
import { EcCrypto } from "./crypto";
|
||||||
import { EcPrivateKey } from "./private_key";
|
import { EcPrivateKey } from "./private_key";
|
||||||
import { EcPublicKey } from "./public_key";
|
import { EcPublicKey } from "./public_key";
|
||||||
|
@ -9,7 +9,7 @@ export class EcdsaProvider extends core.EcdsaProvider {
|
||||||
public namedCurves = ["P-256", "P-384", "P-521", "K-256"];
|
public namedCurves = ["P-256", "P-384", "P-521", "K-256"];
|
||||||
|
|
||||||
public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||||
const key = await EcCrypto.generateKey(
|
const keys = await EcCrypto.generateKey(
|
||||||
{
|
{
|
||||||
...algorithm,
|
...algorithm,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
|
@ -17,29 +17,33 @@ export class EcdsaProvider extends core.EcdsaProvider {
|
||||||
extractable,
|
extractable,
|
||||||
keyUsages);
|
keyUsages);
|
||||||
|
|
||||||
return key;
|
return {
|
||||||
|
privateKey: setCryptoKey(keys.privateKey as EcPrivateKey),
|
||||||
|
publicKey: setCryptoKey(keys.publicKey as EcPublicKey),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onSign(algorithm: EcdsaParams, key: EcPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onSign(algorithm: EcdsaParams, key: EcPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return EcCrypto.sign(algorithm, key, new Uint8Array(data));
|
return EcCrypto.sign(algorithm, getCryptoKey(key) as EcPrivateKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onVerify(algorithm: EcdsaParams, key: EcPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
|
public async onVerify(algorithm: EcdsaParams, key: EcPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
|
||||||
return EcCrypto.verify(algorithm, key, new Uint8Array(signature), new Uint8Array(data));
|
return EcCrypto.verify(algorithm, getCryptoKey(key) as EcPublicKey, new Uint8Array(signature), new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||||
return EcCrypto.exportKey(format, key);
|
return EcCrypto.exportKey(format, getCryptoKey(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||||
const key = await EcCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages);
|
const key = await EcCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages);
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof EcPrivateKey || key instanceof EcPublicKey)) {
|
const internalKey = getCryptoKey(key);
|
||||||
|
if (!(internalKey instanceof EcPrivateKey || internalKey instanceof EcPublicKey)) {
|
||||||
throw new TypeError("key: Is not EC CryptoKey");
|
throw new TypeError("key: Is not EC CryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,14 +29,14 @@ export class EcPrivateKey extends AsymmetricKey implements IJsonConvertible {
|
||||||
}
|
}
|
||||||
|
|
||||||
public fromJSON(json: JsonWebKey) {
|
public fromJSON(json: JsonWebKey) {
|
||||||
if (!json.alg) {
|
if (!json.crv) {
|
||||||
throw new core.OperationError(`Cannot get named curve from JWK. Property 'alg' is required`);
|
throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyInfo = new asn.PrivateKeyInfo();
|
const keyInfo = new asn.PrivateKeyInfo();
|
||||||
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
|
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
|
||||||
keyInfo.privateKeyAlgorithm.parameters = AsnSerializer.serialize(
|
keyInfo.privateKeyAlgorithm.parameters = AsnSerializer.serialize(
|
||||||
new ObjectIdentifier(getOidByNamedCurve(json.crv!)),
|
new ObjectIdentifier(getOidByNamedCurve(json.crv)),
|
||||||
);
|
);
|
||||||
const key = JsonParser.fromJSON(json, { targetSchema: asn.EcPrivateKey });
|
const key = JsonParser.fromJSON(json, { targetSchema: asn.EcPrivateKey });
|
||||||
keyInfo.privateKey = AsnSerializer.serialize(key);
|
keyInfo.privateKey = AsnSerializer.serialize(key);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
|
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
|
||||||
import { IJsonConvertible, JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
import { IJsonConvertible, JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||||
|
import * as core from "webcrypto-core";
|
||||||
import * as asn from "../../asn";
|
import * as asn from "../../asn";
|
||||||
import { ObjectIdentifier } from "../../asn";
|
import { ObjectIdentifier } from "../../asn";
|
||||||
import { AsymmetricKey } from "../../keys/asymmetric";
|
import { AsymmetricKey } from "../../keys/asymmetric";
|
||||||
|
@ -29,12 +30,16 @@ export class EcPublicKey extends AsymmetricKey implements IJsonConvertible {
|
||||||
}
|
}
|
||||||
|
|
||||||
public fromJSON(json: JsonWebKey) {
|
public fromJSON(json: JsonWebKey) {
|
||||||
|
if (!json.crv) {
|
||||||
|
throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`);
|
||||||
|
}
|
||||||
|
|
||||||
const key = JsonParser.fromJSON(json, { targetSchema: asn.EcPublicKey });
|
const key = JsonParser.fromJSON(json, { targetSchema: asn.EcPublicKey });
|
||||||
|
|
||||||
const keyInfo = new asn.PublicKeyInfo();
|
const keyInfo = new asn.PublicKeyInfo();
|
||||||
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
|
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
|
||||||
keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize(
|
keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize(
|
||||||
new ObjectIdentifier(getOidByNamedCurve(json.crv!)),
|
new ObjectIdentifier(getOidByNamedCurve(json.crv)),
|
||||||
);
|
);
|
||||||
keyInfo.publicKey = AsnSerializer.toASN(key).valueHex;
|
keyInfo.publicKey = AsnSerializer.toASN(key).valueHex;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
import { BufferSourceConverter, CryptoKey } from "webcrypto-core";
|
import { BufferSourceConverter, CryptoKey } from "webcrypto-core";
|
||||||
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { HkdfCryptoKey } from "./key";
|
import { HkdfCryptoKey } from "./key";
|
||||||
|
|
||||||
export class HkdfProvider extends core.HkdfProvider {
|
export class HkdfProvider extends core.HkdfProvider {
|
||||||
|
@ -15,7 +16,7 @@ export class HkdfProvider extends core.HkdfProvider {
|
||||||
key.algorithm = { name: this.name };
|
key.algorithm = { name: this.name };
|
||||||
key.extractable = extractable;
|
key.extractable = extractable;
|
||||||
key.usages = keyUsages;
|
key.usages = keyUsages;
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onDeriveBits(params: HkdfParams, baseKey: HkdfCryptoKey, length: number): Promise<ArrayBuffer> {
|
public async onDeriveBits(params: HkdfParams, baseKey: HkdfCryptoKey, length: number): Promise<ArrayBuffer> {
|
||||||
|
@ -26,7 +27,7 @@ export class HkdfProvider extends core.HkdfProvider {
|
||||||
const info = BufferSourceConverter.toUint8Array(params.info);
|
const info = BufferSourceConverter.toUint8Array(params.info);
|
||||||
|
|
||||||
const PRK = crypto.createHmac(hash, BufferSourceConverter.toUint8Array(params.salt))
|
const PRK = crypto.createHmac(hash, BufferSourceConverter.toUint8Array(params.salt))
|
||||||
.update(BufferSourceConverter.toUint8Array(baseKey.data))
|
.update(BufferSourceConverter.toUint8Array(getCryptoKey(baseKey).data))
|
||||||
.digest();
|
.digest();
|
||||||
|
|
||||||
const blocks = [Buffer.alloc(0)];
|
const blocks = [Buffer.alloc(0)];
|
||||||
|
@ -44,7 +45,7 @@ export class HkdfProvider extends core.HkdfProvider {
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof HkdfCryptoKey)) {
|
if (!(getCryptoKey(key) instanceof HkdfCryptoKey)) {
|
||||||
throw new TypeError("key: Is not HKDF CryptoKey");
|
throw new TypeError("key: Is not HKDF CryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
|
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { HmacCryptoKey } from "./key";
|
import { HmacCryptoKey } from "./key";
|
||||||
|
|
||||||
export class HmacProvider extends core.HmacProvider {
|
export class HmacProvider extends core.HmacProvider {
|
||||||
|
@ -16,12 +17,12 @@ export class HmacProvider extends core.HmacProvider {
|
||||||
key.usages = keyUsages;
|
key.usages = keyUsages;
|
||||||
key.data = crypto.randomBytes(length >> 3);
|
key.data = crypto.randomBytes(length >> 3);
|
||||||
|
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onSign(algorithm: Algorithm, key: HmacCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onSign(algorithm: Algorithm, key: HmacCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
const hash = key.algorithm.hash.name.replace("-", "");
|
const hash = key.algorithm.hash.name.replace("-", "");
|
||||||
const hmac = crypto.createHmac(hash, key.data)
|
const hmac = crypto.createHmac(hash, getCryptoKey(key).data)
|
||||||
.update(Buffer.from(data)).digest();
|
.update(Buffer.from(data)).digest();
|
||||||
|
|
||||||
return new Uint8Array(hmac).buffer;
|
return new Uint8Array(hmac).buffer;
|
||||||
|
@ -29,7 +30,7 @@ export class HmacProvider extends core.HmacProvider {
|
||||||
|
|
||||||
public async onVerify(algorithm: Algorithm, key: HmacCryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
|
public async onVerify(algorithm: Algorithm, key: HmacCryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
|
||||||
const hash = key.algorithm.hash.name.replace("-", "");
|
const hash = key.algorithm.hash.name.replace("-", "");
|
||||||
const hmac = crypto.createHmac(hash, key.data)
|
const hmac = crypto.createHmac(hash, getCryptoKey(key).data)
|
||||||
.update(Buffer.from(data)).digest();
|
.update(Buffer.from(data)).digest();
|
||||||
|
|
||||||
return hmac.compare(Buffer.from(signature)) === 0;
|
return hmac.compare(Buffer.from(signature)) === 0;
|
||||||
|
@ -58,15 +59,15 @@ export class HmacProvider extends core.HmacProvider {
|
||||||
key.extractable = extractable;
|
key.extractable = extractable;
|
||||||
key.usages = keyUsages;
|
key.usages = keyUsages;
|
||||||
|
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onExportKey(format: KeyFormat, key: HmacCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
public async onExportKey(format: KeyFormat, key: HmacCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||||
switch (format.toLowerCase()) {
|
switch (format.toLowerCase()) {
|
||||||
case "jwk":
|
case "jwk":
|
||||||
return JsonSerializer.toJSON(key);
|
return JsonSerializer.toJSON(getCryptoKey(key));
|
||||||
case "raw":
|
case "raw":
|
||||||
return new Uint8Array(key.data).buffer;
|
return new Uint8Array(getCryptoKey(key).data).buffer;
|
||||||
default:
|
default:
|
||||||
throw new core.OperationError("format: Must be 'jwk' or 'raw'");
|
throw new core.OperationError("format: Must be 'jwk' or 'raw'");
|
||||||
}
|
}
|
||||||
|
@ -74,7 +75,7 @@ export class HmacProvider extends core.HmacProvider {
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof HmacCryptoKey)) {
|
if (!(getCryptoKey(key) instanceof HmacCryptoKey)) {
|
||||||
throw new TypeError("key: Is not HMAC CryptoKey");
|
throw new TypeError("key: Is not HMAC CryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { JsonProp } from "@peculiar/json-schema";
|
import { JsonProp } from "@peculiar/json-schema";
|
||||||
import * as core from "webcrypto-core";
|
|
||||||
import { JsonBase64UrlConverter } from "../../converters";
|
import { JsonBase64UrlConverter } from "../../converters";
|
||||||
import { CryptoKey } from "../../keys";
|
import { CryptoKey } from "../../keys";
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import * as core from "webcrypto-core";
|
|
||||||
import { CryptoKey } from "../../keys";
|
import { CryptoKey } from "../../keys";
|
||||||
|
|
||||||
export class PbkdfCryptoKey extends CryptoKey {
|
export class PbkdfCryptoKey extends CryptoKey {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { PbkdfCryptoKey } from "./key";
|
import { PbkdfCryptoKey } from "./key";
|
||||||
|
|
||||||
export class Pbkdf2Provider extends core.Pbkdf2Provider {
|
export class Pbkdf2Provider extends core.Pbkdf2Provider {
|
||||||
|
@ -8,7 +9,7 @@ export class Pbkdf2Provider extends core.Pbkdf2Provider {
|
||||||
return new Promise<ArrayBuffer>((resolve, reject) => {
|
return new Promise<ArrayBuffer>((resolve, reject) => {
|
||||||
const salt = core.BufferSourceConverter.toArrayBuffer(algorithm.salt);
|
const salt = core.BufferSourceConverter.toArrayBuffer(algorithm.salt);
|
||||||
const hash = (algorithm.hash as Algorithm).name.replace("-", "");
|
const hash = (algorithm.hash as Algorithm).name.replace("-", "");
|
||||||
crypto.pbkdf2(baseKey.data, Buffer.from(salt), algorithm.iterations, length >> 3, hash, (err, derivedBits) => {
|
crypto.pbkdf2(getCryptoKey(baseKey).data, Buffer.from(salt), algorithm.iterations, length >> 3, hash, (err, derivedBits) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
} else {
|
} else {
|
||||||
|
@ -25,14 +26,14 @@ export class Pbkdf2Provider extends core.Pbkdf2Provider {
|
||||||
key.algorithm = { name: this.name };
|
key.algorithm = { name: this.name };
|
||||||
key.extractable = false;
|
key.extractable = false;
|
||||||
key.usages = keyUsages;
|
key.usages = keyUsages;
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
throw new core.OperationError("format: Must be 'raw'");
|
throw new core.OperationError("format: Must be 'raw'");
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof PbkdfCryptoKey)) {
|
if (!(getCryptoKey(key) instanceof PbkdfCryptoKey)) {
|
||||||
throw new TypeError("key: Is not PBKDF CryptoKey");
|
throw new TypeError("key: Is not PBKDF CryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
import crypto from "crypto";
|
||||||
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
|
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
|
||||||
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||||
import crypto from "crypto";
|
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
import * as asn from "../../asn";
|
import * as asn from "../../asn";
|
||||||
import { CryptoKey } from "../../keys";
|
import { CryptoKey } from "../../keys";
|
||||||
|
@ -74,7 +74,7 @@ export class RsaCrypto {
|
||||||
|
|
||||||
public static async importKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public static async importKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||||
switch (format.toLowerCase()) {
|
switch (format.toLowerCase()) {
|
||||||
case "jwk":
|
case "jwk": {
|
||||||
const jwk = keyData as JsonWebKey;
|
const jwk = keyData as JsonWebKey;
|
||||||
if (jwk.d) {
|
if (jwk.d) {
|
||||||
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: asn.RsaPrivateKey });
|
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: asn.RsaPrivateKey });
|
||||||
|
@ -83,6 +83,7 @@ export class RsaCrypto {
|
||||||
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: asn.RsaPublicKey });
|
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: asn.RsaPublicKey });
|
||||||
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
|
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
case "spki": {
|
case "spki": {
|
||||||
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), asn.PublicKeyInfo);
|
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), asn.PublicKeyInfo);
|
||||||
const asnKey = AsnParser.parse(keyInfo.publicKey, asn.RsaPublicKey);
|
const asnKey = AsnParser.parse(keyInfo.publicKey, asn.RsaPublicKey);
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
|
|
||||||
export function getJwkAlgorithm(algorithm: RsaHashedKeyAlgorithm) {
|
export function getJwkAlgorithm(algorithm: RsaHashedKeyAlgorithm) {
|
||||||
switch (algorithm.name.toUpperCase()) {
|
switch (algorithm.name.toUpperCase()) {
|
||||||
case "RSA-OAEP":
|
case "RSA-OAEP": {
|
||||||
const mdSize = /(\d+)$/.exec(algorithm.hash.name)![1];
|
const mdSize = /(\d+)$/.exec(algorithm.hash.name)![1];
|
||||||
return `RSA-OAEP${mdSize !== "1" ? `-${mdSize}` : ""}`;
|
return `RSA-OAEP${mdSize !== "1" ? `-${mdSize}` : ""}`;
|
||||||
|
}
|
||||||
case "RSASSA-PKCS1-V1_5":
|
case "RSASSA-PKCS1-V1_5":
|
||||||
return `RS${/(\d+)$/.exec(algorithm.hash.name)![1]}`;
|
return `RS${/(\d+)$/.exec(algorithm.hash.name)![1]}`;
|
||||||
case "RSA-PSS":
|
case "RSA-PSS":
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as crypto from "crypto";
|
import * as crypto from "crypto";
|
||||||
import { Convert } from "pvtsutils";
|
import { Convert } from "pvtsutils";
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
import { CryptoKey } from "../../keys";
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { RsaCrypto } from "./crypto";
|
import { RsaCrypto } from "./crypto";
|
||||||
import { RsaPrivateKey } from "./private_key";
|
import { RsaPrivateKey } from "./private_key";
|
||||||
import { RsaPublicKey } from "./public_key";
|
import { RsaPublicKey } from "./public_key";
|
||||||
|
@ -15,7 +15,7 @@ export class RsaEsProvider extends core.ProviderCrypto {
|
||||||
};
|
};
|
||||||
|
|
||||||
public async onGenerateKey(algorithm: RsaKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
public async onGenerateKey(algorithm: RsaKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||||
const key = await RsaCrypto.generateKey(
|
const keys = await RsaCrypto.generateKey(
|
||||||
{
|
{
|
||||||
...algorithm,
|
...algorithm,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
|
@ -23,7 +23,10 @@ export class RsaEsProvider extends core.ProviderCrypto {
|
||||||
extractable,
|
extractable,
|
||||||
keyUsages);
|
keyUsages);
|
||||||
|
|
||||||
return key;
|
return {
|
||||||
|
privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey),
|
||||||
|
publicKey: setCryptoKey(keys.publicKey as RsaPublicKey),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkGenerateKeyParams(algorithm: RsaKeyGenParams) {
|
public checkGenerateKeyParams(algorithm: RsaKeyGenParams) {
|
||||||
|
@ -62,17 +65,18 @@ export class RsaEsProvider extends core.ProviderCrypto {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||||
return RsaCrypto.exportKey(format, key);
|
return RsaCrypto.exportKey(format, getCryptoKey(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||||
const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages);
|
const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages);
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof RsaPrivateKey || key instanceof RsaPublicKey)) {
|
const internalKey = getCryptoKey(key);
|
||||||
|
if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) {
|
||||||
throw new TypeError("key: Is not RSA CryptoKey");
|
throw new TypeError("key: Is not RSA CryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,7 +86,7 @@ export class RsaEsProvider extends core.ProviderCrypto {
|
||||||
private toCryptoOptions(key: RsaPrivateKey | RsaPublicKey) {
|
private toCryptoOptions(key: RsaPrivateKey | RsaPublicKey) {
|
||||||
const type = key.type.toUpperCase();
|
const type = key.type.toUpperCase();
|
||||||
return {
|
return {
|
||||||
key: `-----BEGIN ${type} KEY-----\n${key.data.toString("base64")}\n-----END ${type} KEY-----`,
|
key: `-----BEGIN ${type} KEY-----\n${getCryptoKey(key).data.toString("base64")}\n-----END ${type} KEY-----`,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
padding: crypto.constants.RSA_PKCS1_PADDING,
|
padding: crypto.constants.RSA_PKCS1_PADDING,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
import { CryptoKey } from "../../keys";
|
|
||||||
import { ShaCrypto } from "../sha/crypto";
|
import { ShaCrypto } from "../sha/crypto";
|
||||||
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { RsaCrypto } from "./crypto";
|
import { RsaCrypto } from "./crypto";
|
||||||
import { RsaPrivateKey } from "./private_key";
|
import { RsaPrivateKey } from "./private_key";
|
||||||
import { RsaPublicKey } from "./public_key";
|
import { RsaPublicKey } from "./public_key";
|
||||||
|
@ -16,7 +16,7 @@ import { RsaPublicKey } from "./public_key";
|
||||||
export class RsaOaepProvider extends core.RsaOaepProvider {
|
export class RsaOaepProvider extends core.RsaOaepProvider {
|
||||||
|
|
||||||
public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||||
const key = await RsaCrypto.generateKey(
|
const keys = await RsaCrypto.generateKey(
|
||||||
{
|
{
|
||||||
...algorithm,
|
...algorithm,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
|
@ -24,13 +24,17 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
|
||||||
extractable,
|
extractable,
|
||||||
keyUsages);
|
keyUsages);
|
||||||
|
|
||||||
return key;
|
return {
|
||||||
|
privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey),
|
||||||
|
publicKey: setCryptoKey(keys.publicKey as RsaPublicKey),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onEncrypt(algorithm: RsaOaepParams, key: RsaPublicKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onEncrypt(algorithm: RsaOaepParams, key: RsaPublicKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
|
const internalKey = getCryptoKey(key) as RsaPublicKey;
|
||||||
const dataView = new Uint8Array(data);
|
const dataView = new Uint8Array(data);
|
||||||
const keySize = Math.ceil(key.algorithm.modulusLength >> 3);
|
const keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3);
|
||||||
const hashSize = ShaCrypto.size(key.algorithm.hash) >> 3;
|
const hashSize = ShaCrypto.size(internalKey.algorithm.hash) >> 3;
|
||||||
const dataLength = dataView.byteLength;
|
const dataLength = dataView.byteLength;
|
||||||
const psLength = keySize - dataLength - 2 * hashSize - 2;
|
const psLength = keySize - dataLength - 2 * hashSize - 2;
|
||||||
|
|
||||||
|
@ -44,7 +48,7 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
|
||||||
|
|
||||||
dataBlock.set(dataView, hashSize + psLength + 1);
|
dataBlock.set(dataView, hashSize + psLength + 1);
|
||||||
|
|
||||||
const labelHash = crypto.createHash(key.algorithm.hash.name.replace("-", ""))
|
const labelHash = crypto.createHash(internalKey.algorithm.hash.name.replace("-", ""))
|
||||||
.update(core.BufferSourceConverter.toUint8Array(algorithm.label || new Uint8Array(0)))
|
.update(core.BufferSourceConverter.toUint8Array(algorithm.label || new Uint8Array(0)))
|
||||||
.digest();
|
.digest();
|
||||||
dataBlock.set(labelHash, 0);
|
dataBlock.set(labelHash, 0);
|
||||||
|
@ -52,22 +56,22 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
|
||||||
|
|
||||||
crypto.randomFillSync(seed);
|
crypto.randomFillSync(seed);
|
||||||
|
|
||||||
const dataBlockMask = this.mgf1(key.algorithm.hash, seed, dataBlock.length);
|
const dataBlockMask = this.mgf1(internalKey.algorithm.hash, seed, dataBlock.length);
|
||||||
for (let i = 0; i < dataBlock.length; i++) {
|
for (let i = 0; i < dataBlock.length; i++) {
|
||||||
dataBlock[i] ^= dataBlockMask[i];
|
dataBlock[i] ^= dataBlockMask[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
const seedMask = this.mgf1(key.algorithm.hash, dataBlock, seed.length);
|
const seedMask = this.mgf1(internalKey.algorithm.hash, dataBlock, seed.length);
|
||||||
for (let i = 0; i < seed.length; i++) {
|
for (let i = 0; i < seed.length; i++) {
|
||||||
seed[i] ^= seedMask[i];
|
seed[i] ^= seedMask[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!key.pem) {
|
if (!internalKey.pem) {
|
||||||
key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`;
|
internalKey.pem = `-----BEGIN PUBLIC KEY-----\n${internalKey.data.toString("base64")}\n-----END PUBLIC KEY-----`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pkcs0 = crypto.publicEncrypt({
|
const pkcs0 = crypto.publicEncrypt({
|
||||||
key: key.pem,
|
key: internalKey.pem,
|
||||||
padding: crypto.constants.RSA_NO_PADDING,
|
padding: crypto.constants.RSA_NO_PADDING,
|
||||||
}, Buffer.from(message));
|
}, Buffer.from(message));
|
||||||
|
|
||||||
|
@ -75,20 +79,21 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onDecrypt(algorithm: RsaOaepParams, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onDecrypt(algorithm: RsaOaepParams, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
const keySize = Math.ceil(key.algorithm.modulusLength >> 3);
|
const internalKey = getCryptoKey(key) as RsaPrivateKey;
|
||||||
const hashSize = ShaCrypto.size(key.algorithm.hash) >> 3;
|
const keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3);
|
||||||
|
const hashSize = ShaCrypto.size(internalKey.algorithm.hash) >> 3;
|
||||||
const dataLength = data.byteLength;
|
const dataLength = data.byteLength;
|
||||||
|
|
||||||
if (dataLength !== keySize) {
|
if (dataLength !== keySize) {
|
||||||
throw new Error("Bad data");
|
throw new Error("Bad data");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!key.pem) {
|
if (!internalKey.pem) {
|
||||||
key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`;
|
internalKey.pem = `-----BEGIN PRIVATE KEY-----\n${internalKey.data.toString("base64")}\n-----END PRIVATE KEY-----`;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pkcs0 = crypto.privateDecrypt({
|
let pkcs0 = crypto.privateDecrypt({
|
||||||
key: key.pem,
|
key: internalKey.pem,
|
||||||
padding: crypto.constants.RSA_NO_PADDING,
|
padding: crypto.constants.RSA_NO_PADDING,
|
||||||
}, Buffer.from(data));
|
}, Buffer.from(data));
|
||||||
const z = pkcs0[0];
|
const z = pkcs0[0];
|
||||||
|
@ -99,17 +104,17 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
|
||||||
throw new Error("Decryption failed");
|
throw new Error("Decryption failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
const seedMask = this.mgf1(key.algorithm.hash, dataBlock, seed.length);
|
const seedMask = this.mgf1(internalKey.algorithm.hash, dataBlock, seed.length);
|
||||||
for (let i = 0; i < seed.length; i++) {
|
for (let i = 0; i < seed.length; i++) {
|
||||||
seed[i] ^= seedMask[i];
|
seed[i] ^= seedMask[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
const dataBlockMask = this.mgf1(key.algorithm.hash, seed, dataBlock.length);
|
const dataBlockMask = this.mgf1(internalKey.algorithm.hash, seed, dataBlock.length);
|
||||||
for (let i = 0; i < dataBlock.length; i++) {
|
for (let i = 0; i < dataBlock.length; i++) {
|
||||||
dataBlock[i] ^= dataBlockMask[i];
|
dataBlock[i] ^= dataBlockMask[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
const labelHash = crypto.createHash(key.algorithm.hash.name.replace("-", ""))
|
const labelHash = crypto.createHash(internalKey.algorithm.hash.name.replace("-", ""))
|
||||||
.update(core.BufferSourceConverter.toUint8Array(algorithm.label || new Uint8Array(0)))
|
.update(core.BufferSourceConverter.toUint8Array(algorithm.label || new Uint8Array(0)))
|
||||||
.digest();
|
.digest();
|
||||||
for (let i = 0; i < hashSize; i++) {
|
for (let i = 0; i < hashSize; i++) {
|
||||||
|
@ -138,17 +143,18 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||||
return RsaCrypto.exportKey(format, key);
|
return RsaCrypto.exportKey(format, getCryptoKey(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||||
const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages);
|
const key = await RsaCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages);
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof RsaPrivateKey || key instanceof RsaPublicKey)) {
|
const internalKey = getCryptoKey(key);
|
||||||
|
if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) {
|
||||||
throw new TypeError("key: Is not RSA CryptoKey");
|
throw new TypeError("key: Is not RSA CryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +165,7 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
|
||||||
* @param seed
|
* @param seed
|
||||||
* @param length
|
* @param length
|
||||||
*/
|
*/
|
||||||
protected mgf1(algorithm: Algorithm, seed: Uint8Array, length: number = 0) {
|
protected mgf1(algorithm: Algorithm, seed: Uint8Array, length = 0) {
|
||||||
const hashSize = ShaCrypto.size(algorithm) >> 3;
|
const hashSize = ShaCrypto.size(algorithm) >> 3;
|
||||||
const mask = new Uint8Array(length);
|
const mask = new Uint8Array(length);
|
||||||
const counter = new Uint8Array(4);
|
const counter = new Uint8Array(4);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
import { CryptoKey } from "../../keys";
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { RsaCrypto } from "./crypto";
|
import { RsaCrypto } from "./crypto";
|
||||||
import { RsaPrivateKey } from "./private_key";
|
import { RsaPrivateKey } from "./private_key";
|
||||||
import { RsaPublicKey } from "./public_key";
|
import { RsaPublicKey } from "./public_key";
|
||||||
|
@ -7,7 +7,7 @@ import { RsaPublicKey } from "./public_key";
|
||||||
export class RsaPssProvider extends core.RsaPssProvider {
|
export class RsaPssProvider extends core.RsaPssProvider {
|
||||||
|
|
||||||
public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||||
const key = await RsaCrypto.generateKey(
|
const keys = await RsaCrypto.generateKey(
|
||||||
{
|
{
|
||||||
...algorithm,
|
...algorithm,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
|
@ -15,29 +15,33 @@ export class RsaPssProvider extends core.RsaPssProvider {
|
||||||
extractable,
|
extractable,
|
||||||
keyUsages);
|
keyUsages);
|
||||||
|
|
||||||
return key;
|
return {
|
||||||
|
privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey),
|
||||||
|
publicKey: setCryptoKey(keys.publicKey as RsaPublicKey),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onSign(algorithm: RsaPssParams, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onSign(algorithm: RsaPssParams, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return RsaCrypto.sign(algorithm, key, new Uint8Array(data));
|
return RsaCrypto.sign(algorithm, getCryptoKey(key) as RsaPrivateKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onVerify(algorithm: RsaPssParams, key: RsaPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
|
public async onVerify(algorithm: RsaPssParams, key: RsaPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
|
||||||
return RsaCrypto.verify(algorithm, key, new Uint8Array(signature), new Uint8Array(data));
|
return RsaCrypto.verify(algorithm, getCryptoKey(key) as RsaPublicKey, new Uint8Array(signature), new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||||
return RsaCrypto.exportKey(format, key);
|
return RsaCrypto.exportKey(format, getCryptoKey(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||||
const key = await RsaCrypto.importKey(format, keyData, {...algorithm, name: this.name}, extractable, keyUsages);
|
const key = await RsaCrypto.importKey(format, keyData, {...algorithm, name: this.name}, extractable, keyUsages);
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof RsaPrivateKey || key instanceof RsaPublicKey)) {
|
const internalKey = getCryptoKey(key);
|
||||||
|
if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) {
|
||||||
throw new TypeError("key: Is not RSA CryptoKey");
|
throw new TypeError("key: Is not RSA CryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
import { CryptoKey } from "../../keys";
|
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||||
import { RsaCrypto } from "./crypto";
|
import { RsaCrypto } from "./crypto";
|
||||||
import { RsaPrivateKey } from "./private_key";
|
import { RsaPrivateKey } from "./private_key";
|
||||||
import { RsaPublicKey } from "./public_key";
|
import { RsaPublicKey } from "./public_key";
|
||||||
|
@ -7,7 +7,7 @@ import { RsaPublicKey } from "./public_key";
|
||||||
export class RsaSsaProvider extends core.RsaSsaProvider {
|
export class RsaSsaProvider extends core.RsaSsaProvider {
|
||||||
|
|
||||||
public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||||
const key = await RsaCrypto.generateKey(
|
const keys = await RsaCrypto.generateKey(
|
||||||
{
|
{
|
||||||
...algorithm,
|
...algorithm,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
|
@ -15,29 +15,33 @@ export class RsaSsaProvider extends core.RsaSsaProvider {
|
||||||
extractable,
|
extractable,
|
||||||
keyUsages);
|
keyUsages);
|
||||||
|
|
||||||
return key;
|
return {
|
||||||
|
privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey),
|
||||||
|
publicKey: setCryptoKey(keys.publicKey as RsaPublicKey),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onSign(algorithm: Algorithm, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
public async onSign(algorithm: Algorithm, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
return RsaCrypto.sign(algorithm, key, new Uint8Array(data));
|
return RsaCrypto.sign(algorithm, getCryptoKey(key) as RsaPrivateKey, new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onVerify(algorithm: Algorithm, key: RsaPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
|
public async onVerify(algorithm: Algorithm, key: RsaPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
|
||||||
return RsaCrypto.verify(algorithm, key, new Uint8Array(signature), new Uint8Array(data));
|
return RsaCrypto.verify(algorithm, getCryptoKey(key) as RsaPublicKey, new Uint8Array(signature), new Uint8Array(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||||
return RsaCrypto.exportKey(format, key);
|
return RsaCrypto.exportKey(format, getCryptoKey(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||||
const key = await RsaCrypto.importKey(format, keyData, {...algorithm, name: this.name}, extractable, keyUsages);
|
const key = await RsaCrypto.importKey(format, keyData, {...algorithm, name: this.name}, extractable, keyUsages);
|
||||||
return key;
|
return setCryptoKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||||
super.checkCryptoKey(key, keyUsage);
|
super.checkCryptoKey(key, keyUsage);
|
||||||
if (!(key instanceof RsaPrivateKey || key instanceof RsaPublicKey)) {
|
const internalKey = getCryptoKey(key);
|
||||||
|
if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) {
|
||||||
throw new TypeError("key: Is not RSA CryptoKey");
|
throw new TypeError("key: Is not RSA CryptoKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import * as core from "webcrypto-core";
|
||||||
|
import { CryptoKey as InternalCryptoKey } from "../keys";
|
||||||
|
|
||||||
|
const keyStorage = new WeakMap<core.CryptoKey, InternalCryptoKey>();
|
||||||
|
|
||||||
|
export function getCryptoKey(key: core.CryptoKey) {
|
||||||
|
const res = keyStorage.get(key);
|
||||||
|
if (!res) {
|
||||||
|
throw new core.OperationError("Cannot get CryptoKey from secure storage");
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setCryptoKey(value: InternalCryptoKey) {
|
||||||
|
const key = core.CryptoKey.create(value.algorithm, value.type, value.extractable, value.usages);
|
||||||
|
Object.freeze(key);
|
||||||
|
|
||||||
|
keyStorage.set(key, value);
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
|
import assert from "assert";
|
||||||
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
|
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
|
||||||
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||||
import assert from "assert";
|
|
||||||
import * as asn from "../src/asn";
|
import * as asn from "../src/asn";
|
||||||
|
|
||||||
context("ASN", () => {
|
context("ASN", () => {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import assert from "assert";
|
|
||||||
import * as core from "webcrypto-core";
|
import * as core from "webcrypto-core";
|
||||||
import { Crypto } from "../src";
|
import { Crypto } from "../src";
|
||||||
import { DesCbcParams } from "../src/mechs";
|
import { DesCbcParams } from "../src/mechs";
|
||||||
|
|
|
@ -150,9 +150,10 @@ export function testCrypto(crypto: Crypto, params: ITestParams[]) {
|
||||||
params.forEach((param) => {
|
params.forEach((param) => {
|
||||||
context(param.name, () => {
|
context(param.name, () => {
|
||||||
//#region Generate key
|
//#region Generate key
|
||||||
if (param.actions.generateKey) {
|
const generateKey = param.actions.generateKey;
|
||||||
|
if (generateKey) {
|
||||||
context("Generate Key", () => {
|
context("Generate Key", () => {
|
||||||
param.actions.generateKey!.forEach((action, index) => {
|
generateKey.forEach((action, index) => {
|
||||||
wrapTest(async () => {
|
wrapTest(async () => {
|
||||||
const algorithm = Object.assign({}, action.algorithm);
|
const algorithm = Object.assign({}, action.algorithm);
|
||||||
algorithm.name = algorithm.name.toLowerCase();
|
algorithm.name = algorithm.name.toLowerCase();
|
||||||
|
@ -184,9 +185,10 @@ export function testCrypto(crypto: Crypto, params: ITestParams[]) {
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region encrypt
|
//#region encrypt
|
||||||
if (param.actions.encrypt) {
|
const encrypt = param.actions.encrypt;
|
||||||
|
if (encrypt) {
|
||||||
context("Encrypt/Decrypt", () => {
|
context("Encrypt/Decrypt", () => {
|
||||||
param.actions.encrypt!.forEach((action, index) => {
|
encrypt.forEach((action, index) => {
|
||||||
wrapTest(async () => {
|
wrapTest(async () => {
|
||||||
// import keys
|
// import keys
|
||||||
const keys = await getKeys(crypto, action.key);
|
const keys = await getKeys(crypto, action.key);
|
||||||
|
@ -212,9 +214,10 @@ export function testCrypto(crypto: Crypto, params: ITestParams[]) {
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Import/Export
|
//#region Import/Export
|
||||||
if (param.actions.import) {
|
const importFn = param.actions.import;
|
||||||
|
if (importFn) {
|
||||||
context("Import/Export", () => {
|
context("Import/Export", () => {
|
||||||
param.actions.import!.forEach((action, index) => {
|
importFn.forEach((action, index) => {
|
||||||
wrapTest(async () => {
|
wrapTest(async () => {
|
||||||
const importedKey = await crypto.subtle.importKey(
|
const importedKey = await crypto.subtle.importKey(
|
||||||
action.format,
|
action.format,
|
||||||
|
@ -223,7 +226,7 @@ export function testCrypto(crypto: Crypto, params: ITestParams[]) {
|
||||||
action.extractable,
|
action.extractable,
|
||||||
action.keyUsages);
|
action.keyUsages);
|
||||||
|
|
||||||
// Can't continue if key is not exctractable.
|
// Can't continue if key is not extractable.
|
||||||
if (!action.extractable) {
|
if (!action.extractable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -244,9 +247,10 @@ export function testCrypto(crypto: Crypto, params: ITestParams[]) {
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Sign/Verify
|
//#region Sign/Verify
|
||||||
if (param.actions.sign) {
|
const sign = param.actions.sign;
|
||||||
|
if (sign) {
|
||||||
context("Sign/Verify", () => {
|
context("Sign/Verify", () => {
|
||||||
param.actions.sign!.forEach((action, index) => {
|
sign.forEach((action, index) => {
|
||||||
wrapTest(async () => {
|
wrapTest(async () => {
|
||||||
// import keys
|
// import keys
|
||||||
const keys = await getKeys(crypto, action.key);
|
const keys = await getKeys(crypto, action.key);
|
||||||
|
@ -275,9 +279,10 @@ export function testCrypto(crypto: Crypto, params: ITestParams[]) {
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Derive bits
|
//#region Derive bits
|
||||||
if (param.actions.deriveBits) {
|
const deriveBits = param.actions.deriveBits;
|
||||||
|
if (deriveBits) {
|
||||||
context("Derive bits", () => {
|
context("Derive bits", () => {
|
||||||
param.actions.deriveBits!.forEach((action, index) => {
|
deriveBits.forEach((action, index) => {
|
||||||
wrapTest(async () => {
|
wrapTest(async () => {
|
||||||
// import keys
|
// import keys
|
||||||
const keys = await getKeys(crypto, action.key);
|
const keys = await getKeys(crypto, action.key);
|
||||||
|
@ -295,9 +300,10 @@ export function testCrypto(crypto: Crypto, params: ITestParams[]) {
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Derive key
|
//#region Derive key
|
||||||
if (param.actions.deriveKey) {
|
const deriveKey = param.actions.deriveKey;
|
||||||
|
if (deriveKey) {
|
||||||
context("Derive key", () => {
|
context("Derive key", () => {
|
||||||
param.actions.deriveKey!.forEach((action, index) => {
|
deriveKey.forEach((action, index) => {
|
||||||
wrapTest(async () => {
|
wrapTest(async () => {
|
||||||
// import keys
|
// import keys
|
||||||
const keys = await getKeys(crypto, action.key);
|
const keys = await getKeys(crypto, action.key);
|
||||||
|
@ -320,9 +326,10 @@ export function testCrypto(crypto: Crypto, params: ITestParams[]) {
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Digest
|
//#region Digest
|
||||||
if (param.actions.digest) {
|
const digest = param.actions.digest;
|
||||||
|
if (digest) {
|
||||||
context("Digest", () => {
|
context("Digest", () => {
|
||||||
param.actions.digest!.forEach((action, index) => {
|
digest.forEach((action, index) => {
|
||||||
wrapTest(async () => {
|
wrapTest(async () => {
|
||||||
const hash = await crypto.subtle.digest(action.algorithm, action.data);
|
const hash = await crypto.subtle.digest(action.algorithm, action.data);
|
||||||
assert.equal(Convert.ToHex(hash), Convert.ToHex(action.hash));
|
assert.equal(Convert.ToHex(hash), Convert.ToHex(action.hash));
|
||||||
|
@ -333,9 +340,10 @@ export function testCrypto(crypto: Crypto, params: ITestParams[]) {
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Wrap/Unwrap key
|
//#region Wrap/Unwrap key
|
||||||
if (param.actions.wrapKey) {
|
const wrapKey = param.actions.wrapKey;
|
||||||
|
if (wrapKey) {
|
||||||
context("Wrap/Unwrap key", () => {
|
context("Wrap/Unwrap key", () => {
|
||||||
param.actions.wrapKey!.forEach((action, index) => {
|
wrapKey.forEach((action, index) => {
|
||||||
wrapTest(async () => {
|
wrapTest(async () => {
|
||||||
const wKey = (await getKeys(crypto, action.wKey)).privateKey;
|
const wKey = (await getKeys(crypto, action.wKey)).privateKey;
|
||||||
const key = await getKeys(crypto, action.key);
|
const key = await getKeys(crypto, action.key);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { Convert } from "pvtsutils";
|
|
||||||
import { Crypto } from "../src";
|
import { Crypto } from "../src";
|
||||||
import { testCrypto } from "./helper";
|
import { testCrypto } from "./helper";
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
--require ts-node/register
|
|
||||||
test/**/*.ts
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Convert } from "pvtsutils";
|
import { Convert } from "pvtsutils";
|
||||||
import { Crypto } from "../src";
|
import { Crypto } from "../src";
|
||||||
import { ITestGenerateKeyAction, testCrypto } from "./helper";
|
import { testCrypto } from "./helper";
|
||||||
|
|
||||||
context("SHA", () => {
|
context("SHA", () => {
|
||||||
|
|
||||||
|
|
15
tslint.json
15
tslint.json
|
@ -1,15 +0,0 @@
|
||||||
{
|
|
||||||
"defaultSeverity": "error",
|
|
||||||
"extends": [
|
|
||||||
"tslint:recommended"
|
|
||||||
],
|
|
||||||
"jsRules": {},
|
|
||||||
"rules": {
|
|
||||||
"max-line-length": false,
|
|
||||||
"no-bitwise": false,
|
|
||||||
"object-literal-sort-keys": false,
|
|
||||||
"no-namespace": false,
|
|
||||||
"max-classes-per-file": false
|
|
||||||
},
|
|
||||||
"rulesDirectory": []
|
|
||||||
}
|
|
Reference in New Issue