Compare commits
No commits in common. "9e7cff20ff3a74c13d976d9cc1afcfc1e21c6020" and "49f7b850325720a3b6275c4639b6d85ca1fa96e9" have entirely different histories.
9e7cff20ff
...
49f7b85032
File diff suppressed because it is too large
Load Diff
2377
build/webcrypto.js
2377
build/webcrypto.js
File diff suppressed because it is too large
Load Diff
|
@ -61,7 +61,6 @@
|
|||
"eslint": "^8.36.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"mocha": "^10.2.0",
|
||||
"prettier": "^2.8.7",
|
||||
"rimraf": "^4.4.0",
|
||||
"rollup": "^3.20.0",
|
||||
"rollup-plugin-typescript2": "^0.34.1",
|
||||
|
@ -71,7 +70,6 @@
|
|||
"dependencies": {
|
||||
"@peculiar/asn1-schema": "^2.3.6",
|
||||
"@peculiar/json-schema": "^1.1.12",
|
||||
"buffer": "^6.0.3",
|
||||
"pvtsutils": "^1.3.2",
|
||||
"tslib": "^2.5.0",
|
||||
"webcrypto-core": "^1.7.7"
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Buffer } from "buffer";
|
||||
import { IJsonConverter } from "@peculiar/json-schema";
|
||||
import { Convert } from "pvtsutils";
|
||||
|
||||
|
|
|
@ -1,23 +1,18 @@
|
|||
import { Buffer } from "buffer";
|
||||
import crypto from "crypto";
|
||||
import * as core from "webcrypto-core";
|
||||
import { SubtleCrypto } from "./subtle";
|
||||
|
||||
export class Crypto extends core.Crypto {
|
||||
|
||||
public subtle = new SubtleCrypto();
|
||||
|
||||
public getRandomValues<T extends ArrayBufferView | null>(array: T): T {
|
||||
if (!ArrayBuffer.isView(array)) {
|
||||
throw new TypeError(
|
||||
"Failed to execute 'getRandomValues' on 'Crypto': parameter 1 is not of type 'ArrayBufferView'"
|
||||
);
|
||||
throw new TypeError("Failed to execute 'getRandomValues' on 'Crypto': parameter 1 is not of type 'ArrayBufferView'");
|
||||
}
|
||||
const buffer = Buffer.from(
|
||||
array.buffer,
|
||||
array.byteOffset,
|
||||
array.byteLength
|
||||
);
|
||||
const buffer = Buffer.from(array.buffer, array.byteOffset, array.byteLength);
|
||||
crypto.randomFillSync(buffer);
|
||||
return array;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { CryptoKey } from "./key";
|
||||
|
||||
export abstract class AsymmetricKey extends CryptoKey {
|
||||
|
||||
public abstract override type: "public" | "private";
|
||||
public pem?: string;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Buffer } from "buffer";
|
||||
import { JsonProp, JsonPropTypes } from "@peculiar/json-schema";
|
||||
import * as core from "webcrypto-core";
|
||||
|
||||
|
@ -12,12 +11,7 @@ export class CryptoKey extends core.CryptoKey {
|
|||
|
||||
public override type: KeyType = "secret";
|
||||
|
||||
@JsonProp({
|
||||
name: "key_ops",
|
||||
type: JsonPropTypes.String,
|
||||
repeated: true,
|
||||
optional: true,
|
||||
})
|
||||
@JsonProp({ name: "key_ops", type: JsonPropTypes.String, repeated: true, optional: true })
|
||||
public override usages: KeyUsage[] = [];
|
||||
|
||||
@JsonProp({ type: JsonPropTypes.String })
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { CryptoKey } from "./key";
|
||||
|
||||
export class SymmetricKey extends CryptoKey {
|
||||
|
||||
public override readonly kty = "oct";
|
||||
public override readonly type = "secret" as const;
|
||||
|
||||
}
|
||||
|
|
|
@ -4,68 +4,33 @@ import { AesCryptoKey } from "./key";
|
|||
import { getCryptoKey, setCryptoKey } from "../storage";
|
||||
|
||||
export class AesCbcProvider extends core.AesCbcProvider {
|
||||
public async onGenerateKey(
|
||||
algorithm: AesKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKey> {
|
||||
|
||||
public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
const key = await AesCrypto.generateKey(
|
||||
{
|
||||
name: this.name,
|
||||
length: algorithm.length,
|
||||
},
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
keyUsages);
|
||||
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
public async onEncrypt(
|
||||
algorithm: Algorithm,
|
||||
key: AesCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return AesCrypto.encrypt(
|
||||
algorithm,
|
||||
getCryptoKey(key) as AesCryptoKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||
}
|
||||
|
||||
public async onDecrypt(
|
||||
algorithm: Algorithm,
|
||||
key: AesCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return AesCrypto.decrypt(
|
||||
algorithm,
|
||||
getCryptoKey(key) as AesCryptoKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
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, getCryptoKey(key) as AesCryptoKey);
|
||||
}
|
||||
|
||||
public async onImportKey(
|
||||
format: KeyFormat,
|
||||
keyData: JsonWebKey | ArrayBuffer,
|
||||
algorithm: Algorithm,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKey> {
|
||||
const key = await AesCrypto.importKey(
|
||||
format,
|
||||
keyData,
|
||||
{ name: algorithm.name },
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
const key = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Buffer } from "buffer";
|
||||
import * as crypto from "crypto";
|
||||
import * as core from "webcrypto-core";
|
||||
import { AesCrypto } from "./crypto";
|
||||
|
@ -91,17 +90,14 @@ function aesCmac(key: Buffer, message: Buffer) {
|
|||
blockCount = 1;
|
||||
lastBlockCompleteFlag = false;
|
||||
} else {
|
||||
lastBlockCompleteFlag = message.length % blockSize === 0;
|
||||
lastBlockCompleteFlag = (message.length % blockSize === 0);
|
||||
}
|
||||
const lastBlockIndex = blockCount - 1;
|
||||
|
||||
if (lastBlockCompleteFlag) {
|
||||
lastBlock = xor(getMessageBlock(message, lastBlockIndex), subkeys.subkey1);
|
||||
} else {
|
||||
lastBlock = xor(
|
||||
getPaddedMessageBlock(message, lastBlockIndex),
|
||||
subkeys.subkey2
|
||||
);
|
||||
lastBlock = xor(getPaddedMessageBlock(message, lastBlockIndex), subkeys.subkey2);
|
||||
}
|
||||
|
||||
let x = zero;
|
||||
|
@ -116,63 +112,35 @@ function aesCmac(key: Buffer, message: Buffer) {
|
|||
}
|
||||
|
||||
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> {
|
||||
const key = await AesCrypto.generateKey(
|
||||
{
|
||||
name: this.name,
|
||||
length: algorithm.length,
|
||||
},
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
keyUsages);
|
||||
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
public async onSign(
|
||||
algorithm: core.AesCmacParams,
|
||||
key: AesCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
public async onSign(algorithm: core.AesCmacParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
const result = aesCmac(getCryptoKey(key).data, Buffer.from(data));
|
||||
return new Uint8Array(result).buffer;
|
||||
}
|
||||
|
||||
public async onVerify(
|
||||
algorithm: core.AesCmacParams,
|
||||
key: AesCryptoKey,
|
||||
signature: ArrayBuffer,
|
||||
data: ArrayBuffer
|
||||
): Promise<boolean> {
|
||||
public async onVerify(algorithm: core.AesCmacParams, key: AesCryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
|
||||
const signature2 = await this.sign(algorithm, key, data);
|
||||
return Buffer.from(signature).compare(Buffer.from(signature2)) === 0;
|
||||
}
|
||||
|
||||
public async onExportKey(
|
||||
format: KeyFormat,
|
||||
key: AesCryptoKey
|
||||
): Promise<JsonWebKey | ArrayBuffer> {
|
||||
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||
return AesCrypto.exportKey(format, getCryptoKey(key) as AesCryptoKey);
|
||||
}
|
||||
|
||||
public async onImportKey(
|
||||
format: KeyFormat,
|
||||
keyData: JsonWebKey | ArrayBuffer,
|
||||
algorithm: Algorithm,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKey> {
|
||||
const res = await AesCrypto.importKey(
|
||||
format,
|
||||
keyData,
|
||||
{ name: algorithm.name },
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
||||
return setCryptoKey(res);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,68 +4,33 @@ import { AesCryptoKey } from "./key";
|
|||
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||
|
||||
export class AesCtrProvider extends core.AesCtrProvider {
|
||||
public async onGenerateKey(
|
||||
algorithm: AesKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKey> {
|
||||
|
||||
public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
const key = await AesCrypto.generateKey(
|
||||
{
|
||||
name: this.name,
|
||||
length: algorithm.length,
|
||||
},
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
keyUsages);
|
||||
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
public async onEncrypt(
|
||||
algorithm: AesCtrParams,
|
||||
key: AesCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return AesCrypto.encrypt(
|
||||
algorithm,
|
||||
getCryptoKey(key) as AesCryptoKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onEncrypt(algorithm: AesCtrParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||
}
|
||||
|
||||
public async onDecrypt(
|
||||
algorithm: AesCtrParams,
|
||||
key: AesCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return AesCrypto.decrypt(
|
||||
algorithm,
|
||||
getCryptoKey(key) as AesCryptoKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onDecrypt(algorithm: AesCtrParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
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, getCryptoKey(key) as AesCryptoKey);
|
||||
}
|
||||
|
||||
public async onImportKey(
|
||||
format: KeyFormat,
|
||||
keyData: JsonWebKey | ArrayBuffer,
|
||||
algorithm: Algorithm,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKey> {
|
||||
const res = await AesCrypto.importKey(
|
||||
format,
|
||||
keyData,
|
||||
{ name: algorithm.name },
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
||||
return setCryptoKey(res);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,68 +4,33 @@ import { AesCryptoKey } from "./key";
|
|||
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||
|
||||
export class AesEcbProvider extends core.AesEcbProvider {
|
||||
public async onGenerateKey(
|
||||
algorithm: AesKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKey> {
|
||||
|
||||
public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
const key = await AesCrypto.generateKey(
|
||||
{
|
||||
name: this.name,
|
||||
length: algorithm.length,
|
||||
},
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
keyUsages);
|
||||
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
public async onEncrypt(
|
||||
algorithm: Algorithm,
|
||||
key: AesCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return AesCrypto.encrypt(
|
||||
algorithm,
|
||||
getCryptoKey(key) as AesCryptoKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||
}
|
||||
|
||||
public async onDecrypt(
|
||||
algorithm: Algorithm,
|
||||
key: AesCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return AesCrypto.decrypt(
|
||||
algorithm,
|
||||
getCryptoKey(key) as AesCryptoKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
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, getCryptoKey(key) as AesCryptoKey);
|
||||
}
|
||||
|
||||
public async onImportKey(
|
||||
format: KeyFormat,
|
||||
keyData: JsonWebKey | ArrayBuffer,
|
||||
algorithm: Algorithm,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKey> {
|
||||
const res = await AesCrypto.importKey(
|
||||
format,
|
||||
keyData,
|
||||
{ name: algorithm.name },
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
||||
return setCryptoKey(res);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,68 +4,33 @@ import { AesCryptoKey } from "./key";
|
|||
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||
|
||||
export class AesGcmProvider extends core.AesGcmProvider {
|
||||
public async onGenerateKey(
|
||||
algorithm: AesKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKey> {
|
||||
|
||||
public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
const key = await AesCrypto.generateKey(
|
||||
{
|
||||
name: this.name,
|
||||
length: algorithm.length,
|
||||
},
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
keyUsages);
|
||||
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
public async onEncrypt(
|
||||
algorithm: AesGcmParams,
|
||||
key: AesCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return AesCrypto.encrypt(
|
||||
algorithm,
|
||||
getCryptoKey(key) as AesCryptoKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onEncrypt(algorithm: AesGcmParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||
}
|
||||
|
||||
public async onDecrypt(
|
||||
algorithm: AesGcmParams,
|
||||
key: AesCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return AesCrypto.decrypt(
|
||||
algorithm,
|
||||
getCryptoKey(key) as AesCryptoKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onDecrypt(algorithm: AesGcmParams, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
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, getCryptoKey(key) as AesCryptoKey);
|
||||
}
|
||||
|
||||
public async onImportKey(
|
||||
format: KeyFormat,
|
||||
keyData: JsonWebKey | ArrayBuffer,
|
||||
algorithm: Algorithm,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKey> {
|
||||
const res = await AesCrypto.importKey(
|
||||
format,
|
||||
keyData,
|
||||
{ name: algorithm.name },
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
||||
return setCryptoKey(res);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,68 +4,34 @@ import { AesCryptoKey } from "./key";
|
|||
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||
|
||||
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> {
|
||||
const res = await AesCrypto.generateKey(
|
||||
{
|
||||
name: this.name,
|
||||
length: algorithm.length,
|
||||
},
|
||||
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, getCryptoKey(key) as AesCryptoKey);
|
||||
}
|
||||
|
||||
public async onImportKey(
|
||||
format: KeyFormat,
|
||||
keyData: JsonWebKey | ArrayBuffer,
|
||||
algorithm: Algorithm,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKey> {
|
||||
const res = await AesCrypto.importKey(
|
||||
format,
|
||||
keyData,
|
||||
{ name: algorithm.name },
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
const res = await AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
||||
return setCryptoKey(res);
|
||||
}
|
||||
|
||||
public override async onEncrypt(
|
||||
algorithm: Algorithm,
|
||||
key: AesCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return AesCrypto.encrypt(
|
||||
algorithm,
|
||||
getCryptoKey(key) as AesCryptoKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public override async onEncrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return AesCrypto.encrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||
}
|
||||
|
||||
public override async onDecrypt(
|
||||
algorithm: Algorithm,
|
||||
key: AesCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return AesCrypto.decrypt(
|
||||
algorithm,
|
||||
getCryptoKey(key) as AesCryptoKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public override async onDecrypt(algorithm: Algorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return AesCrypto.decrypt(algorithm, getCryptoKey(key) as AesCryptoKey, new Uint8Array(data));
|
||||
}
|
||||
|
||||
public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Buffer } from "buffer";
|
||||
import crypto, { CipherGCM, DecipherGCM } from "crypto";
|
||||
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||
import * as core from "webcrypto-core";
|
||||
|
@ -6,13 +5,10 @@ import { AesCryptoKey } from "./key";
|
|||
import { CryptoKey } from "../../keys";
|
||||
|
||||
export class AesCrypto {
|
||||
|
||||
public static AES_KW_IV = Buffer.from("A6A6A6A6A6A6A6A6", "hex");
|
||||
|
||||
public static async generateKey(
|
||||
algorithm: AesKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<AesCryptoKey> {
|
||||
public static async generateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<AesCryptoKey> {
|
||||
const key = new AesCryptoKey();
|
||||
key.algorithm = algorithm;
|
||||
key.extractable = extractable;
|
||||
|
@ -22,10 +18,7 @@ export class AesCrypto {
|
|||
return key;
|
||||
}
|
||||
|
||||
public static async exportKey(
|
||||
format: string,
|
||||
key: AesCryptoKey
|
||||
): Promise<JsonWebKey | ArrayBuffer> {
|
||||
public static async exportKey(format: string, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||
if (!(key instanceof AesCryptoKey)) {
|
||||
throw new Error("key: Is not AesCryptoKey");
|
||||
}
|
||||
|
@ -40,13 +33,7 @@ export class AesCrypto {
|
|||
}
|
||||
}
|
||||
|
||||
public static async importKey(
|
||||
format: string,
|
||||
keyData: JsonWebKey | ArrayBuffer,
|
||||
algorithm: any,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKey> {
|
||||
public static async importKey(format: string, keyData: JsonWebKey | ArrayBuffer, algorithm: any, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
let key: AesCryptoKey;
|
||||
|
||||
switch (format.toLowerCase()) {
|
||||
|
@ -79,167 +66,78 @@ export class AesCrypto {
|
|||
return key;
|
||||
}
|
||||
|
||||
public static async encrypt(
|
||||
algorithm: Algorithm,
|
||||
key: AesCryptoKey,
|
||||
data: Uint8Array
|
||||
): Promise<ArrayBuffer> {
|
||||
public static async encrypt(algorithm: Algorithm, key: AesCryptoKey, data: Uint8Array): Promise<ArrayBuffer> {
|
||||
switch (algorithm.name.toUpperCase()) {
|
||||
case "AES-CBC":
|
||||
return this.encryptAesCBC(
|
||||
algorithm as AesCbcParams,
|
||||
key,
|
||||
Buffer.from(data)
|
||||
);
|
||||
return this.encryptAesCBC(algorithm as AesCbcParams, key, Buffer.from(data));
|
||||
case "AES-CTR":
|
||||
return this.encryptAesCTR(
|
||||
algorithm as AesCtrParams,
|
||||
key,
|
||||
Buffer.from(data)
|
||||
);
|
||||
return this.encryptAesCTR(algorithm as AesCtrParams, key, Buffer.from(data));
|
||||
case "AES-GCM":
|
||||
return this.encryptAesGCM(
|
||||
algorithm as AesGcmParams,
|
||||
key,
|
||||
Buffer.from(data)
|
||||
);
|
||||
return this.encryptAesGCM(algorithm as AesGcmParams, key, Buffer.from(data));
|
||||
case "AES-KW":
|
||||
return this.encryptAesKW(
|
||||
algorithm as AesKeyAlgorithm,
|
||||
key,
|
||||
Buffer.from(data)
|
||||
);
|
||||
return this.encryptAesKW(algorithm as AesKeyAlgorithm, key, Buffer.from(data));
|
||||
case "AES-ECB":
|
||||
return this.encryptAesECB(
|
||||
algorithm as AesKeyAlgorithm,
|
||||
key,
|
||||
Buffer.from(data)
|
||||
);
|
||||
return this.encryptAesECB(algorithm as AesKeyAlgorithm, key, Buffer.from(data));
|
||||
default:
|
||||
throw new core.OperationError("algorithm: Is not recognized");
|
||||
}
|
||||
}
|
||||
|
||||
public static async decrypt(
|
||||
algorithm: Algorithm,
|
||||
key: CryptoKey,
|
||||
data: Uint8Array
|
||||
): Promise<ArrayBuffer> {
|
||||
public static async decrypt(algorithm: Algorithm, key: CryptoKey, data: Uint8Array): Promise<ArrayBuffer> {
|
||||
if (!(key instanceof AesCryptoKey)) {
|
||||
throw new Error("key: Is not AesCryptoKey");
|
||||
}
|
||||
|
||||
switch (algorithm.name.toUpperCase()) {
|
||||
case "AES-CBC":
|
||||
return this.decryptAesCBC(
|
||||
algorithm as AesCbcParams,
|
||||
key,
|
||||
Buffer.from(data)
|
||||
);
|
||||
return this.decryptAesCBC(algorithm as AesCbcParams, key, Buffer.from(data));
|
||||
case "AES-CTR":
|
||||
return this.decryptAesCTR(
|
||||
algorithm as AesCtrParams,
|
||||
key,
|
||||
Buffer.from(data)
|
||||
);
|
||||
return this.decryptAesCTR(algorithm as AesCtrParams, key, Buffer.from(data));
|
||||
case "AES-GCM":
|
||||
return this.decryptAesGCM(
|
||||
algorithm as AesGcmParams,
|
||||
key,
|
||||
Buffer.from(data)
|
||||
);
|
||||
return this.decryptAesGCM(algorithm as AesGcmParams, key, Buffer.from(data));
|
||||
case "AES-KW":
|
||||
return this.decryptAesKW(
|
||||
algorithm as AesKeyAlgorithm,
|
||||
key,
|
||||
Buffer.from(data)
|
||||
);
|
||||
return this.decryptAesKW(algorithm as AesKeyAlgorithm, key, Buffer.from(data));
|
||||
case "AES-ECB":
|
||||
return this.decryptAesECB(
|
||||
algorithm as AesKeyAlgorithm,
|
||||
key,
|
||||
Buffer.from(data)
|
||||
);
|
||||
return this.decryptAesECB(algorithm as AesKeyAlgorithm, key, Buffer.from(data));
|
||||
default:
|
||||
throw new core.OperationError("algorithm: Is not recognized");
|
||||
}
|
||||
}
|
||||
|
||||
public static async encryptAesCBC(
|
||||
algorithm: AesCbcParams,
|
||||
key: AesCryptoKey,
|
||||
data: Buffer
|
||||
) {
|
||||
const cipher = crypto.createCipheriv(
|
||||
`aes-${key.algorithm.length}-cbc`,
|
||||
key.data,
|
||||
new Uint8Array(algorithm.iv as ArrayBuffer)
|
||||
);
|
||||
public static async encryptAesCBC(algorithm: AesCbcParams, key: AesCryptoKey, data: Buffer) {
|
||||
const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-cbc`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer));
|
||||
let enc = cipher.update(data);
|
||||
enc = Buffer.concat([enc, cipher.final()]);
|
||||
const res = new Uint8Array(enc).buffer;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static async decryptAesCBC(
|
||||
algorithm: AesCbcParams,
|
||||
key: AesCryptoKey,
|
||||
data: Buffer
|
||||
) {
|
||||
const decipher = crypto.createDecipheriv(
|
||||
`aes-${key.algorithm.length}-cbc`,
|
||||
key.data,
|
||||
new Uint8Array(algorithm.iv as ArrayBuffer)
|
||||
);
|
||||
public static async decryptAesCBC(algorithm: AesCbcParams, key: AesCryptoKey, data: Buffer) {
|
||||
const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-cbc`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer));
|
||||
let dec = decipher.update(data);
|
||||
dec = Buffer.concat([dec, decipher.final()]);
|
||||
return new Uint8Array(dec).buffer;
|
||||
}
|
||||
|
||||
public static async encryptAesCTR(
|
||||
algorithm: AesCtrParams,
|
||||
key: AesCryptoKey,
|
||||
data: Buffer
|
||||
) {
|
||||
const cipher = crypto.createCipheriv(
|
||||
`aes-${key.algorithm.length}-ctr`,
|
||||
key.data,
|
||||
Buffer.from(algorithm.counter as ArrayBuffer)
|
||||
);
|
||||
public static async encryptAesCTR(algorithm: AesCtrParams, key: AesCryptoKey, data: Buffer) {
|
||||
const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-ctr`, key.data, Buffer.from(algorithm.counter as ArrayBuffer));
|
||||
let enc = cipher.update(data);
|
||||
enc = Buffer.concat([enc, cipher.final()]);
|
||||
const res = new Uint8Array(enc).buffer;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static async decryptAesCTR(
|
||||
algorithm: AesCtrParams,
|
||||
key: AesCryptoKey,
|
||||
data: Buffer
|
||||
) {
|
||||
const decipher = crypto.createDecipheriv(
|
||||
`aes-${key.algorithm.length}-ctr`,
|
||||
key.data,
|
||||
new Uint8Array(algorithm.counter as ArrayBuffer)
|
||||
);
|
||||
public static async decryptAesCTR(algorithm: AesCtrParams, key: AesCryptoKey, data: Buffer) {
|
||||
const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-ctr`, key.data, new Uint8Array(algorithm.counter as ArrayBuffer));
|
||||
let dec = decipher.update(data);
|
||||
dec = Buffer.concat([dec, decipher.final()]);
|
||||
return new Uint8Array(dec).buffer;
|
||||
}
|
||||
|
||||
public static async encryptAesGCM(
|
||||
algorithm: AesGcmParams,
|
||||
key: AesCryptoKey,
|
||||
data: Buffer
|
||||
) {
|
||||
const cipher = crypto.createCipheriv(
|
||||
`aes-${key.algorithm.length}-gcm`,
|
||||
key.data,
|
||||
Buffer.from(algorithm.iv as ArrayBuffer),
|
||||
{
|
||||
authTagLength: (algorithm.tagLength || 128) >> 3,
|
||||
} as any
|
||||
) as CipherGCM; // NodeJs d.ts doesn't support CipherGCMOptions for createCipheriv
|
||||
public static async encryptAesGCM(algorithm: AesGcmParams, key: AesCryptoKey, data: Buffer) {
|
||||
const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-gcm`, key.data, Buffer.from(algorithm.iv as ArrayBuffer), {
|
||||
authTagLength: (algorithm.tagLength || 128) >> 3,
|
||||
} as any) as CipherGCM; // NodeJs d.ts doesn't support CipherGCMOptions for createCipheriv
|
||||
if (algorithm.additionalData) {
|
||||
cipher.setAAD(Buffer.from(algorithm.additionalData as ArrayBuffer));
|
||||
}
|
||||
|
@ -249,16 +147,8 @@ export class AesCrypto {
|
|||
return res;
|
||||
}
|
||||
|
||||
public static async decryptAesGCM(
|
||||
algorithm: AesGcmParams,
|
||||
key: AesCryptoKey,
|
||||
data: Buffer
|
||||
) {
|
||||
const decipher = crypto.createDecipheriv(
|
||||
`aes-${key.algorithm.length}-gcm`,
|
||||
key.data,
|
||||
new Uint8Array(algorithm.iv as ArrayBuffer)
|
||||
) as DecipherGCM;
|
||||
public static async decryptAesGCM(algorithm: AesGcmParams, key: AesCryptoKey, data: Buffer) {
|
||||
const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-gcm`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer)) as DecipherGCM;
|
||||
const tagLength = (algorithm.tagLength || 128) >> 3;
|
||||
const enc = data.slice(0, data.length - tagLength);
|
||||
const tag = data.slice(data.length - tagLength);
|
||||
|
@ -271,62 +161,30 @@ export class AesCrypto {
|
|||
return new Uint8Array(dec).buffer;
|
||||
}
|
||||
|
||||
public static async encryptAesKW(
|
||||
algorithm: Algorithm,
|
||||
key: AesCryptoKey,
|
||||
data: Buffer
|
||||
) {
|
||||
const cipher = crypto.createCipheriv(
|
||||
`id-aes${key.algorithm.length}-wrap`,
|
||||
key.data,
|
||||
this.AES_KW_IV
|
||||
);
|
||||
public static async encryptAesKW(algorithm: Algorithm, key: AesCryptoKey, data: Buffer) {
|
||||
const cipher = crypto.createCipheriv(`id-aes${key.algorithm.length}-wrap`, key.data, this.AES_KW_IV);
|
||||
let enc = cipher.update(data);
|
||||
enc = Buffer.concat([enc, cipher.final()]);
|
||||
return new Uint8Array(enc).buffer;
|
||||
}
|
||||
|
||||
public static async decryptAesKW(
|
||||
algorithm: Algorithm,
|
||||
key: AesCryptoKey,
|
||||
data: Buffer
|
||||
) {
|
||||
const decipher = crypto.createDecipheriv(
|
||||
`id-aes${key.algorithm.length}-wrap`,
|
||||
key.data,
|
||||
this.AES_KW_IV
|
||||
);
|
||||
public static async decryptAesKW(algorithm: Algorithm, key: AesCryptoKey, data: Buffer) {
|
||||
const decipher = crypto.createDecipheriv(`id-aes${key.algorithm.length}-wrap`, key.data, this.AES_KW_IV);
|
||||
let dec = decipher.update(data);
|
||||
dec = Buffer.concat([dec, decipher.final()]);
|
||||
return new Uint8Array(dec).buffer;
|
||||
}
|
||||
|
||||
public static async encryptAesECB(
|
||||
algorithm: Algorithm,
|
||||
key: AesCryptoKey,
|
||||
data: Buffer
|
||||
) {
|
||||
const cipher = crypto.createCipheriv(
|
||||
`aes-${key.algorithm.length}-ecb`,
|
||||
key.data,
|
||||
new Uint8Array(0)
|
||||
);
|
||||
public static async encryptAesECB(algorithm: Algorithm, key: AesCryptoKey, data: Buffer) {
|
||||
const cipher = crypto.createCipheriv(`aes-${key.algorithm.length}-ecb`, key.data, new Uint8Array(0));
|
||||
let enc = cipher.update(data);
|
||||
enc = Buffer.concat([enc, cipher.final()]);
|
||||
const res = new Uint8Array(enc).buffer;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static async decryptAesECB(
|
||||
algorithm: Algorithm,
|
||||
key: AesCryptoKey,
|
||||
data: Buffer
|
||||
) {
|
||||
const decipher = crypto.createDecipheriv(
|
||||
`aes-${key.algorithm.length}-ecb`,
|
||||
key.data,
|
||||
new Uint8Array(0)
|
||||
);
|
||||
public static async decryptAesECB(algorithm: Algorithm, key: AesCryptoKey, data: Buffer) {
|
||||
const decipher = crypto.createDecipheriv(`aes-${key.algorithm.length}-ecb`, key.data, new Uint8Array(0));
|
||||
let dec = decipher.update(data);
|
||||
dec = Buffer.concat([dec, decipher.final()]);
|
||||
return new Uint8Array(dec).buffer;
|
||||
|
|
|
@ -4,9 +4,10 @@ import { JsonBase64UrlConverter } from "../../converters";
|
|||
import { SymmetricKey } from "../../keys";
|
||||
|
||||
export class AesCryptoKey extends SymmetricKey {
|
||||
|
||||
public override algorithm!: AesKeyAlgorithm;
|
||||
|
||||
@JsonProp({ name: "k", converter: JsonBase64UrlConverter })
|
||||
@JsonProp({name: "k", converter: JsonBase64UrlConverter})
|
||||
public override data!: Buffer;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
|
@ -33,4 +34,5 @@ export class AesCryptoKey extends SymmetricKey {
|
|||
public override set alg(value: string) {
|
||||
// nothing, cause set is needed for json-schema, but is not used by module
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Buffer } from "buffer";
|
||||
import crypto from "crypto";
|
||||
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||
import * as core from "webcrypto-core";
|
||||
|
@ -7,11 +6,8 @@ import { DesCryptoKey } from "./key";
|
|||
import { CryptoKey } from "../../keys";
|
||||
|
||||
export class DesCrypto {
|
||||
public static async generateKey(
|
||||
algorithm: AesKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<DesCryptoKey> {
|
||||
|
||||
public static async generateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<DesCryptoKey> {
|
||||
const key = new DesCryptoKey();
|
||||
key.algorithm = algorithm;
|
||||
key.extractable = extractable;
|
||||
|
@ -21,10 +17,7 @@ export class DesCrypto {
|
|||
return key;
|
||||
}
|
||||
|
||||
public static async exportKey(
|
||||
format: string,
|
||||
key: CryptoKey
|
||||
): Promise<JsonWebKey | ArrayBuffer> {
|
||||
public static async exportKey(format: string, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||
switch (format.toLowerCase()) {
|
||||
case "jwk":
|
||||
return JsonSerializer.toJSON(key);
|
||||
|
@ -35,13 +28,7 @@ export class DesCrypto {
|
|||
}
|
||||
}
|
||||
|
||||
public static async importKey(
|
||||
format: string,
|
||||
keyData: JsonWebKey | ArrayBuffer,
|
||||
algorithm: any,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKey> {
|
||||
public static async importKey(format: string, keyData: JsonWebKey | ArrayBuffer, algorithm: any, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
let key: DesCryptoKey;
|
||||
|
||||
switch (format.toLowerCase()) {
|
||||
|
@ -63,11 +50,7 @@ export class DesCrypto {
|
|||
return key;
|
||||
}
|
||||
|
||||
public static async encrypt(
|
||||
algorithm: DesParams,
|
||||
key: DesCryptoKey,
|
||||
data: Uint8Array
|
||||
): Promise<ArrayBuffer> {
|
||||
public static async encrypt(algorithm: DesParams, key: DesCryptoKey, data: Uint8Array): Promise<ArrayBuffer> {
|
||||
switch (algorithm.name.toUpperCase()) {
|
||||
case "DES-CBC":
|
||||
return this.encryptDesCBC(algorithm, key, Buffer.from(data));
|
||||
|
@ -78,11 +61,7 @@ export class DesCrypto {
|
|||
}
|
||||
}
|
||||
|
||||
public static async decrypt(
|
||||
algorithm: DesParams,
|
||||
key: CryptoKey,
|
||||
data: Uint8Array
|
||||
): Promise<ArrayBuffer> {
|
||||
public static async decrypt(algorithm: DesParams, key: CryptoKey, data: Uint8Array): Promise<ArrayBuffer> {
|
||||
if (!(key instanceof DesCryptoKey)) {
|
||||
throw new Error("key: Is not DesCryptoKey");
|
||||
}
|
||||
|
@ -97,65 +76,34 @@ export class DesCrypto {
|
|||
}
|
||||
}
|
||||
|
||||
public static async encryptDesCBC(
|
||||
algorithm: DesParams,
|
||||
key: DesCryptoKey,
|
||||
data: Buffer
|
||||
) {
|
||||
const cipher = crypto.createCipheriv(
|
||||
`des-cbc`,
|
||||
key.data,
|
||||
new Uint8Array(algorithm.iv as ArrayBuffer)
|
||||
);
|
||||
public static async encryptDesCBC(algorithm: DesParams, key: DesCryptoKey, data: Buffer) {
|
||||
const cipher = crypto.createCipheriv(`des-cbc`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer));
|
||||
let enc = cipher.update(data);
|
||||
enc = Buffer.concat([enc, cipher.final()]);
|
||||
const res = new Uint8Array(enc).buffer;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static async decryptDesCBC(
|
||||
algorithm: DesParams,
|
||||
key: DesCryptoKey,
|
||||
data: Buffer
|
||||
) {
|
||||
const decipher = crypto.createDecipheriv(
|
||||
`des-cbc`,
|
||||
key.data,
|
||||
new Uint8Array(algorithm.iv as ArrayBuffer)
|
||||
);
|
||||
public static async decryptDesCBC(algorithm: DesParams, key: DesCryptoKey, data: Buffer) {
|
||||
const decipher = crypto.createDecipheriv(`des-cbc`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer));
|
||||
let dec = decipher.update(data);
|
||||
dec = Buffer.concat([dec, decipher.final()]);
|
||||
return new Uint8Array(dec).buffer;
|
||||
}
|
||||
|
||||
public static async encryptDesEDE3CBC(
|
||||
algorithm: DesParams,
|
||||
key: DesCryptoKey,
|
||||
data: Buffer
|
||||
) {
|
||||
const cipher = crypto.createCipheriv(
|
||||
`des-ede3-cbc`,
|
||||
key.data,
|
||||
Buffer.from(algorithm.iv as ArrayBuffer)
|
||||
);
|
||||
public static async encryptDesEDE3CBC(algorithm: DesParams, key: DesCryptoKey, data: Buffer) {
|
||||
const cipher = crypto.createCipheriv(`des-ede3-cbc`, key.data, Buffer.from(algorithm.iv as ArrayBuffer));
|
||||
let enc = cipher.update(data);
|
||||
enc = Buffer.concat([enc, cipher.final()]);
|
||||
const res = new Uint8Array(enc).buffer;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static async decryptDesEDE3CBC(
|
||||
algorithm: DesParams,
|
||||
key: DesCryptoKey,
|
||||
data: Buffer
|
||||
) {
|
||||
const decipher = crypto.createDecipheriv(
|
||||
`des-ede3-cbc`,
|
||||
key.data,
|
||||
new Uint8Array(algorithm.iv as ArrayBuffer)
|
||||
);
|
||||
public static async decryptDesEDE3CBC(algorithm: DesParams, key: DesCryptoKey, data: Buffer) {
|
||||
const decipher = crypto.createDecipheriv(`des-ede3-cbc`, key.data, new Uint8Array(algorithm.iv as ArrayBuffer));
|
||||
let dec = decipher.update(data);
|
||||
dec = Buffer.concat([dec, decipher.final()]);
|
||||
return new Uint8Array(dec).buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,73 +7,38 @@ import { setCryptoKey, getCryptoKey } from "../storage";
|
|||
export type DesCbcParams = core.DesParams;
|
||||
|
||||
export class DesCbcProvider extends core.DesProvider {
|
||||
|
||||
public keySizeBits = 64;
|
||||
public ivSize = 8;
|
||||
public name = "DES-CBC";
|
||||
|
||||
public async onGenerateKey(
|
||||
algorithm: core.DesKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<core.CryptoKey> {
|
||||
public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
|
||||
const key = await DesCrypto.generateKey(
|
||||
{
|
||||
name: this.name,
|
||||
length: this.keySizeBits,
|
||||
},
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
keyUsages);
|
||||
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
public async onEncrypt(
|
||||
algorithm: DesCbcParams,
|
||||
key: DesCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return DesCrypto.encrypt(
|
||||
algorithm,
|
||||
getCryptoKey(key) as DesCryptoKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onEncrypt(algorithm: DesCbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return DesCrypto.encrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data));
|
||||
}
|
||||
|
||||
public async onDecrypt(
|
||||
algorithm: DesCbcParams,
|
||||
key: DesCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return DesCrypto.decrypt(
|
||||
algorithm,
|
||||
getCryptoKey(key) as DesCryptoKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onDecrypt(algorithm: DesCbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
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, getCryptoKey(key) as DesCryptoKey);
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
if (key.data.length !== this.keySizeBits >> 3) {
|
||||
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);
|
||||
if (key.data.length !== (this.keySizeBits >> 3)) {
|
||||
throw new core.OperationError("keyData: Wrong key size");
|
||||
}
|
||||
return setCryptoKey(key);
|
||||
|
@ -85,4 +50,5 @@ export class DesCbcProvider extends core.DesProvider {
|
|||
throw new TypeError("key: Is not a DesCryptoKey");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,73 +7,38 @@ import { setCryptoKey, getCryptoKey } from "../storage";
|
|||
export type DesEde3CbcParams = core.DesParams;
|
||||
|
||||
export class DesEde3CbcProvider extends core.DesProvider {
|
||||
|
||||
public keySizeBits = 192;
|
||||
public ivSize = 8;
|
||||
public name = "DES-EDE3-CBC";
|
||||
|
||||
public async onGenerateKey(
|
||||
algorithm: core.DesKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<core.CryptoKey> {
|
||||
public async onGenerateKey(algorithm: core.DesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
|
||||
const key = await DesCrypto.generateKey(
|
||||
{
|
||||
name: this.name,
|
||||
length: this.keySizeBits,
|
||||
},
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
keyUsages);
|
||||
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
public async onEncrypt(
|
||||
algorithm: DesEde3CbcParams,
|
||||
key: DesCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return DesCrypto.encrypt(
|
||||
algorithm,
|
||||
getCryptoKey(key) as DesCryptoKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onEncrypt(algorithm: DesEde3CbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return DesCrypto.encrypt(algorithm, getCryptoKey(key) as DesCryptoKey, new Uint8Array(data));
|
||||
}
|
||||
|
||||
public async onDecrypt(
|
||||
algorithm: DesEde3CbcParams,
|
||||
key: DesCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return DesCrypto.decrypt(
|
||||
algorithm,
|
||||
getCryptoKey(key) as DesCryptoKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onDecrypt(algorithm: DesEde3CbcParams, key: DesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
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, getCryptoKey(key) as DesCryptoKey);
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
if (key.data.length !== this.keySizeBits >> 3) {
|
||||
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);
|
||||
if (key.data.length !== (this.keySizeBits >> 3)) {
|
||||
throw new core.OperationError("keyData: Wrong key size");
|
||||
}
|
||||
return setCryptoKey(key);
|
||||
|
@ -85,4 +50,5 @@ export class DesEde3CbcProvider extends core.DesProvider {
|
|||
throw new TypeError("key: Is not a DesCryptoKey");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,9 +4,10 @@ import { JsonBase64UrlConverter } from "../../converters";
|
|||
import { SymmetricKey } from "../../keys";
|
||||
|
||||
export class DesCryptoKey extends SymmetricKey {
|
||||
|
||||
public override algorithm!: core.DesKeyAlgorithm;
|
||||
|
||||
@JsonProp({ name: "k", converter: JsonBase64UrlConverter })
|
||||
@JsonProp({name: "k", converter: JsonBase64UrlConverter})
|
||||
public override data!: Buffer;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
|
@ -25,4 +26,5 @@ export class DesCryptoKey extends SymmetricKey {
|
|||
public override set alg(value: string) {
|
||||
// nothing, cause set is needed for json-schema, but is not used by module
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Buffer } from "buffer";
|
||||
import crypto from "crypto";
|
||||
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
|
||||
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||
|
@ -11,27 +10,20 @@ import { CryptoKey } from "../../keys";
|
|||
import { ShaCrypto } from "../sha";
|
||||
|
||||
export class EcCrypto {
|
||||
|
||||
public static publicKeyUsages = ["verify"];
|
||||
public static privateKeyUsages = ["sign", "deriveKey", "deriveBits"];
|
||||
|
||||
public static async generateKey(
|
||||
algorithm: EcKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKeyPair> {
|
||||
public static async generateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||
const privateKey = new EcPrivateKey();
|
||||
privateKey.algorithm = algorithm;
|
||||
privateKey.extractable = extractable;
|
||||
privateKey.usages = keyUsages.filter(
|
||||
(usage) => this.privateKeyUsages.indexOf(usage) !== -1
|
||||
);
|
||||
privateKey.usages = keyUsages.filter((usage) => this.privateKeyUsages.indexOf(usage) !== -1);
|
||||
|
||||
const publicKey = new EcPublicKey();
|
||||
publicKey.algorithm = algorithm;
|
||||
publicKey.extractable = true;
|
||||
publicKey.usages = keyUsages.filter(
|
||||
(usage) => this.publicKeyUsages.indexOf(usage) !== -1
|
||||
);
|
||||
publicKey.usages = keyUsages.filter((usage) => this.publicKeyUsages.indexOf(usage) !== -1);
|
||||
|
||||
const keys = crypto.generateKeyPairSync("ec", {
|
||||
namedCurve: this.getOpenSSLNamedCurve(algorithm.namedCurve),
|
||||
|
@ -56,19 +48,13 @@ export class EcCrypto {
|
|||
return res;
|
||||
}
|
||||
|
||||
public static async sign(
|
||||
algorithm: EcdsaParams,
|
||||
key: EcPrivateKey,
|
||||
data: Uint8Array
|
||||
): Promise<ArrayBuffer> {
|
||||
public static async sign(algorithm: EcdsaParams, key: EcPrivateKey, data: Uint8Array): Promise<ArrayBuffer> {
|
||||
const cryptoAlg = ShaCrypto.getAlgorithmName(algorithm.hash as Algorithm);
|
||||
const signer = crypto.createSign(cryptoAlg);
|
||||
signer.update(Buffer.from(data));
|
||||
|
||||
if (!key.pem) {
|
||||
key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString(
|
||||
"base64"
|
||||
)}\n-----END PRIVATE KEY-----`;
|
||||
key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`;
|
||||
}
|
||||
const options = {
|
||||
key: key.pem,
|
||||
|
@ -77,28 +63,18 @@ export class EcCrypto {
|
|||
const signature = signer.sign(options);
|
||||
const ecSignature = AsnParser.parse(signature, core.asn1.EcDsaSignature);
|
||||
|
||||
const signatureRaw = core.EcUtils.encodeSignature(
|
||||
ecSignature,
|
||||
core.EcCurves.get(key.algorithm.namedCurve).size
|
||||
);
|
||||
const signatureRaw = core.EcUtils.encodeSignature(ecSignature, core.EcCurves.get(key.algorithm.namedCurve).size);
|
||||
|
||||
return signatureRaw.buffer;
|
||||
}
|
||||
|
||||
public static async verify(
|
||||
algorithm: EcdsaParams,
|
||||
key: EcPublicKey,
|
||||
signature: Uint8Array,
|
||||
data: Uint8Array
|
||||
): Promise<boolean> {
|
||||
public static async verify(algorithm: EcdsaParams, key: EcPublicKey, signature: Uint8Array, data: Uint8Array): Promise<boolean> {
|
||||
const cryptoAlg = ShaCrypto.getAlgorithmName(algorithm.hash as Algorithm);
|
||||
const signer = crypto.createVerify(cryptoAlg);
|
||||
signer.update(Buffer.from(data));
|
||||
|
||||
if (!key.pem) {
|
||||
key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString(
|
||||
"base64"
|
||||
)}\n-----END PUBLIC KEY-----`;
|
||||
key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`;
|
||||
}
|
||||
const options = {
|
||||
key: key.pem,
|
||||
|
@ -106,10 +82,7 @@ export class EcCrypto {
|
|||
|
||||
const ecSignature = new core.asn1.EcDsaSignature();
|
||||
const namedCurve = core.EcCurves.get(key.algorithm.namedCurve);
|
||||
const signaturePoint = core.EcUtils.decodeSignature(
|
||||
signature,
|
||||
namedCurve.size
|
||||
);
|
||||
const signaturePoint = core.EcUtils.decodeSignature(signature, namedCurve.size);
|
||||
ecSignature.r = BufferSourceConverter.toArrayBuffer(signaturePoint.r);
|
||||
ecSignature.s = BufferSourceConverter.toArrayBuffer(signaturePoint.s);
|
||||
|
||||
|
@ -118,30 +91,15 @@ export class EcCrypto {
|
|||
return ok;
|
||||
}
|
||||
|
||||
public static async deriveBits(
|
||||
algorithm: EcdhKeyDeriveParams,
|
||||
baseKey: CryptoKey,
|
||||
length: number | null
|
||||
): Promise<ArrayBuffer> {
|
||||
const cryptoAlg = this.getOpenSSLNamedCurve(
|
||||
(baseKey.algorithm as EcKeyAlgorithm).namedCurve
|
||||
);
|
||||
public static async deriveBits(algorithm: EcdhKeyDeriveParams, baseKey: CryptoKey, length: number | null): Promise<ArrayBuffer> {
|
||||
const cryptoAlg = this.getOpenSSLNamedCurve((baseKey.algorithm as EcKeyAlgorithm).namedCurve);
|
||||
|
||||
const ecdh = crypto.createECDH(cryptoAlg);
|
||||
const asnPrivateKey = AsnParser.parse(
|
||||
baseKey.data,
|
||||
core.asn1.PrivateKeyInfo
|
||||
);
|
||||
const asnEcPrivateKey = AsnParser.parse(
|
||||
asnPrivateKey.privateKey,
|
||||
core.asn1.EcPrivateKey
|
||||
);
|
||||
const asnPrivateKey = AsnParser.parse(baseKey.data, core.asn1.PrivateKeyInfo);
|
||||
const asnEcPrivateKey = AsnParser.parse(asnPrivateKey.privateKey, core.asn1.EcPrivateKey);
|
||||
ecdh.setPrivateKey(Buffer.from(asnEcPrivateKey.privateKey));
|
||||
|
||||
const asnPublicKey = AsnParser.parse(
|
||||
(algorithm.public as CryptoKey).data,
|
||||
core.asn1.PublicKeyInfo
|
||||
);
|
||||
const asnPublicKey = AsnParser.parse((algorithm.public as CryptoKey).data, core.asn1.PublicKeyInfo);
|
||||
const bits = ecdh.computeSecret(Buffer.from(asnPublicKey.publicKey));
|
||||
|
||||
if (length === null) {
|
||||
|
@ -151,10 +109,7 @@ export class EcCrypto {
|
|||
return new Uint8Array(bits).buffer.slice(0, length >> 3);
|
||||
}
|
||||
|
||||
public static async exportKey(
|
||||
format: KeyFormat,
|
||||
key: CryptoKey
|
||||
): Promise<JsonWebKey | ArrayBuffer> {
|
||||
public static async exportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||
switch (format.toLowerCase()) {
|
||||
case "jwk":
|
||||
return JsonSerializer.toJSON(key);
|
||||
|
@ -162,49 +117,24 @@ export class EcCrypto {
|
|||
case "spki":
|
||||
return new Uint8Array(key.data).buffer;
|
||||
case "raw": {
|
||||
const publicKeyInfo = AsnParser.parse(
|
||||
key.data,
|
||||
core.asn1.PublicKeyInfo
|
||||
);
|
||||
const publicKeyInfo = AsnParser.parse(key.data, core.asn1.PublicKeyInfo);
|
||||
return publicKeyInfo.publicKey;
|
||||
}
|
||||
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'");
|
||||
}
|
||||
}
|
||||
|
||||
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()) {
|
||||
case "jwk": {
|
||||
const jwk = keyData as JsonWebKey;
|
||||
if (jwk.d) {
|
||||
const asnKey = JsonParser.fromJSON(keyData, {
|
||||
targetSchema: core.asn1.EcPrivateKey,
|
||||
});
|
||||
return this.importPrivateKey(
|
||||
asnKey,
|
||||
algorithm,
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.EcPrivateKey });
|
||||
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
|
||||
} else {
|
||||
const asnKey = JsonParser.fromJSON(keyData, {
|
||||
targetSchema: core.asn1.EcPublicKey,
|
||||
});
|
||||
return this.importPublicKey(
|
||||
asnKey,
|
||||
algorithm,
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.EcPublicKey });
|
||||
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
|
||||
}
|
||||
}
|
||||
case "raw": {
|
||||
|
@ -212,75 +142,43 @@ export class EcCrypto {
|
|||
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
|
||||
}
|
||||
case "spki": {
|
||||
const keyInfo = AsnParser.parse(
|
||||
new Uint8Array(keyData as ArrayBuffer),
|
||||
core.asn1.PublicKeyInfo
|
||||
);
|
||||
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PublicKeyInfo);
|
||||
const asnKey = new core.asn1.EcPublicKey(keyInfo.publicKey);
|
||||
this.assertKeyParameters(
|
||||
keyInfo.publicKeyAlgorithm.parameters,
|
||||
algorithm.namedCurve
|
||||
);
|
||||
this.assertKeyParameters(keyInfo.publicKeyAlgorithm.parameters, algorithm.namedCurve);
|
||||
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
|
||||
}
|
||||
case "pkcs8": {
|
||||
const keyInfo = AsnParser.parse(
|
||||
new Uint8Array(keyData as ArrayBuffer),
|
||||
core.asn1.PrivateKeyInfo
|
||||
);
|
||||
const asnKey = AsnParser.parse(
|
||||
keyInfo.privateKey,
|
||||
core.asn1.EcPrivateKey
|
||||
);
|
||||
this.assertKeyParameters(
|
||||
keyInfo.privateKeyAlgorithm.parameters,
|
||||
algorithm.namedCurve
|
||||
);
|
||||
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PrivateKeyInfo);
|
||||
const asnKey = AsnParser.parse(keyInfo.privateKey, core.asn1.EcPrivateKey);
|
||||
this.assertKeyParameters(keyInfo.privateKeyAlgorithm.parameters, algorithm.namedCurve);
|
||||
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
|
||||
}
|
||||
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'");
|
||||
}
|
||||
}
|
||||
|
||||
protected static assertKeyParameters(
|
||||
parameters: ArrayBuffer | null | undefined,
|
||||
namedCurve: string
|
||||
) {
|
||||
protected static assertKeyParameters(parameters: ArrayBuffer | null | undefined, namedCurve: string) {
|
||||
if (!parameters) {
|
||||
throw new core.CryptoError("Key info doesn't have required parameters");
|
||||
}
|
||||
|
||||
let namedCurveIdentifier = "";
|
||||
try {
|
||||
namedCurveIdentifier = AsnParser.parse(
|
||||
parameters,
|
||||
core.asn1.ObjectIdentifier
|
||||
).value;
|
||||
namedCurveIdentifier = AsnParser.parse(parameters, core.asn1.ObjectIdentifier).value;
|
||||
} catch (e) {
|
||||
throw new core.CryptoError("Cannot read key info parameters");
|
||||
}
|
||||
|
||||
if (getOidByNamedCurve(namedCurve) !== namedCurveIdentifier) {
|
||||
throw new core.CryptoError(
|
||||
"Key info parameter doesn't match to named curve"
|
||||
);
|
||||
throw new core.CryptoError("Key info parameter doesn't match to named curve");
|
||||
}
|
||||
}
|
||||
|
||||
protected static async importPrivateKey(
|
||||
asnKey: core.asn1.EcPrivateKey,
|
||||
algorithm: EcKeyImportParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
) {
|
||||
protected static async importPrivateKey(asnKey: core.asn1.EcPrivateKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
|
||||
const keyInfo = new core.asn1.PrivateKeyInfo();
|
||||
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
|
||||
keyInfo.privateKeyAlgorithm.parameters = AsnSerializer.serialize(
|
||||
new core.asn1.ObjectIdentifier(getOidByNamedCurve(algorithm.namedCurve))
|
||||
);
|
||||
keyInfo.privateKeyAlgorithm.parameters = AsnSerializer.serialize(new core.asn1.ObjectIdentifier(getOidByNamedCurve(algorithm.namedCurve)));
|
||||
keyInfo.privateKey = AsnSerializer.serialize(asnKey);
|
||||
|
||||
const key = new EcPrivateKey();
|
||||
|
@ -293,18 +191,11 @@ export class EcCrypto {
|
|||
return key;
|
||||
}
|
||||
|
||||
protected static async importPublicKey(
|
||||
asnKey: core.asn1.EcPublicKey,
|
||||
algorithm: EcKeyImportParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
) {
|
||||
protected static async importPublicKey(asnKey: core.asn1.EcPublicKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
|
||||
const keyInfo = new core.asn1.PublicKeyInfo();
|
||||
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
|
||||
const namedCurve = getOidByNamedCurve(algorithm.namedCurve);
|
||||
keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize(
|
||||
new core.asn1.ObjectIdentifier(namedCurve)
|
||||
);
|
||||
keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize(new core.asn1.ObjectIdentifier(namedCurve));
|
||||
keyInfo.publicKey = asnKey.value;
|
||||
|
||||
const key = new EcPublicKey();
|
||||
|
@ -331,4 +222,5 @@ export class EcCrypto {
|
|||
return curve;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,21 +6,17 @@ import { CryptoKey } from "../../keys";
|
|||
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||
|
||||
export class EcdhProvider extends core.EcdhProvider {
|
||||
|
||||
public override namedCurves = core.EcCurves.names;
|
||||
|
||||
public async onGenerateKey(
|
||||
algorithm: EcKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKeyPair> {
|
||||
public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||
const keys = await EcCrypto.generateKey(
|
||||
{
|
||||
...algorithm,
|
||||
name: this.name,
|
||||
},
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
keyUsages);
|
||||
|
||||
return {
|
||||
privateKey: setCryptoKey(keys.privateKey as CryptoKey),
|
||||
|
@ -28,53 +24,26 @@ export class EcdhProvider extends core.EcdhProvider {
|
|||
};
|
||||
}
|
||||
|
||||
public async onExportKey(
|
||||
format: KeyFormat,
|
||||
key: CryptoKey
|
||||
): Promise<JsonWebKey | ArrayBuffer> {
|
||||
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||
return EcCrypto.exportKey(format, getCryptoKey(key));
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
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);
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||
super.checkCryptoKey(key, keyUsage);
|
||||
const internalKey = getCryptoKey(key);
|
||||
if (
|
||||
!(
|
||||
internalKey instanceof EcPrivateKey ||
|
||||
internalKey instanceof EcPublicKey
|
||||
)
|
||||
) {
|
||||
if (!(internalKey instanceof EcPrivateKey || internalKey instanceof EcPublicKey)) {
|
||||
throw new TypeError("key: Is not EC CryptoKey");
|
||||
}
|
||||
}
|
||||
|
||||
public async onDeriveBits(
|
||||
algorithm: EcdhKeyDeriveParams,
|
||||
baseKey: CryptoKey,
|
||||
length: number
|
||||
): Promise<ArrayBuffer> {
|
||||
const bits = await EcCrypto.deriveBits(
|
||||
{ ...algorithm, public: getCryptoKey(algorithm.public) },
|
||||
getCryptoKey(baseKey),
|
||||
length
|
||||
);
|
||||
public async onDeriveBits(algorithm: EcdhKeyDeriveParams, baseKey: CryptoKey, length: number): Promise<ArrayBuffer> {
|
||||
const bits = await EcCrypto.deriveBits({...algorithm, public: getCryptoKey(algorithm.public)}, getCryptoKey(baseKey), length);
|
||||
return bits;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,33 +5,22 @@ import { EcPublicKey } from "./public_key";
|
|||
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||
|
||||
export class EcdsaProvider extends core.EcdsaProvider {
|
||||
|
||||
public override namedCurves = core.EcCurves.names;
|
||||
|
||||
public override hashAlgorithms = [
|
||||
"SHA-1",
|
||||
"SHA-256",
|
||||
"SHA-384",
|
||||
"SHA-512",
|
||||
"shake128",
|
||||
"shake256",
|
||||
"SHA3-256",
|
||||
"SHA3-384",
|
||||
"SHA3-512",
|
||||
];
|
||||
"SHA-1", "SHA-256", "SHA-384", "SHA-512",
|
||||
"shake128", "shake256",
|
||||
"SHA3-256", "SHA3-384", "SHA3-512"];
|
||||
|
||||
public async onGenerateKey(
|
||||
algorithm: EcKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKeyPair> {
|
||||
public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||
const keys = await EcCrypto.generateKey(
|
||||
{
|
||||
...algorithm,
|
||||
name: this.name,
|
||||
},
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
keyUsages);
|
||||
|
||||
return {
|
||||
privateKey: setCryptoKey(keys.privateKey as EcPrivateKey),
|
||||
|
@ -39,66 +28,29 @@ export class EcdsaProvider extends core.EcdsaProvider {
|
|||
};
|
||||
}
|
||||
|
||||
public async onSign(
|
||||
algorithm: EcdsaParams,
|
||||
key: EcPrivateKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return EcCrypto.sign(
|
||||
algorithm,
|
||||
getCryptoKey(key) as EcPrivateKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onSign(algorithm: EcdsaParams, key: EcPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return EcCrypto.sign(algorithm, getCryptoKey(key) as EcPrivateKey, new Uint8Array(data));
|
||||
}
|
||||
|
||||
public async onVerify(
|
||||
algorithm: EcdsaParams,
|
||||
key: EcPublicKey,
|
||||
signature: ArrayBuffer,
|
||||
data: ArrayBuffer
|
||||
): Promise<boolean> {
|
||||
return EcCrypto.verify(
|
||||
algorithm,
|
||||
getCryptoKey(key) as EcPublicKey,
|
||||
new Uint8Array(signature),
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onVerify(algorithm: EcdsaParams, key: EcPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
|
||||
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, getCryptoKey(key));
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
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);
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||
super.checkCryptoKey(key, keyUsage);
|
||||
const internalKey = getCryptoKey(key);
|
||||
if (
|
||||
!(
|
||||
internalKey instanceof EcPrivateKey ||
|
||||
internalKey instanceof EcPublicKey
|
||||
)
|
||||
) {
|
||||
if (!(internalKey instanceof EcPrivateKey || internalKey instanceof EcPublicKey)) {
|
||||
throw new TypeError("key: Is not EC CryptoKey");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,42 +15,40 @@ const namedOIDs: { [key: string]: string } = {
|
|||
"K-256": "1.3.132.0.10",
|
||||
|
||||
// brainpool
|
||||
brainpoolP160r1: "1.3.36.3.3.2.8.1.1.1",
|
||||
"brainpoolP160r1": "1.3.36.3.3.2.8.1.1.1",
|
||||
"1.3.36.3.3.2.8.1.1.1": "brainpoolP160r1",
|
||||
brainpoolP160t1: "1.3.36.3.3.2.8.1.1.2",
|
||||
"brainpoolP160t1": "1.3.36.3.3.2.8.1.1.2",
|
||||
"1.3.36.3.3.2.8.1.1.2": "brainpoolP160t1",
|
||||
brainpoolP192r1: "1.3.36.3.3.2.8.1.1.3",
|
||||
"brainpoolP192r1": "1.3.36.3.3.2.8.1.1.3",
|
||||
"1.3.36.3.3.2.8.1.1.3": "brainpoolP192r1",
|
||||
brainpoolP192t1: "1.3.36.3.3.2.8.1.1.4",
|
||||
"brainpoolP192t1": "1.3.36.3.3.2.8.1.1.4",
|
||||
"1.3.36.3.3.2.8.1.1.4": "brainpoolP192t1",
|
||||
brainpoolP224r1: "1.3.36.3.3.2.8.1.1.5",
|
||||
"brainpoolP224r1": "1.3.36.3.3.2.8.1.1.5",
|
||||
"1.3.36.3.3.2.8.1.1.5": "brainpoolP224r1",
|
||||
brainpoolP224t1: "1.3.36.3.3.2.8.1.1.6",
|
||||
"brainpoolP224t1": "1.3.36.3.3.2.8.1.1.6",
|
||||
"1.3.36.3.3.2.8.1.1.6": "brainpoolP224t1",
|
||||
brainpoolP256r1: "1.3.36.3.3.2.8.1.1.7",
|
||||
"brainpoolP256r1": "1.3.36.3.3.2.8.1.1.7",
|
||||
"1.3.36.3.3.2.8.1.1.7": "brainpoolP256r1",
|
||||
brainpoolP256t1: "1.3.36.3.3.2.8.1.1.8",
|
||||
"brainpoolP256t1": "1.3.36.3.3.2.8.1.1.8",
|
||||
"1.3.36.3.3.2.8.1.1.8": "brainpoolP256t1",
|
||||
brainpoolP320r1: "1.3.36.3.3.2.8.1.1.9",
|
||||
"brainpoolP320r1": "1.3.36.3.3.2.8.1.1.9",
|
||||
"1.3.36.3.3.2.8.1.1.9": "brainpoolP320r1",
|
||||
brainpoolP320t1: "1.3.36.3.3.2.8.1.1.10",
|
||||
"brainpoolP320t1": "1.3.36.3.3.2.8.1.1.10",
|
||||
"1.3.36.3.3.2.8.1.1.10": "brainpoolP320t1",
|
||||
brainpoolP384r1: "1.3.36.3.3.2.8.1.1.11",
|
||||
"brainpoolP384r1": "1.3.36.3.3.2.8.1.1.11",
|
||||
"1.3.36.3.3.2.8.1.1.11": "brainpoolP384r1",
|
||||
brainpoolP384t1: "1.3.36.3.3.2.8.1.1.12",
|
||||
"brainpoolP384t1": "1.3.36.3.3.2.8.1.1.12",
|
||||
"1.3.36.3.3.2.8.1.1.12": "brainpoolP384t1",
|
||||
brainpoolP512r1: "1.3.36.3.3.2.8.1.1.13",
|
||||
"brainpoolP512r1": "1.3.36.3.3.2.8.1.1.13",
|
||||
"1.3.36.3.3.2.8.1.1.13": "brainpoolP512r1",
|
||||
brainpoolP512t1: "1.3.36.3.3.2.8.1.1.14",
|
||||
"brainpoolP512t1": "1.3.36.3.3.2.8.1.1.14",
|
||||
"1.3.36.3.3.2.8.1.1.14": "brainpoolP512t1",
|
||||
};
|
||||
|
||||
export function getNamedCurveByOid(oid: string) {
|
||||
const namedCurve = namedOIDs[oid];
|
||||
if (!namedCurve) {
|
||||
throw new core.OperationError(
|
||||
`Cannot convert OID(${oid}) to WebCrypto named curve`
|
||||
);
|
||||
throw new core.OperationError(`Cannot convert OID(${oid}) to WebCrypto named curve`);
|
||||
}
|
||||
return namedCurve;
|
||||
}
|
||||
|
@ -58,9 +56,7 @@ export function getNamedCurveByOid(oid: string) {
|
|||
export function getOidByNamedCurve(namedCurve: string) {
|
||||
const oid = namedOIDs[namedCurve];
|
||||
if (!oid) {
|
||||
throw new core.OperationError(
|
||||
`Cannot convert WebCrypto named curve '${namedCurve}' to OID`
|
||||
);
|
||||
throw new core.OperationError(`Cannot convert WebCrypto named curve '${namedCurve}' to OID`);
|
||||
}
|
||||
return oid;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
import { Buffer } from "buffer";
|
||||
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 { getOidByNamedCurve } from "./helper";
|
||||
import { AsymmetricKey } from "../../keys";
|
||||
|
@ -33,23 +28,20 @@ export class EcPrivateKey extends AsymmetricKey implements IJsonConvertible {
|
|||
|
||||
public fromJSON(json: JsonWebKey) {
|
||||
if (!json.crv) {
|
||||
throw new core.OperationError(
|
||||
`Cannot get named curve from JWK. Property 'crv' is required`
|
||||
);
|
||||
throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`);
|
||||
}
|
||||
|
||||
const keyInfo = new core.asn1.PrivateKeyInfo();
|
||||
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
|
||||
keyInfo.privateKeyAlgorithm.parameters = AsnSerializer.serialize(
|
||||
new core.asn1.ObjectIdentifier(getOidByNamedCurve(json.crv))
|
||||
new core.asn1.ObjectIdentifier(getOidByNamedCurve(json.crv)),
|
||||
);
|
||||
const key = JsonParser.fromJSON(json, {
|
||||
targetSchema: core.asn1.EcPrivateKey,
|
||||
});
|
||||
const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.EcPrivateKey });
|
||||
keyInfo.privateKey = AsnSerializer.serialize(key);
|
||||
|
||||
this.data = Buffer.from(AsnSerializer.serialize(keyInfo));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
import { Buffer } from "buffer";
|
||||
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 { getOidByNamedCurve } from "./helper";
|
||||
import { AsymmetricKey } from "../../keys/asymmetric";
|
||||
|
||||
export class EcPublicKey extends AsymmetricKey implements IJsonConvertible {
|
||||
|
||||
public readonly type = "public" as const;
|
||||
public override algorithm!: EcKeyAlgorithm;
|
||||
|
||||
|
@ -33,19 +29,15 @@ export class EcPublicKey extends AsymmetricKey implements IJsonConvertible {
|
|||
|
||||
public fromJSON(json: JsonWebKey) {
|
||||
if (!json.crv) {
|
||||
throw new core.OperationError(
|
||||
`Cannot get named curve from JWK. Property 'crv' is required`
|
||||
);
|
||||
throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`);
|
||||
}
|
||||
|
||||
const key = JsonParser.fromJSON(json, {
|
||||
targetSchema: core.asn1.EcPublicKey,
|
||||
});
|
||||
const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.EcPublicKey });
|
||||
|
||||
const keyInfo = new core.asn1.PublicKeyInfo();
|
||||
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.10045.2.1";
|
||||
keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize(
|
||||
new core.asn1.ObjectIdentifier(getOidByNamedCurve(json.crv))
|
||||
new core.asn1.ObjectIdentifier(getOidByNamedCurve(json.crv)),
|
||||
);
|
||||
keyInfo.publicKey = (AsnSerializer.toASN(key) as any).valueHex;
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Buffer } from "buffer";
|
||||
import crypto from "crypto";
|
||||
import { AsnParser } from "@peculiar/asn1-schema";
|
||||
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||
|
@ -9,27 +8,20 @@ import { EdPublicKey } from "./public_key";
|
|||
import { CryptoKey } from "../../keys";
|
||||
|
||||
export class EdCrypto {
|
||||
|
||||
public static publicKeyUsages = ["verify"];
|
||||
public static privateKeyUsages = ["sign", "deriveKey", "deriveBits"];
|
||||
|
||||
public static async generateKey(
|
||||
algorithm: EcKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKeyPair> {
|
||||
public static async generateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||
const privateKey = new EdPrivateKey();
|
||||
privateKey.algorithm = algorithm;
|
||||
privateKey.extractable = extractable;
|
||||
privateKey.usages = keyUsages.filter(
|
||||
(usage) => this.privateKeyUsages.indexOf(usage) !== -1
|
||||
);
|
||||
privateKey.usages = keyUsages.filter((usage) => this.privateKeyUsages.indexOf(usage) !== -1);
|
||||
|
||||
const publicKey = new EdPublicKey();
|
||||
publicKey.algorithm = algorithm;
|
||||
publicKey.extractable = true;
|
||||
publicKey.usages = keyUsages.filter(
|
||||
(usage) => this.publicKeyUsages.indexOf(usage) !== -1
|
||||
);
|
||||
publicKey.usages = keyUsages.filter((usage) => this.publicKeyUsages.indexOf(usage) !== -1);
|
||||
|
||||
const type = algorithm.namedCurve.toLowerCase() as "x448"; // "x448" | "ed448" | "x25519" | "ed25519"
|
||||
const keys = crypto.generateKeyPairSync(type, {
|
||||
|
@ -54,15 +46,9 @@ export class EdCrypto {
|
|||
return res;
|
||||
}
|
||||
|
||||
public static async sign(
|
||||
algorithm: Algorithm,
|
||||
key: EdPrivateKey,
|
||||
data: Uint8Array
|
||||
): Promise<ArrayBuffer> {
|
||||
public static async sign(algorithm: Algorithm, key: EdPrivateKey, data: Uint8Array): Promise<ArrayBuffer> {
|
||||
if (!key.pem) {
|
||||
key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString(
|
||||
"base64"
|
||||
)}\n-----END PRIVATE KEY-----`;
|
||||
key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`;
|
||||
}
|
||||
const options = {
|
||||
key: key.pem,
|
||||
|
@ -72,34 +58,18 @@ export class EdCrypto {
|
|||
return core.BufferSourceConverter.toArrayBuffer(signature);
|
||||
}
|
||||
|
||||
public static async verify(
|
||||
algorithm: EcdsaParams,
|
||||
key: EdPublicKey,
|
||||
signature: Uint8Array,
|
||||
data: Uint8Array
|
||||
): Promise<boolean> {
|
||||
public static async verify(algorithm: EcdsaParams, key: EdPublicKey, signature: Uint8Array, data: Uint8Array): Promise<boolean> {
|
||||
if (!key.pem) {
|
||||
key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString(
|
||||
"base64"
|
||||
)}\n-----END PUBLIC KEY-----`;
|
||||
key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`;
|
||||
}
|
||||
const options = {
|
||||
key: key.pem,
|
||||
};
|
||||
const ok = crypto.verify(
|
||||
null,
|
||||
Buffer.from(data),
|
||||
options,
|
||||
Buffer.from(signature)
|
||||
);
|
||||
const ok = crypto.verify(null, Buffer.from(data), options, Buffer.from(signature));
|
||||
return ok;
|
||||
}
|
||||
|
||||
public static async deriveBits(
|
||||
algorithm: EcdhKeyDeriveParams,
|
||||
baseKey: CryptoKey,
|
||||
length: number
|
||||
): Promise<ArrayBuffer> {
|
||||
public static async deriveBits(algorithm: EcdhKeyDeriveParams, baseKey: CryptoKey, length: number): Promise<ArrayBuffer> {
|
||||
const publicKey = crypto.createPublicKey({
|
||||
key: (algorithm.public as CryptoKey).data,
|
||||
format: "der",
|
||||
|
@ -118,10 +88,7 @@ export class EdCrypto {
|
|||
return new Uint8Array(bits).buffer.slice(0, length >> 3);
|
||||
}
|
||||
|
||||
public static async exportKey(
|
||||
format: KeyFormat,
|
||||
key: CryptoKey
|
||||
): Promise<JsonWebKey | ArrayBuffer> {
|
||||
public static async exportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||
switch (format.toLowerCase()) {
|
||||
case "jwk":
|
||||
return JsonSerializer.toJSON(key);
|
||||
|
@ -129,95 +96,46 @@ export class EdCrypto {
|
|||
case "spki":
|
||||
return new Uint8Array(key.data).buffer;
|
||||
case "raw": {
|
||||
const publicKeyInfo = AsnParser.parse(
|
||||
key.data,
|
||||
core.asn1.PublicKeyInfo
|
||||
);
|
||||
const publicKeyInfo = AsnParser.parse(key.data, core.asn1.PublicKeyInfo);
|
||||
return publicKeyInfo.publicKey;
|
||||
}
|
||||
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'");
|
||||
}
|
||||
}
|
||||
|
||||
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()) {
|
||||
case "jwk": {
|
||||
const jwk = keyData as JsonWebKey;
|
||||
if (jwk.d) {
|
||||
const asnKey = JsonParser.fromJSON(keyData, {
|
||||
targetSchema: core.asn1.CurvePrivateKey,
|
||||
});
|
||||
return this.importPrivateKey(
|
||||
asnKey,
|
||||
algorithm,
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.CurvePrivateKey });
|
||||
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
|
||||
} else {
|
||||
if (!jwk.x) {
|
||||
throw new TypeError("keyData: Cannot get required 'x' filed");
|
||||
}
|
||||
return this.importPublicKey(
|
||||
Convert.FromBase64Url(jwk.x),
|
||||
algorithm,
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
return this.importPublicKey(Convert.FromBase64Url(jwk.x), algorithm, extractable, keyUsages);
|
||||
}
|
||||
}
|
||||
case "raw": {
|
||||
return this.importPublicKey(
|
||||
keyData as ArrayBuffer,
|
||||
algorithm,
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
return this.importPublicKey(keyData as ArrayBuffer, algorithm, extractable, keyUsages);
|
||||
}
|
||||
case "spki": {
|
||||
const keyInfo = AsnParser.parse(
|
||||
new Uint8Array(keyData as ArrayBuffer),
|
||||
core.asn1.PublicKeyInfo
|
||||
);
|
||||
return this.importPublicKey(
|
||||
keyInfo.publicKey,
|
||||
algorithm,
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PublicKeyInfo);
|
||||
return this.importPublicKey(keyInfo.publicKey, algorithm, extractable, keyUsages);
|
||||
}
|
||||
case "pkcs8": {
|
||||
const keyInfo = AsnParser.parse(
|
||||
new Uint8Array(keyData as ArrayBuffer),
|
||||
core.asn1.PrivateKeyInfo
|
||||
);
|
||||
const asnKey = AsnParser.parse(
|
||||
keyInfo.privateKey,
|
||||
core.asn1.CurvePrivateKey
|
||||
);
|
||||
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PrivateKeyInfo);
|
||||
const asnKey = AsnParser.parse(keyInfo.privateKey, core.asn1.CurvePrivateKey);
|
||||
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
|
||||
}
|
||||
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'");
|
||||
}
|
||||
}
|
||||
|
||||
protected static importPrivateKey(
|
||||
asnKey: core.asn1.CurvePrivateKey,
|
||||
algorithm: EcKeyImportParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
) {
|
||||
protected static importPrivateKey(asnKey: core.asn1.CurvePrivateKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
|
||||
const key = new EdPrivateKey();
|
||||
key.fromJSON({
|
||||
crv: algorithm.namedCurve,
|
||||
|
@ -231,12 +149,7 @@ export class EdCrypto {
|
|||
return key;
|
||||
}
|
||||
|
||||
protected static async importPublicKey(
|
||||
asnKey: ArrayBuffer,
|
||||
algorithm: EcKeyImportParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
) {
|
||||
protected static async importPublicKey(asnKey: ArrayBuffer, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
|
||||
const key = new EdPublicKey();
|
||||
key.fromJSON({
|
||||
crv: algorithm.namedCurve,
|
||||
|
@ -249,4 +162,5 @@ export class EdCrypto {
|
|||
|
||||
return key;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,19 +4,15 @@ import { CryptoKey } from "../../keys";
|
|||
import { getCryptoKey, setCryptoKey } from "../storage";
|
||||
|
||||
export class EcdhEsProvider extends core.EcdhEsProvider {
|
||||
public async onGenerateKey(
|
||||
algorithm: EcKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKeyPair> {
|
||||
|
||||
public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||
const keys = await EdCrypto.generateKey(
|
||||
{
|
||||
name: this.name,
|
||||
namedCurve: algorithm.namedCurve.toUpperCase(),
|
||||
},
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
keyUsages);
|
||||
|
||||
return {
|
||||
privateKey: setCryptoKey(keys.privateKey as CryptoKey),
|
||||
|
@ -24,40 +20,18 @@ export class EcdhEsProvider extends core.EcdhEsProvider {
|
|||
};
|
||||
}
|
||||
|
||||
public async onDeriveBits(
|
||||
algorithm: EcdhKeyDeriveParams,
|
||||
baseKey: core.CryptoKey,
|
||||
length: number
|
||||
): Promise<ArrayBuffer> {
|
||||
const bits = await EdCrypto.deriveBits(
|
||||
{ ...algorithm, public: getCryptoKey(algorithm.public) },
|
||||
getCryptoKey(baseKey),
|
||||
length
|
||||
);
|
||||
public async onDeriveBits(algorithm: EcdhKeyDeriveParams, baseKey: core.CryptoKey, length: number): Promise<ArrayBuffer> {
|
||||
const bits = await EdCrypto.deriveBits({...algorithm, public: getCryptoKey(algorithm.public)}, getCryptoKey(baseKey), length);
|
||||
return bits;
|
||||
}
|
||||
|
||||
public async onExportKey(
|
||||
format: KeyFormat,
|
||||
key: CryptoKey
|
||||
): Promise<ArrayBuffer | JsonWebKey> {
|
||||
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<ArrayBuffer | JsonWebKey> {
|
||||
return EdCrypto.exportKey(format, getCryptoKey(key));
|
||||
}
|
||||
|
||||
public async onImportKey(
|
||||
format: KeyFormat,
|
||||
keyData: ArrayBuffer | JsonWebKey,
|
||||
algorithm: EcKeyImportParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<core.CryptoKey> {
|
||||
const key = await EdCrypto.importKey(
|
||||
format,
|
||||
keyData,
|
||||
{ ...algorithm, name: this.name },
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
public async onImportKey(format: KeyFormat, keyData: ArrayBuffer | JsonWebKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
|
||||
const key = await EdCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages);
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
}
|
|
@ -6,19 +6,15 @@ import { CryptoKey } from "../../keys";
|
|||
import { getCryptoKey, setCryptoKey } from "../storage";
|
||||
|
||||
export class EdDsaProvider extends core.EdDsaProvider {
|
||||
public async onGenerateKey(
|
||||
algorithm: EcKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKeyPair> {
|
||||
|
||||
public async onGenerateKey(algorithm: EcKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||
const keys = await EdCrypto.generateKey(
|
||||
{
|
||||
name: this.name,
|
||||
namedCurve: algorithm.namedCurve.replace(/^ed/i, "Ed"),
|
||||
},
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
keyUsages);
|
||||
|
||||
return {
|
||||
privateKey: setCryptoKey(keys.privateKey as CryptoKey),
|
||||
|
@ -26,53 +22,21 @@ export class EdDsaProvider extends core.EdDsaProvider {
|
|||
};
|
||||
}
|
||||
|
||||
public async onSign(
|
||||
algorithm: EcdsaParams,
|
||||
key: CryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return EdCrypto.sign(
|
||||
algorithm,
|
||||
getCryptoKey(key) as EdPrivateKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onSign(algorithm: EcdsaParams, key: CryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return EdCrypto.sign(algorithm, getCryptoKey(key) as EdPrivateKey, new Uint8Array(data));
|
||||
}
|
||||
|
||||
public async onVerify(
|
||||
algorithm: EcdsaParams,
|
||||
key: CryptoKey,
|
||||
signature: ArrayBuffer,
|
||||
data: ArrayBuffer
|
||||
): Promise<boolean> {
|
||||
return EdCrypto.verify(
|
||||
algorithm,
|
||||
getCryptoKey(key) as EdPublicKey,
|
||||
new Uint8Array(signature),
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onVerify(algorithm: EcdsaParams, key: CryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
|
||||
return EdCrypto.verify(algorithm, getCryptoKey(key) as EdPublicKey, new Uint8Array(signature), new Uint8Array(data));
|
||||
}
|
||||
|
||||
public async onExportKey(
|
||||
format: KeyFormat,
|
||||
key: CryptoKey
|
||||
): Promise<ArrayBuffer | JsonWebKey> {
|
||||
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<ArrayBuffer | JsonWebKey> {
|
||||
return EdCrypto.exportKey(format, getCryptoKey(key));
|
||||
}
|
||||
|
||||
public async onImportKey(
|
||||
format: KeyFormat,
|
||||
keyData: ArrayBuffer | JsonWebKey,
|
||||
algorithm: EcKeyImportParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<core.CryptoKey> {
|
||||
const key = await EdCrypto.importKey(
|
||||
format,
|
||||
keyData,
|
||||
{ ...algorithm, name: this.name },
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
public async onImportKey(format: KeyFormat, keyData: ArrayBuffer | JsonWebKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<core.CryptoKey> {
|
||||
const key = await EdCrypto.importKey(format, keyData, { ...algorithm, name: this.name }, extractable, keyUsages);
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,24 +3,22 @@ import * as core from "webcrypto-core";
|
|||
const edOIDs: { [key: string]: string } = {
|
||||
// Ed448
|
||||
[core.asn1.idEd448]: "Ed448",
|
||||
ed448: core.asn1.idEd448,
|
||||
"ed448": core.asn1.idEd448,
|
||||
// X448
|
||||
[core.asn1.idX448]: "X448",
|
||||
x448: core.asn1.idX448,
|
||||
"x448": core.asn1.idX448,
|
||||
// Ed25519
|
||||
[core.asn1.idEd25519]: "Ed25519",
|
||||
ed25519: core.asn1.idEd25519,
|
||||
"ed25519": core.asn1.idEd25519,
|
||||
// X25519
|
||||
[core.asn1.idX25519]: "X25519",
|
||||
x25519: core.asn1.idX25519,
|
||||
"x25519": core.asn1.idX25519,
|
||||
};
|
||||
|
||||
export function getNamedCurveByOid(oid: string) {
|
||||
const namedCurve = edOIDs[oid];
|
||||
if (!namedCurve) {
|
||||
throw new core.OperationError(
|
||||
`Cannot convert OID(${oid}) to WebCrypto named curve`
|
||||
);
|
||||
throw new core.OperationError(`Cannot convert OID(${oid}) to WebCrypto named curve`);
|
||||
}
|
||||
return namedCurve;
|
||||
}
|
||||
|
@ -28,9 +26,7 @@ export function getNamedCurveByOid(oid: string) {
|
|||
export function getOidByNamedCurve(namedCurve: string) {
|
||||
const oid = edOIDs[namedCurve.toLowerCase()];
|
||||
if (!oid) {
|
||||
throw new core.OperationError(
|
||||
`Cannot convert WebCrypto named curve '${namedCurve}' to OID`
|
||||
);
|
||||
throw new core.OperationError(`Cannot convert WebCrypto named curve '${namedCurve}' to OID`);
|
||||
}
|
||||
return oid;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
import { Buffer } from "buffer";
|
||||
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 { getOidByNamedCurve } from "./helper";
|
||||
import { AsymmetricKey } from "../../keys";
|
||||
|
@ -33,20 +28,17 @@ export class EdPrivateKey extends AsymmetricKey implements IJsonConvertible {
|
|||
|
||||
public fromJSON(json: JsonWebKey) {
|
||||
if (!json.crv) {
|
||||
throw new core.OperationError(
|
||||
`Cannot get named curve from JWK. Property 'crv' is required`
|
||||
);
|
||||
throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`);
|
||||
}
|
||||
|
||||
const keyInfo = new core.asn1.PrivateKeyInfo();
|
||||
keyInfo.privateKeyAlgorithm.algorithm = getOidByNamedCurve(json.crv);
|
||||
const key = JsonParser.fromJSON(json, {
|
||||
targetSchema: core.asn1.CurvePrivateKey,
|
||||
});
|
||||
const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.CurvePrivateKey });
|
||||
keyInfo.privateKey = AsnSerializer.serialize(key);
|
||||
|
||||
this.data = Buffer.from(AsnSerializer.serialize(keyInfo));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Buffer } from "buffer";
|
||||
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
|
||||
import { IJsonConvertible } from "@peculiar/json-schema";
|
||||
import { Convert } from "pvtsutils";
|
||||
|
@ -7,6 +6,7 @@ import { getOidByNamedCurve } from "./helper";
|
|||
import { AsymmetricKey } from "../../keys/asymmetric";
|
||||
|
||||
export class EdPublicKey extends AsymmetricKey implements IJsonConvertible {
|
||||
|
||||
public readonly type = "public" as const;
|
||||
public override algorithm!: EcKeyAlgorithm;
|
||||
|
||||
|
@ -26,20 +26,16 @@ export class EdPublicKey extends AsymmetricKey implements IJsonConvertible {
|
|||
};
|
||||
|
||||
return Object.assign(json, {
|
||||
x: Convert.ToBase64Url(key),
|
||||
x: Convert.ToBase64Url(key)
|
||||
});
|
||||
}
|
||||
|
||||
public fromJSON(json: JsonWebKey) {
|
||||
if (!json.crv) {
|
||||
throw new core.OperationError(
|
||||
`Cannot get named curve from JWK. Property 'crv' is required`
|
||||
);
|
||||
throw new core.OperationError(`Cannot get named curve from JWK. Property 'crv' is required`);
|
||||
}
|
||||
if (!json.x) {
|
||||
throw new core.OperationError(
|
||||
`Cannot get property from JWK. Property 'x' is required`
|
||||
);
|
||||
throw new core.OperationError(`Cannot get property from JWK. Property 'x' is required`);
|
||||
}
|
||||
|
||||
const keyInfo = new core.asn1.PublicKeyInfo();
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Buffer } from "buffer";
|
||||
import crypto from "crypto";
|
||||
import * as core from "webcrypto-core";
|
||||
import { BufferSourceConverter, CryptoKey } from "webcrypto-core";
|
||||
|
@ -6,15 +5,10 @@ import { HkdfCryptoKey } from "./key";
|
|||
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||
|
||||
export class HkdfProvider extends core.HkdfProvider {
|
||||
public async onImportKey(
|
||||
format: KeyFormat,
|
||||
keyData: ArrayBuffer,
|
||||
algorithm: HmacImportParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKey> {
|
||||
|
||||
public async onImportKey(format: KeyFormat, keyData: ArrayBuffer, algorithm: HmacImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
if (format.toLowerCase() !== "raw") {
|
||||
throw new core.OperationError("Operation not supported");
|
||||
throw new core.OperationError("Operation not supported");
|
||||
}
|
||||
|
||||
const key: HkdfCryptoKey = new HkdfCryptoKey();
|
||||
|
@ -25,30 +19,24 @@ export class HkdfProvider extends core.HkdfProvider {
|
|||
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> {
|
||||
const hash = (params.hash as Algorithm).name.replace("-", "");
|
||||
const hashLength = crypto.createHash(hash).digest().length;
|
||||
|
||||
const byteLength = length / 8;
|
||||
const info = BufferSourceConverter.toUint8Array(params.info);
|
||||
|
||||
const PRK = crypto
|
||||
.createHmac(hash, BufferSourceConverter.toUint8Array(params.salt))
|
||||
.update(BufferSourceConverter.toUint8Array(getCryptoKey(baseKey).data))
|
||||
.digest();
|
||||
const PRK = crypto.createHmac(hash, BufferSourceConverter.toUint8Array(params.salt))
|
||||
.update(BufferSourceConverter.toUint8Array(getCryptoKey(baseKey).data))
|
||||
.digest();
|
||||
|
||||
const blocks = [Buffer.alloc(0)];
|
||||
const blockCount = Math.ceil(byteLength / hashLength) + 1; // Includes empty buffer
|
||||
for (let i = 1; i < blockCount; ++i) {
|
||||
blocks.push(
|
||||
crypto
|
||||
.createHmac(hash, PRK)
|
||||
.update(Buffer.concat([blocks[i - 1], info, Buffer.from([i])]))
|
||||
.digest()
|
||||
crypto.createHmac(hash, PRK)
|
||||
.update(Buffer.concat([blocks[i - 1], info, Buffer.from([i])]))
|
||||
.digest(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -61,4 +49,5 @@ export class HkdfProvider extends core.HkdfProvider {
|
|||
throw new TypeError("key: Is not HKDF CryptoKey");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { CryptoKey } from "../../keys";
|
||||
|
||||
export class HkdfCryptoKey extends CryptoKey {
|
||||
|
||||
public override data!: Buffer;
|
||||
|
||||
public override algorithm!: KeyAlgorithm;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Buffer } from "buffer";
|
||||
import crypto from "crypto";
|
||||
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||
import * as core from "webcrypto-core";
|
||||
|
@ -7,19 +6,12 @@ import { ShaCrypto } from "../sha";
|
|||
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||
|
||||
export class HmacProvider extends core.HmacProvider {
|
||||
public async onGenerateKey(
|
||||
algorithm: HmacKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKey> {
|
||||
const length =
|
||||
((algorithm.length ||
|
||||
this.getDefaultLength((algorithm.hash as Algorithm).name)) >>
|
||||
3) <<
|
||||
3;
|
||||
|
||||
public async onGenerateKey(algorithm: HmacKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
const length = (algorithm.length || this.getDefaultLength((algorithm.hash as Algorithm).name)) >> 3 << 3;
|
||||
const key = new HmacCryptoKey();
|
||||
key.algorithm = {
|
||||
...(algorithm as any),
|
||||
...algorithm as any,
|
||||
length,
|
||||
name: this.name,
|
||||
};
|
||||
|
@ -30,42 +22,23 @@ export class HmacProvider extends core.HmacProvider {
|
|||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
public override async onSign(
|
||||
algorithm: Algorithm,
|
||||
key: HmacCryptoKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
public override async onSign(algorithm: Algorithm, key: HmacCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
const cryptoAlg = ShaCrypto.getAlgorithmName(key.algorithm.hash);
|
||||
const hmac = crypto
|
||||
.createHmac(cryptoAlg, getCryptoKey(key).data)
|
||||
.update(Buffer.from(data))
|
||||
.digest();
|
||||
const hmac = crypto.createHmac(cryptoAlg, getCryptoKey(key).data)
|
||||
.update(Buffer.from(data)).digest();
|
||||
|
||||
return new Uint8Array(hmac).buffer;
|
||||
}
|
||||
|
||||
public override async onVerify(
|
||||
algorithm: Algorithm,
|
||||
key: HmacCryptoKey,
|
||||
signature: ArrayBuffer,
|
||||
data: ArrayBuffer
|
||||
): Promise<boolean> {
|
||||
public override async onVerify(algorithm: Algorithm, key: HmacCryptoKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
|
||||
const cryptoAlg = ShaCrypto.getAlgorithmName(key.algorithm.hash);
|
||||
const hmac = crypto
|
||||
.createHmac(cryptoAlg, getCryptoKey(key).data)
|
||||
.update(Buffer.from(data))
|
||||
.digest();
|
||||
const hmac = crypto.createHmac(cryptoAlg, getCryptoKey(key).data)
|
||||
.update(Buffer.from(data)).digest();
|
||||
|
||||
return hmac.compare(Buffer.from(signature)) === 0;
|
||||
}
|
||||
|
||||
public async onImportKey(
|
||||
format: KeyFormat,
|
||||
keyData: JsonWebKey | ArrayBuffer,
|
||||
algorithm: HmacImportParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKey> {
|
||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: HmacImportParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
let key: HmacCryptoKey;
|
||||
|
||||
switch (format.toLowerCase()) {
|
||||
|
@ -91,10 +64,7 @@ export class HmacProvider extends core.HmacProvider {
|
|||
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()) {
|
||||
case "jwk":
|
||||
return JsonSerializer.toJSON(getCryptoKey(key));
|
||||
|
@ -111,4 +81,5 @@ export class HmacProvider extends core.HmacProvider {
|
|||
throw new TypeError("key: Is not HMAC CryptoKey");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { JsonBase64UrlConverter } from "../../converters";
|
|||
import { CryptoKey } from "../../keys";
|
||||
|
||||
export class HmacCryptoKey extends CryptoKey {
|
||||
|
||||
@JsonProp({ name: "k", converter: JsonBase64UrlConverter })
|
||||
public override data!: Buffer;
|
||||
|
||||
|
@ -18,4 +19,5 @@ export class HmacCryptoKey extends CryptoKey {
|
|||
protected override set alg(value: string) {
|
||||
// nothing, cause set is needed for json-schema, but is not used by module
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { CryptoKey } from "../../keys";
|
||||
|
||||
export class PbkdfCryptoKey extends CryptoKey {}
|
||||
export class PbkdfCryptoKey extends CryptoKey {
|
||||
}
|
||||
|
|
|
@ -1,42 +1,25 @@
|
|||
import { Buffer } from "buffer";
|
||||
import crypto from "crypto";
|
||||
import * as core from "webcrypto-core";
|
||||
import { PbkdfCryptoKey } from "./key";
|
||||
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||
|
||||
export class Pbkdf2Provider extends core.Pbkdf2Provider {
|
||||
public async onDeriveBits(
|
||||
algorithm: Pbkdf2Params,
|
||||
baseKey: PbkdfCryptoKey,
|
||||
length: number
|
||||
): Promise<ArrayBuffer> {
|
||||
|
||||
public async onDeriveBits(algorithm: Pbkdf2Params, baseKey: PbkdfCryptoKey, length: number): Promise<ArrayBuffer> {
|
||||
return new Promise<ArrayBuffer>((resolve, reject) => {
|
||||
const salt = core.BufferSourceConverter.toArrayBuffer(algorithm.salt);
|
||||
const hash = (algorithm.hash as Algorithm).name.replace("-", "");
|
||||
crypto.pbkdf2(
|
||||
getCryptoKey(baseKey).data,
|
||||
Buffer.from(salt),
|
||||
algorithm.iterations,
|
||||
length >> 3,
|
||||
hash,
|
||||
(err, derivedBits) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(new Uint8Array(derivedBits).buffer);
|
||||
}
|
||||
crypto.pbkdf2(getCryptoKey(baseKey).data, Buffer.from(salt), algorithm.iterations, length >> 3, hash, (err, derivedBits) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(new Uint8Array(derivedBits).buffer);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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> {
|
||||
if (format === "raw") {
|
||||
const key = new PbkdfCryptoKey();
|
||||
key.data = Buffer.from(keyData as ArrayBuffer);
|
||||
|
@ -54,4 +37,5 @@ export class Pbkdf2Provider extends core.Pbkdf2Provider {
|
|||
throw new TypeError("key: Is not PBKDF CryptoKey");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Buffer } from "buffer";
|
||||
import crypto from "crypto";
|
||||
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
|
||||
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||
|
@ -15,27 +14,20 @@ interface INodeCryptoSignOptions {
|
|||
}
|
||||
|
||||
export class RsaCrypto {
|
||||
|
||||
public static publicKeyUsages = ["verify", "encrypt", "wrapKey"];
|
||||
public static privateKeyUsages = ["sign", "decrypt", "unwrapKey"];
|
||||
|
||||
public static async generateKey(
|
||||
algorithm: RsaHashedKeyGenParams | RsaKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: string[]
|
||||
): Promise<CryptoKeyPair> {
|
||||
public static async generateKey(algorithm: RsaHashedKeyGenParams | RsaKeyGenParams, extractable: boolean, keyUsages: string[]): Promise<CryptoKeyPair> {
|
||||
const privateKey = new RsaPrivateKey();
|
||||
privateKey.algorithm = algorithm as RsaHashedKeyAlgorithm;
|
||||
privateKey.extractable = extractable;
|
||||
privateKey.usages = keyUsages.filter(
|
||||
(usage) => this.privateKeyUsages.indexOf(usage) !== -1
|
||||
) as KeyUsage[];
|
||||
privateKey.usages = keyUsages.filter((usage) => this.privateKeyUsages.indexOf(usage) !== -1) as KeyUsage[];
|
||||
|
||||
const publicKey = new RsaPublicKey();
|
||||
publicKey.algorithm = algorithm as RsaHashedKeyAlgorithm;
|
||||
publicKey.extractable = true;
|
||||
publicKey.usages = keyUsages.filter(
|
||||
(usage) => this.publicKeyUsages.indexOf(usage) !== -1
|
||||
) as KeyUsage[];
|
||||
publicKey.usages = keyUsages.filter((usage) => this.publicKeyUsages.indexOf(usage) !== -1) as KeyUsage[];
|
||||
|
||||
const publicExponent = Buffer.concat([
|
||||
Buffer.alloc(4 - algorithm.publicExponent.byteLength, 0),
|
||||
|
@ -66,10 +58,7 @@ export class RsaCrypto {
|
|||
return res;
|
||||
}
|
||||
|
||||
public static async exportKey(
|
||||
format: KeyFormat,
|
||||
key: CryptoKey
|
||||
): Promise<JsonWebKey | ArrayBuffer> {
|
||||
public static async exportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||
switch (format.toLowerCase()) {
|
||||
case "jwk":
|
||||
return JsonSerializer.toJSON(key);
|
||||
|
@ -77,78 +66,38 @@ export class RsaCrypto {
|
|||
case "spki":
|
||||
return new Uint8Array(key.data).buffer;
|
||||
default:
|
||||
throw new core.OperationError(
|
||||
"format: Must be 'jwk', 'pkcs8' or 'spki'"
|
||||
);
|
||||
throw new core.OperationError("format: Must be 'jwk', 'pkcs8' or 'spki'");
|
||||
}
|
||||
}
|
||||
|
||||
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()) {
|
||||
case "jwk": {
|
||||
const jwk = keyData as JsonWebKey;
|
||||
if (jwk.d) {
|
||||
const asnKey = JsonParser.fromJSON(keyData, {
|
||||
targetSchema: core.asn1.RsaPrivateKey,
|
||||
});
|
||||
return this.importPrivateKey(
|
||||
asnKey,
|
||||
algorithm,
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.RsaPrivateKey });
|
||||
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
|
||||
} else {
|
||||
const asnKey = JsonParser.fromJSON(keyData, {
|
||||
targetSchema: core.asn1.RsaPublicKey,
|
||||
});
|
||||
return this.importPublicKey(
|
||||
asnKey,
|
||||
algorithm,
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
const asnKey = JsonParser.fromJSON(keyData, { targetSchema: core.asn1.RsaPublicKey });
|
||||
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
|
||||
}
|
||||
}
|
||||
case "spki": {
|
||||
const keyInfo = AsnParser.parse(
|
||||
new Uint8Array(keyData as ArrayBuffer),
|
||||
core.asn1.PublicKeyInfo
|
||||
);
|
||||
const asnKey = AsnParser.parse(
|
||||
keyInfo.publicKey,
|
||||
core.asn1.RsaPublicKey
|
||||
);
|
||||
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PublicKeyInfo);
|
||||
const asnKey = AsnParser.parse(keyInfo.publicKey, core.asn1.RsaPublicKey);
|
||||
return this.importPublicKey(asnKey, algorithm, extractable, keyUsages);
|
||||
}
|
||||
case "pkcs8": {
|
||||
const keyInfo = AsnParser.parse(
|
||||
new Uint8Array(keyData as ArrayBuffer),
|
||||
core.asn1.PrivateKeyInfo
|
||||
);
|
||||
const asnKey = AsnParser.parse(
|
||||
keyInfo.privateKey,
|
||||
core.asn1.RsaPrivateKey
|
||||
);
|
||||
const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PrivateKeyInfo);
|
||||
const asnKey = AsnParser.parse(keyInfo.privateKey, core.asn1.RsaPrivateKey);
|
||||
return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages);
|
||||
}
|
||||
default:
|
||||
throw new core.OperationError(
|
||||
"format: Must be 'jwk', 'pkcs8' or 'spki'"
|
||||
);
|
||||
throw new core.OperationError("format: Must be 'jwk', 'pkcs8' or 'spki'");
|
||||
}
|
||||
}
|
||||
|
||||
public static async sign(
|
||||
algorithm: Algorithm,
|
||||
key: RsaPrivateKey,
|
||||
data: Uint8Array
|
||||
): Promise<ArrayBuffer> {
|
||||
public static async sign(algorithm: Algorithm, key: RsaPrivateKey, data: Uint8Array): Promise<ArrayBuffer> {
|
||||
switch (algorithm.name.toUpperCase()) {
|
||||
case "RSA-PSS":
|
||||
case "RSASSA-PKCS1-V1_5":
|
||||
|
@ -158,12 +107,7 @@ export class RsaCrypto {
|
|||
}
|
||||
}
|
||||
|
||||
public static async verify(
|
||||
algorithm: Algorithm,
|
||||
key: RsaPublicKey,
|
||||
signature: Uint8Array,
|
||||
data: Uint8Array
|
||||
): Promise<boolean> {
|
||||
public static async verify(algorithm: Algorithm, key: RsaPublicKey, signature: Uint8Array, data: Uint8Array): Promise<boolean> {
|
||||
switch (algorithm.name.toUpperCase()) {
|
||||
case "RSA-PSS":
|
||||
case "RSASSA-PKCS1-V1_5":
|
||||
|
@ -173,11 +117,7 @@ export class RsaCrypto {
|
|||
}
|
||||
}
|
||||
|
||||
public static async encrypt(
|
||||
algorithm: RsaOaepParams,
|
||||
key: RsaPublicKey,
|
||||
data: Uint8Array
|
||||
): Promise<ArrayBuffer> {
|
||||
public static async encrypt(algorithm: RsaOaepParams, key: RsaPublicKey, data: Uint8Array): Promise<ArrayBuffer> {
|
||||
switch (algorithm.name.toUpperCase()) {
|
||||
case "RSA-OAEP":
|
||||
return this.encryptOAEP(algorithm, key, data);
|
||||
|
@ -186,11 +126,7 @@ export class RsaCrypto {
|
|||
}
|
||||
}
|
||||
|
||||
public static async decrypt(
|
||||
algorithm: RsaOaepParams,
|
||||
key: RsaPrivateKey,
|
||||
data: Uint8Array
|
||||
): Promise<ArrayBuffer> {
|
||||
public static async decrypt(algorithm: RsaOaepParams, key: RsaPrivateKey, data: Uint8Array): Promise<ArrayBuffer> {
|
||||
switch (algorithm.name.toUpperCase()) {
|
||||
case "RSA-OAEP":
|
||||
return this.decryptOAEP(algorithm, key, data);
|
||||
|
@ -199,12 +135,7 @@ export class RsaCrypto {
|
|||
}
|
||||
}
|
||||
|
||||
protected static importPrivateKey(
|
||||
asnKey: core.asn1.RsaPrivateKey,
|
||||
algorithm: RsaHashedImportParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
) {
|
||||
protected static importPrivateKey(asnKey: core.asn1.RsaPrivateKey, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
|
||||
const keyInfo = new core.asn1.PrivateKeyInfo();
|
||||
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";
|
||||
keyInfo.privateKeyAlgorithm.parameters = null;
|
||||
|
@ -222,12 +153,7 @@ export class RsaCrypto {
|
|||
return key;
|
||||
}
|
||||
|
||||
protected static importPublicKey(
|
||||
asnKey: core.asn1.RsaPublicKey,
|
||||
algorithm: RsaHashedImportParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
) {
|
||||
protected static importPublicKey(asnKey: core.asn1.RsaPublicKey, algorithm: RsaHashedImportParams, extractable: boolean, keyUsages: KeyUsage[]) {
|
||||
const keyInfo = new core.asn1.PublicKeyInfo();
|
||||
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";
|
||||
keyInfo.publicKeyAlgorithm.parameters = null;
|
||||
|
@ -266,19 +192,13 @@ export class RsaCrypto {
|
|||
}
|
||||
}
|
||||
|
||||
protected static signRsa(
|
||||
algorithm: Algorithm,
|
||||
key: RsaPrivateKey,
|
||||
data: Uint8Array
|
||||
) {
|
||||
protected static signRsa(algorithm: Algorithm, key: RsaPrivateKey, data: Uint8Array) {
|
||||
const cryptoAlg = this.getCryptoAlgorithm(key.algorithm);
|
||||
const signer = crypto.createSign(cryptoAlg);
|
||||
signer.update(Buffer.from(data));
|
||||
|
||||
if (!key.pem) {
|
||||
key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString(
|
||||
"base64"
|
||||
)}\n-----END PRIVATE KEY-----`;
|
||||
key.pem = `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`;
|
||||
}
|
||||
const options: INodeCryptoSignOptions = {
|
||||
key: key.pem,
|
||||
|
@ -292,20 +212,13 @@ export class RsaCrypto {
|
|||
return new Uint8Array(signature).buffer;
|
||||
}
|
||||
|
||||
protected static verifySSA(
|
||||
algorithm: Algorithm,
|
||||
key: RsaPublicKey,
|
||||
data: Uint8Array,
|
||||
signature: Uint8Array
|
||||
) {
|
||||
protected static verifySSA(algorithm: Algorithm, key: RsaPublicKey, data: Uint8Array, signature: Uint8Array) {
|
||||
const cryptoAlg = this.getCryptoAlgorithm(key.algorithm);
|
||||
const signer = crypto.createVerify(cryptoAlg);
|
||||
signer.update(Buffer.from(data));
|
||||
|
||||
if (!key.pem) {
|
||||
key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString(
|
||||
"base64"
|
||||
)}\n-----END PUBLIC KEY-----`;
|
||||
key.pem = `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`;
|
||||
}
|
||||
const options: INodeCryptoSignOptions = {
|
||||
key: key.pem,
|
||||
|
@ -319,15 +232,9 @@ export class RsaCrypto {
|
|||
return ok;
|
||||
}
|
||||
|
||||
protected static encryptOAEP(
|
||||
algorithm: RsaOaepParams,
|
||||
key: RsaPublicKey,
|
||||
data: Uint8Array
|
||||
) {
|
||||
protected static encryptOAEP(algorithm: RsaOaepParams, key: RsaPublicKey, data: Uint8Array) {
|
||||
const options: crypto.RsaPublicKey = {
|
||||
key: `-----BEGIN PUBLIC KEY-----\n${key.data.toString(
|
||||
"base64"
|
||||
)}\n-----END PUBLIC KEY-----`,
|
||||
key: `-----BEGIN PUBLIC KEY-----\n${key.data.toString("base64")}\n-----END PUBLIC KEY-----`,
|
||||
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
|
||||
};
|
||||
if (algorithm.label) {
|
||||
|
@ -337,15 +244,9 @@ export class RsaCrypto {
|
|||
return new Uint8Array(crypto.publicEncrypt(options, data)).buffer;
|
||||
}
|
||||
|
||||
protected static decryptOAEP(
|
||||
algorithm: RsaOaepParams,
|
||||
key: RsaPrivateKey,
|
||||
data: Uint8Array
|
||||
) {
|
||||
protected static decryptOAEP(algorithm: RsaOaepParams, key: RsaPrivateKey, data: Uint8Array) {
|
||||
const options: crypto.RsaPrivateKey = {
|
||||
key: `-----BEGIN PRIVATE KEY-----\n${key.data.toString(
|
||||
"base64"
|
||||
)}\n-----END PRIVATE KEY-----`,
|
||||
key: `-----BEGIN PRIVATE KEY-----\n${key.data.toString("base64")}\n-----END PRIVATE KEY-----`,
|
||||
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
|
||||
};
|
||||
if (algorithm.label) {
|
||||
|
@ -354,4 +255,5 @@ export class RsaCrypto {
|
|||
|
||||
return new Uint8Array(crypto.privateDecrypt(options, data)).buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Buffer } from "buffer";
|
||||
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
|
||||
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||
import * as core from "webcrypto-core";
|
||||
|
@ -28,9 +27,7 @@ export class RsaPrivateKey extends AsymmetricKey {
|
|||
}
|
||||
|
||||
public fromJSON(json: JsonWebKey) {
|
||||
const key = JsonParser.fromJSON(json, {
|
||||
targetSchema: core.asn1.RsaPrivateKey,
|
||||
});
|
||||
const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.RsaPrivateKey });
|
||||
|
||||
const keyInfo = new core.asn1.PrivateKeyInfo();
|
||||
keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";
|
||||
|
@ -39,4 +36,5 @@ export class RsaPrivateKey extends AsymmetricKey {
|
|||
|
||||
this.data = Buffer.from(AsnSerializer.serialize(keyInfo));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Buffer } from "buffer";
|
||||
import { AsnParser, AsnSerializer } from "@peculiar/asn1-schema";
|
||||
import { JsonParser, JsonSerializer } from "@peculiar/json-schema";
|
||||
import * as core from "webcrypto-core";
|
||||
|
@ -28,9 +27,7 @@ export class RsaPublicKey extends AsymmetricKey {
|
|||
}
|
||||
|
||||
public fromJSON(json: JsonWebKey) {
|
||||
const key = JsonParser.fromJSON(json, {
|
||||
targetSchema: core.asn1.RsaPublicKey,
|
||||
});
|
||||
const key = JsonParser.fromJSON(json, { targetSchema: core.asn1.RsaPublicKey });
|
||||
|
||||
const keyInfo = new core.asn1.PublicKeyInfo();
|
||||
keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.113549.1.1.1";
|
||||
|
|
|
@ -7,25 +7,21 @@ import { RsaPublicKey } from "./public_key";
|
|||
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||
|
||||
export class RsaEsProvider extends core.ProviderCrypto {
|
||||
|
||||
public name = "RSAES-PKCS1-v1_5";
|
||||
public usages = {
|
||||
publicKey: ["encrypt", "wrapKey"] as core.KeyUsages,
|
||||
privateKey: ["decrypt", "unwrapKey"] as core.KeyUsages,
|
||||
};
|
||||
|
||||
public override async onGenerateKey(
|
||||
algorithm: RsaKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKeyPair> {
|
||||
public override async onGenerateKey(algorithm: RsaKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||
const keys = await RsaCrypto.generateKey(
|
||||
{
|
||||
...algorithm,
|
||||
name: this.name,
|
||||
},
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
keyUsages);
|
||||
|
||||
return {
|
||||
privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey),
|
||||
|
@ -36,12 +32,7 @@ export class RsaEsProvider extends core.ProviderCrypto {
|
|||
public override checkGenerateKeyParams(algorithm: RsaKeyGenParams) {
|
||||
// public exponent
|
||||
this.checkRequiredProperty(algorithm, "publicExponent");
|
||||
if (
|
||||
!(
|
||||
algorithm.publicExponent &&
|
||||
algorithm.publicExponent instanceof Uint8Array
|
||||
)
|
||||
) {
|
||||
if (!(algorithm.publicExponent && algorithm.publicExponent instanceof Uint8Array)) {
|
||||
throw new TypeError("publicExponent: Missing or not a Uint8Array");
|
||||
}
|
||||
const publicExponent = Convert.ToBase64(algorithm.publicExponent);
|
||||
|
@ -61,59 +52,31 @@ export class RsaEsProvider extends core.ProviderCrypto {
|
|||
}
|
||||
}
|
||||
|
||||
public override async onEncrypt(
|
||||
algorithm: Algorithm,
|
||||
key: RsaPublicKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
public override async onEncrypt(algorithm: Algorithm, key: RsaPublicKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
const options = this.toCryptoOptions(key);
|
||||
const enc = crypto.publicEncrypt(options, new Uint8Array(data));
|
||||
return new Uint8Array(enc).buffer;
|
||||
}
|
||||
|
||||
public override async onDecrypt(
|
||||
algorithm: Algorithm,
|
||||
key: RsaPrivateKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
public override async onDecrypt(algorithm: Algorithm, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
const options = this.toCryptoOptions(key);
|
||||
const dec = crypto.privateDecrypt(options, new Uint8Array(data));
|
||||
return new Uint8Array(dec).buffer;
|
||||
}
|
||||
|
||||
public override async onExportKey(
|
||||
format: KeyFormat,
|
||||
key: CryptoKey
|
||||
): Promise<JsonWebKey | ArrayBuffer> {
|
||||
public override async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||
return RsaCrypto.exportKey(format, getCryptoKey(key));
|
||||
}
|
||||
|
||||
public override 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
|
||||
);
|
||||
public override 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);
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||
super.checkCryptoKey(key, keyUsage);
|
||||
const internalKey = getCryptoKey(key);
|
||||
if (
|
||||
!(
|
||||
internalKey instanceof RsaPrivateKey ||
|
||||
internalKey instanceof RsaPublicKey
|
||||
)
|
||||
) {
|
||||
if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) {
|
||||
throw new TypeError("key: Is not RSA CryptoKey");
|
||||
}
|
||||
}
|
||||
|
@ -123,9 +86,7 @@ export class RsaEsProvider extends core.ProviderCrypto {
|
|||
private toCryptoOptions(key: RsaPrivateKey | RsaPublicKey) {
|
||||
const type = key.type.toUpperCase();
|
||||
return {
|
||||
key: `-----BEGIN ${type} KEY-----\n${getCryptoKey(key).data.toString(
|
||||
"base64"
|
||||
)}\n-----END ${type} KEY-----`,
|
||||
key: `-----BEGIN ${type} KEY-----\n${getCryptoKey(key).data.toString("base64")}\n-----END ${type} KEY-----`,
|
||||
padding: crypto.constants.RSA_PKCS1_PADDING,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Buffer } from "buffer";
|
||||
import crypto from "crypto";
|
||||
import * as core from "webcrypto-core";
|
||||
import { RsaCrypto } from "./crypto";
|
||||
|
@ -15,31 +14,23 @@ import { setCryptoKey, getCryptoKey } from "../storage";
|
|||
*/
|
||||
|
||||
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 keys = await RsaCrypto.generateKey(
|
||||
{
|
||||
...algorithm,
|
||||
name: this.name,
|
||||
},
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
keyUsages);
|
||||
|
||||
return {
|
||||
privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey),
|
||||
publicKey: setCryptoKey(keys.publicKey as RsaPublicKey),
|
||||
};
|
||||
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 keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3);
|
||||
|
@ -57,59 +48,37 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
|
|||
|
||||
dataBlock.set(dataView, hashSize + psLength + 1);
|
||||
|
||||
const labelHash = crypto
|
||||
.createHash(internalKey.algorithm.hash.name.replace("-", ""))
|
||||
.update(
|
||||
core.BufferSourceConverter.toUint8Array(
|
||||
algorithm.label || new Uint8Array(0)
|
||||
)
|
||||
)
|
||||
const labelHash = crypto.createHash(internalKey.algorithm.hash.name.replace("-", ""))
|
||||
.update(core.BufferSourceConverter.toUint8Array(algorithm.label || new Uint8Array(0)))
|
||||
.digest();
|
||||
dataBlock.set(labelHash, 0);
|
||||
dataBlock[hashSize + psLength] = 1;
|
||||
|
||||
crypto.randomFillSync(seed);
|
||||
|
||||
const dataBlockMask = this.mgf1(
|
||||
internalKey.algorithm.hash,
|
||||
seed,
|
||||
dataBlock.length
|
||||
);
|
||||
const dataBlockMask = this.mgf1(internalKey.algorithm.hash, seed, dataBlock.length);
|
||||
for (let i = 0; i < dataBlock.length; i++) {
|
||||
dataBlock[i] ^= dataBlockMask[i];
|
||||
}
|
||||
|
||||
const seedMask = this.mgf1(
|
||||
internalKey.algorithm.hash,
|
||||
dataBlock,
|
||||
seed.length
|
||||
);
|
||||
const seedMask = this.mgf1(internalKey.algorithm.hash, dataBlock, seed.length);
|
||||
for (let i = 0; i < seed.length; i++) {
|
||||
seed[i] ^= seedMask[i];
|
||||
}
|
||||
|
||||
if (!internalKey.pem) {
|
||||
internalKey.pem = `-----BEGIN PUBLIC KEY-----\n${internalKey.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(
|
||||
{
|
||||
key: internalKey.pem,
|
||||
padding: crypto.constants.RSA_NO_PADDING,
|
||||
},
|
||||
Buffer.from(message)
|
||||
);
|
||||
const pkcs0 = crypto.publicEncrypt({
|
||||
key: internalKey.pem,
|
||||
padding: crypto.constants.RSA_NO_PADDING,
|
||||
}, Buffer.from(message));
|
||||
|
||||
return new Uint8Array(pkcs0).buffer;
|
||||
}
|
||||
|
||||
public async onDecrypt(
|
||||
algorithm: RsaOaepParams,
|
||||
key: RsaPrivateKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
public async onDecrypt(algorithm: RsaOaepParams, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
const internalKey = getCryptoKey(key) as RsaPrivateKey;
|
||||
const keySize = Math.ceil(internalKey.algorithm.modulusLength >> 3);
|
||||
const hashSize = ShaCrypto.size(internalKey.algorithm.hash) >> 3;
|
||||
|
@ -120,18 +89,13 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
|
|||
}
|
||||
|
||||
if (!internalKey.pem) {
|
||||
internalKey.pem = `-----BEGIN PRIVATE KEY-----\n${internalKey.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(
|
||||
{
|
||||
key: internalKey.pem,
|
||||
padding: crypto.constants.RSA_NO_PADDING,
|
||||
},
|
||||
Buffer.from(data)
|
||||
);
|
||||
let pkcs0 = crypto.privateDecrypt({
|
||||
key: internalKey.pem,
|
||||
padding: crypto.constants.RSA_NO_PADDING,
|
||||
}, Buffer.from(data));
|
||||
const z = pkcs0[0];
|
||||
const seed = pkcs0.subarray(1, hashSize + 1);
|
||||
const dataBlock = pkcs0.subarray(hashSize + 1);
|
||||
|
@ -140,31 +104,18 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
|
|||
throw new Error("Decryption failed");
|
||||
}
|
||||
|
||||
const seedMask = this.mgf1(
|
||||
internalKey.algorithm.hash,
|
||||
dataBlock,
|
||||
seed.length
|
||||
);
|
||||
const seedMask = this.mgf1(internalKey.algorithm.hash, dataBlock, seed.length);
|
||||
for (let i = 0; i < seed.length; i++) {
|
||||
seed[i] ^= seedMask[i];
|
||||
}
|
||||
|
||||
const dataBlockMask = this.mgf1(
|
||||
internalKey.algorithm.hash,
|
||||
seed,
|
||||
dataBlock.length
|
||||
);
|
||||
const dataBlockMask = this.mgf1(internalKey.algorithm.hash, seed, dataBlock.length);
|
||||
for (let i = 0; i < dataBlock.length; i++) {
|
||||
dataBlock[i] ^= dataBlockMask[i];
|
||||
}
|
||||
|
||||
const labelHash = crypto
|
||||
.createHash(internalKey.algorithm.hash.name.replace("-", ""))
|
||||
.update(
|
||||
core.BufferSourceConverter.toUint8Array(
|
||||
algorithm.label || new Uint8Array(0)
|
||||
)
|
||||
)
|
||||
const labelHash = crypto.createHash(internalKey.algorithm.hash.name.replace("-", ""))
|
||||
.update(core.BufferSourceConverter.toUint8Array(algorithm.label || new Uint8Array(0)))
|
||||
.digest();
|
||||
for (let i = 0; i < hashSize; i++) {
|
||||
if (labelHash[i] !== dataBlock[i]) {
|
||||
|
@ -191,39 +142,19 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
|
|||
return new Uint8Array(pkcs0).buffer;
|
||||
}
|
||||
|
||||
public async onExportKey(
|
||||
format: KeyFormat,
|
||||
key: CryptoKey
|
||||
): Promise<JsonWebKey | ArrayBuffer> {
|
||||
public async onExportKey(format: KeyFormat, key: CryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||
return RsaCrypto.exportKey(format, getCryptoKey(key));
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
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);
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||
super.checkCryptoKey(key, keyUsage);
|
||||
const internalKey = getCryptoKey(key);
|
||||
if (
|
||||
!(
|
||||
internalKey instanceof RsaPrivateKey ||
|
||||
internalKey instanceof RsaPublicKey
|
||||
)
|
||||
) {
|
||||
if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) {
|
||||
throw new TypeError("key: Is not RSA CryptoKey");
|
||||
}
|
||||
}
|
||||
|
@ -247,8 +178,7 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
|
|||
|
||||
const submask = mask.subarray(i * hashSize);
|
||||
|
||||
let chunk = crypto
|
||||
.createHash(algorithm.name.replace("-", ""))
|
||||
let chunk = crypto.createHash(algorithm.name.replace("-", ""))
|
||||
.update(seed)
|
||||
.update(counter)
|
||||
.digest() as Uint8Array;
|
||||
|
@ -261,4 +191,5 @@ export class RsaOaepProvider extends core.RsaOaepProvider {
|
|||
|
||||
return mask;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,98 +5,50 @@ import { RsaPublicKey } from "./public_key";
|
|||
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||
|
||||
export class RsaPssProvider extends core.RsaPssProvider {
|
||||
public override hashAlgorithms = [
|
||||
"SHA-1",
|
||||
"SHA-256",
|
||||
"SHA-384",
|
||||
"SHA-512",
|
||||
"shake128",
|
||||
"shake256",
|
||||
"SHA3-256",
|
||||
"SHA3-384",
|
||||
"SHA3-512",
|
||||
];
|
||||
|
||||
public async onGenerateKey(
|
||||
algorithm: RsaHashedKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<CryptoKeyPair> {
|
||||
public override hashAlgorithms = [
|
||||
"SHA-1", "SHA-256", "SHA-384", "SHA-512",
|
||||
"shake128", "shake256",
|
||||
"SHA3-256", "SHA3-384", "SHA3-512"];
|
||||
|
||||
public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair> {
|
||||
const keys = await RsaCrypto.generateKey(
|
||||
{
|
||||
...algorithm,
|
||||
name: this.name,
|
||||
},
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
keyUsages);
|
||||
|
||||
return {
|
||||
privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey),
|
||||
publicKey: setCryptoKey(keys.publicKey as RsaPublicKey),
|
||||
};
|
||||
return {
|
||||
privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey),
|
||||
publicKey: setCryptoKey(keys.publicKey as RsaPublicKey),
|
||||
};
|
||||
}
|
||||
|
||||
public async onSign(
|
||||
algorithm: RsaPssParams,
|
||||
key: RsaPrivateKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return RsaCrypto.sign(
|
||||
algorithm,
|
||||
getCryptoKey(key) as RsaPrivateKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onSign(algorithm: RsaPssParams, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return RsaCrypto.sign(algorithm, getCryptoKey(key) as RsaPrivateKey, new Uint8Array(data));
|
||||
}
|
||||
|
||||
public async onVerify(
|
||||
algorithm: RsaPssParams,
|
||||
key: RsaPublicKey,
|
||||
signature: ArrayBuffer,
|
||||
data: ArrayBuffer
|
||||
): Promise<boolean> {
|
||||
return RsaCrypto.verify(
|
||||
algorithm,
|
||||
getCryptoKey(key) as RsaPublicKey,
|
||||
new Uint8Array(signature),
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onVerify(algorithm: RsaPssParams, key: RsaPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
|
||||
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, getCryptoKey(key));
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
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);
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||
super.checkCryptoKey(key, keyUsage);
|
||||
const internalKey = getCryptoKey(key);
|
||||
if (
|
||||
!(
|
||||
internalKey instanceof RsaPrivateKey ||
|
||||
internalKey instanceof RsaPublicKey
|
||||
)
|
||||
) {
|
||||
if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) {
|
||||
throw new TypeError("key: Is not RSA CryptoKey");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,98 +5,50 @@ import { RsaPublicKey } from "./public_key";
|
|||
import { setCryptoKey, getCryptoKey } from "../storage";
|
||||
|
||||
export class RsaSsaProvider extends core.RsaSsaProvider {
|
||||
public override hashAlgorithms = [
|
||||
"SHA-1",
|
||||
"SHA-256",
|
||||
"SHA-384",
|
||||
"SHA-512",
|
||||
"shake128",
|
||||
"shake256",
|
||||
"SHA3-256",
|
||||
"SHA3-384",
|
||||
"SHA3-512",
|
||||
];
|
||||
|
||||
public async onGenerateKey(
|
||||
algorithm: RsaHashedKeyGenParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[]
|
||||
): Promise<globalThis.CryptoKeyPair> {
|
||||
public override hashAlgorithms = [
|
||||
"SHA-1", "SHA-256", "SHA-384", "SHA-512",
|
||||
"shake128", "shake256",
|
||||
"SHA3-256", "SHA3-384", "SHA3-512"];
|
||||
|
||||
public async onGenerateKey(algorithm: RsaHashedKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<globalThis.CryptoKeyPair> {
|
||||
const keys = await RsaCrypto.generateKey(
|
||||
{
|
||||
...algorithm,
|
||||
name: this.name,
|
||||
},
|
||||
extractable,
|
||||
keyUsages
|
||||
);
|
||||
keyUsages);
|
||||
|
||||
return {
|
||||
privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey),
|
||||
publicKey: setCryptoKey(keys.publicKey as RsaPublicKey),
|
||||
};
|
||||
return {
|
||||
privateKey: setCryptoKey(keys.privateKey as RsaPrivateKey),
|
||||
publicKey: setCryptoKey(keys.publicKey as RsaPublicKey),
|
||||
};
|
||||
}
|
||||
|
||||
public async onSign(
|
||||
algorithm: Algorithm,
|
||||
key: RsaPrivateKey,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
return RsaCrypto.sign(
|
||||
algorithm,
|
||||
getCryptoKey(key) as RsaPrivateKey,
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onSign(algorithm: Algorithm, key: RsaPrivateKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return RsaCrypto.sign(algorithm, getCryptoKey(key) as RsaPrivateKey, new Uint8Array(data));
|
||||
}
|
||||
|
||||
public async onVerify(
|
||||
algorithm: Algorithm,
|
||||
key: RsaPublicKey,
|
||||
signature: ArrayBuffer,
|
||||
data: ArrayBuffer
|
||||
): Promise<boolean> {
|
||||
return RsaCrypto.verify(
|
||||
algorithm,
|
||||
getCryptoKey(key) as RsaPublicKey,
|
||||
new Uint8Array(signature),
|
||||
new Uint8Array(data)
|
||||
);
|
||||
public async onVerify(algorithm: Algorithm, key: RsaPublicKey, signature: ArrayBuffer, data: ArrayBuffer): Promise<boolean> {
|
||||
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, getCryptoKey(key));
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
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);
|
||||
return setCryptoKey(key);
|
||||
}
|
||||
|
||||
public override checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||
super.checkCryptoKey(key, keyUsage);
|
||||
const internalKey = getCryptoKey(key);
|
||||
if (
|
||||
!(
|
||||
internalKey instanceof RsaPrivateKey ||
|
||||
internalKey instanceof RsaPublicKey
|
||||
)
|
||||
) {
|
||||
if (!(internalKey instanceof RsaPrivateKey || internalKey instanceof RsaPublicKey)) {
|
||||
throw new TypeError("key: Is not RSA CryptoKey");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Buffer } from "buffer";
|
||||
import crypto from "crypto";
|
||||
|
||||
export class ShaCrypto {
|
||||
|
||||
/**
|
||||
* Returns size of the hash algorithm in bits
|
||||
* @param algorithm Hash algorithm
|
||||
|
@ -53,7 +53,9 @@ export class ShaCrypto {
|
|||
|
||||
public static digest(algorithm: Algorithm, data: ArrayBuffer) {
|
||||
const hashAlg = this.getAlgorithmName(algorithm);
|
||||
const hash = crypto.createHash(hashAlg).update(Buffer.from(data)).digest();
|
||||
const hash = crypto.createHash(hashAlg)
|
||||
.update(Buffer.from(data)).digest();
|
||||
return new Uint8Array(hash).buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,10 +5,8 @@ export class Sha3256Provider extends core.ProviderCrypto {
|
|||
public name = "SHA3-256";
|
||||
public usages = [];
|
||||
|
||||
public override async onDigest(
|
||||
algorithm: Algorithm,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return ShaCrypto.digest(algorithm, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,10 +5,8 @@ export class Sha3384Provider extends core.ProviderCrypto {
|
|||
public name = "SHA3-384";
|
||||
public usages = [];
|
||||
|
||||
public override async onDigest(
|
||||
algorithm: Algorithm,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return ShaCrypto.digest(algorithm, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,10 +5,8 @@ export class Sha3512Provider extends core.ProviderCrypto {
|
|||
public name = "SHA3-512";
|
||||
public usages = [];
|
||||
|
||||
public override async onDigest(
|
||||
algorithm: Algorithm,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return ShaCrypto.digest(algorithm, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,10 +5,8 @@ export class Sha1Provider extends core.ProviderCrypto {
|
|||
public name = "SHA-1";
|
||||
public usages = [];
|
||||
|
||||
public override async onDigest(
|
||||
algorithm: Algorithm,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return ShaCrypto.digest(algorithm, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,10 +5,8 @@ export class Sha256Provider extends core.ProviderCrypto {
|
|||
public name = "SHA-256";
|
||||
public usages = [];
|
||||
|
||||
public override async onDigest(
|
||||
algorithm: Algorithm,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return ShaCrypto.digest(algorithm, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,10 +5,8 @@ export class Sha384Provider extends core.ProviderCrypto {
|
|||
public name = "SHA-384";
|
||||
public usages = [];
|
||||
|
||||
public override async onDigest(
|
||||
algorithm: Algorithm,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return ShaCrypto.digest(algorithm, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,10 +5,8 @@ export class Sha512Provider extends core.ProviderCrypto {
|
|||
public name = "SHA-512";
|
||||
public usages = [];
|
||||
|
||||
public override async onDigest(
|
||||
algorithm: Algorithm,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
public override async onDigest(algorithm: Algorithm, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return ShaCrypto.digest(algorithm, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,19 +1,13 @@
|
|||
import { Buffer } from "buffer";
|
||||
import crypto from "crypto";
|
||||
import * as core from "webcrypto-core";
|
||||
|
||||
export class ShakeCrypto {
|
||||
public static digest(
|
||||
algorithm: Required<core.ShakeParams>,
|
||||
data: ArrayBuffer
|
||||
) {
|
||||
const hash = crypto
|
||||
.createHash(algorithm.name.toLowerCase(), {
|
||||
outputLength: algorithm.length,
|
||||
})
|
||||
.update(Buffer.from(data))
|
||||
.digest();
|
||||
|
||||
public static digest(algorithm: Required<core.ShakeParams>, data: ArrayBuffer) {
|
||||
const hash = crypto.createHash(algorithm.name.toLowerCase(), {outputLength: algorithm.length})
|
||||
.update(Buffer.from(data)).digest();
|
||||
|
||||
return new Uint8Array(hash).buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,10 +2,9 @@ import * as core from "webcrypto-core";
|
|||
import { ShakeCrypto } from "./crypto";
|
||||
|
||||
export class Shake128Provider extends core.Shake128Provider {
|
||||
public override async onDigest(
|
||||
algorithm: Required<core.ShakeParams>,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
|
||||
public override async onDigest(algorithm: Required<core.ShakeParams>, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return ShakeCrypto.digest(algorithm, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,10 +2,9 @@ import * as core from "webcrypto-core";
|
|||
import { ShakeCrypto } from "./crypto";
|
||||
|
||||
export class Shake256Provider extends core.Shake256Provider {
|
||||
public override async onDigest(
|
||||
algorithm: Required<core.ShakeParams>,
|
||||
data: ArrayBuffer
|
||||
): Promise<ArrayBuffer> {
|
||||
|
||||
public override async onDigest(algorithm: Required<core.ShakeParams>, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return ShakeCrypto.digest(algorithm, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,12 +12,7 @@ export function getCryptoKey(key: core.CryptoKey) {
|
|||
}
|
||||
|
||||
export function setCryptoKey(value: InternalCryptoKey) {
|
||||
const key = core.CryptoKey.create(
|
||||
value.algorithm,
|
||||
value.type,
|
||||
value.extractable,
|
||||
value.usages
|
||||
);
|
||||
const key = core.CryptoKey.create(value.algorithm, value.type, value.extractable, value.usages);
|
||||
Object.freeze(key);
|
||||
|
||||
keyStorage.set(key, value);
|
||||
|
|
|
@ -2,34 +2,18 @@ import * as crypto from "crypto";
|
|||
import * as process from "process";
|
||||
import * as core from "webcrypto-core";
|
||||
import {
|
||||
AesCbcProvider,
|
||||
AesCmacProvider,
|
||||
AesCtrProvider,
|
||||
AesEcbProvider,
|
||||
AesGcmProvider,
|
||||
AesKwProvider,
|
||||
AesCbcProvider, AesCmacProvider, AesCtrProvider, AesEcbProvider, AesGcmProvider, AesKwProvider,
|
||||
DesCbcProvider,
|
||||
DesEde3CbcProvider,
|
||||
EcdhProvider,
|
||||
EcdsaProvider,
|
||||
HkdfProvider,
|
||||
DesEde3CbcProvider, EcdhProvider,
|
||||
EcdsaProvider, HkdfProvider,
|
||||
EdDsaProvider,
|
||||
EcdhEsProvider,
|
||||
HmacProvider,
|
||||
Pbkdf2Provider,
|
||||
RsaEsProvider,
|
||||
RsaOaepProvider,
|
||||
RsaPssProvider,
|
||||
RsaSsaProvider,
|
||||
Sha1Provider,
|
||||
Sha256Provider,
|
||||
Sha384Provider,
|
||||
Sha512Provider,
|
||||
Shake128Provider,
|
||||
Shake256Provider,
|
||||
Sha3256Provider,
|
||||
Sha3384Provider,
|
||||
Sha3512Provider,
|
||||
RsaEsProvider, RsaOaepProvider, RsaPssProvider, RsaSsaProvider,
|
||||
Sha1Provider, Sha256Provider, Sha384Provider, Sha512Provider,
|
||||
Shake128Provider, Shake256Provider,
|
||||
Sha3256Provider, Sha3384Provider, Sha3512Provider,
|
||||
} from "./mechs";
|
||||
|
||||
export class SubtleCrypto extends core.SubtleCrypto {
|
||||
|
|
Reference in New Issue