commit
e512422a2b
|
@ -40,6 +40,7 @@ npm install @peculiar/webcrypto
|
|||
| AES-CBC | X | | X | | X | X | |
|
||||
| AES-CTR | X | | X | | X | X | |
|
||||
| AES-GCM | X | | X | | X | X | |
|
||||
| AES-KW | X | | X | | | X | |
|
||||
| ECDSA<sup>1</sup> | X | | X | X | | | |
|
||||
| ECDH<sup>1</sup> | X | | X | | | | X |
|
||||
| PBKDF2 | | | X | | | | X |
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import * as core from "webcrypto-core";
|
||||
import { AesCrypto } from "./crypto";
|
||||
import { AesCryptoKey } from "./key";
|
||||
|
||||
export class AesKwProvider extends core.AesKwProvider {
|
||||
|
||||
public async onGenerateKey(algorithm: AesKeyGenParams, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair | CryptoKey> {
|
||||
return await AesCrypto.generateKey(
|
||||
{
|
||||
name: this.name,
|
||||
length: algorithm.length,
|
||||
},
|
||||
extractable,
|
||||
keyUsages,
|
||||
);
|
||||
}
|
||||
|
||||
public async onExportKey(format: KeyFormat, key: AesCryptoKey): Promise<JsonWebKey | ArrayBuffer> {
|
||||
return AesCrypto.exportKey(format, key);
|
||||
}
|
||||
|
||||
public async onImportKey(format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, algorithm: Algorithm, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey> {
|
||||
return AesCrypto.importKey(format, keyData, { name: algorithm.name }, extractable, keyUsages);
|
||||
}
|
||||
|
||||
public async onEncrypt(algorithm: AesKeyAlgorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return AesCrypto.encrypt(algorithm, key, new Uint8Array(data));
|
||||
}
|
||||
|
||||
public async onDecrypt(algorithm: AesKeyAlgorithm, key: AesCryptoKey, data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||
return AesCrypto.decrypt(algorithm, key, new Uint8Array(data));
|
||||
}
|
||||
|
||||
public checkCryptoKey(key: CryptoKey, keyUsage?: KeyUsage) {
|
||||
super.checkCryptoKey(key, keyUsage);
|
||||
if (!(key instanceof AesCryptoKey)) {
|
||||
throw new TypeError("key: Is not a AesCryptoKey");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -74,6 +74,8 @@ export class AesCrypto {
|
|||
return this.encryptAesCTR(algorithm as AesCtrParams, key, Buffer.from(data));
|
||||
case "AES-GCM":
|
||||
return this.encryptAesGCM(algorithm as AesGcmParams, key, Buffer.from(data));
|
||||
case "AES-KW":
|
||||
return this.encryptAesKW(algorithm as AesKeyAlgorithm, key, Buffer.from(data));
|
||||
default:
|
||||
throw new core.OperationError("algorithm: Is not recognized");
|
||||
}
|
||||
|
@ -91,6 +93,8 @@ export class AesCrypto {
|
|||
return this.decryptAesCTR(algorithm as AesCtrParams, key, Buffer.from(data));
|
||||
case "AES-GCM":
|
||||
return this.decryptAesGCM(algorithm as AesGcmParams, key, Buffer.from(data));
|
||||
case "AES-KW":
|
||||
return this.decryptAesKW(algorithm as AesKeyAlgorithm, key, Buffer.from(data));
|
||||
default:
|
||||
throw new core.OperationError("algorithm: Is not recognized");
|
||||
}
|
||||
|
@ -153,4 +157,20 @@ export class AesCrypto {
|
|||
return new Uint8Array(dec).buffer;
|
||||
}
|
||||
|
||||
public static async encryptAesKW(algorithm: AesKeyAlgorithm, key: AesCryptoKey, data: Buffer) {
|
||||
const iv = Buffer.from("A6A6A6A6A6A6A6A6", "hex");
|
||||
const cipher = crypto.createCipheriv(`id-aes${key.algorithm.length}-wrap`, key.data, iv);
|
||||
let enc = cipher.update(data);
|
||||
enc = Buffer.concat([enc, cipher.final()]);
|
||||
const res = new Uint8Array(enc).buffer;
|
||||
return res;
|
||||
}
|
||||
|
||||
public static async decryptAesKW(algorithm: AesKeyAlgorithm, key: AesCryptoKey, data: Buffer) {
|
||||
const iv = Buffer.from("A6A6A6A6A6A6A6A6", "'hex");
|
||||
const decipher = crypto.createDecipheriv(`id-aes${key.algorithm.length}-wrap`, key.data, iv);
|
||||
let dec = decipher.update(data);
|
||||
dec = Buffer.concat([dec, decipher.final()]);
|
||||
return new Uint8Array(dec).buffer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,3 +3,4 @@ export * from "./aes_cbc";
|
|||
export * from "./aes_cmac";
|
||||
export * from "./aes_ctr";
|
||||
export * from "./aes_gcm";
|
||||
export * from "./aes_kw";
|
||||
|
|
|
@ -18,6 +18,8 @@ export class AesCryptoKey extends SymmetricKey {
|
|||
return `A${this.algorithm.length}CTR`;
|
||||
case "AES-GCM":
|
||||
return `A${this.algorithm.length}GCM`;
|
||||
case "AES-KW":
|
||||
return `A${this.algorithm.length}KW`;
|
||||
default:
|
||||
throw new core.AlgorithmError("Unsupported algorithm name");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as core from "webcrypto-core";
|
||||
import {
|
||||
AesCbcProvider, AesCtrProvider, AesGcmProvider,
|
||||
AesCbcProvider, AesCtrProvider, AesGcmProvider, AesKwProvider,
|
||||
DesCbcProvider, DesEde3CbcProvider,
|
||||
EcdhProvider, EcdsaProvider,
|
||||
HmacProvider,
|
||||
|
@ -17,6 +17,7 @@ export class SubtleCrypto extends core.SubtleCrypto {
|
|||
this.providers.set(new AesCbcProvider());
|
||||
this.providers.set(new AesCtrProvider());
|
||||
this.providers.set(new AesGcmProvider());
|
||||
this.providers.set(new AesKwProvider());
|
||||
//#endregion
|
||||
|
||||
//#region DES
|
||||
|
|
177
test/aes.ts
177
test/aes.ts
|
@ -529,6 +529,183 @@ context("AES", () => {
|
|||
},
|
||||
//#endregion
|
||||
|
||||
//#region AES-KW
|
||||
{
|
||||
name: "AES-128-KW",
|
||||
actions: {
|
||||
generateKey: [
|
||||
{
|
||||
algorithm: { name: "AES-KW", length: 128 } as AesKeyGenParams,
|
||||
extractable: true,
|
||||
keyUsages: ["wrapKey", "unwrapKey"] as KeyUsage[],
|
||||
},
|
||||
],
|
||||
wrapKey: [
|
||||
{
|
||||
key: {
|
||||
format: "raw",
|
||||
algorithm: "AES-KW",
|
||||
data: Buffer.from("000102030405060708090A0B0C0D0E0F", "hex"),
|
||||
extractable: true,
|
||||
keyUsages: ["wrapKey", "unwrapKey"],
|
||||
},
|
||||
wKey: {
|
||||
format: "raw" as KeyFormat,
|
||||
data: Buffer.from("00112233445566778899AABBCCDDEEFF", "hex"),
|
||||
algorithm: "AES-KW",
|
||||
extractable: true,
|
||||
keyUsages: ["wrapKey", "unwrapKey"],
|
||||
},
|
||||
algorithm: {
|
||||
name: "AES-KW",
|
||||
},
|
||||
wrappedKey: Buffer.from("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5", "hex")
|
||||
},
|
||||
],
|
||||
import: [
|
||||
{
|
||||
name: "raw",
|
||||
format: "raw" as KeyFormat,
|
||||
data: Buffer.from("1234567890abcdef12345678"),
|
||||
algorithm: "AES-KW",
|
||||
extractable: true,
|
||||
keyUsages: ["wrapKey", "unwrapKey"] as KeyUsage[],
|
||||
},
|
||||
{
|
||||
name: "jwk",
|
||||
format: "jwk",
|
||||
data: {
|
||||
kty: "oct",
|
||||
alg: "A192KW",
|
||||
k: "MTIzNDU2Nzg5MGFiY2RlZjEyMzQ1Njc4",
|
||||
ext: true,
|
||||
key_ops: ["wrapKey", "unwrapKey"],
|
||||
},
|
||||
algorithm: "AES-KW",
|
||||
extractable: true,
|
||||
keyUsages: ["wrapKey", "unwrapKey"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AES-192-KW",
|
||||
actions: {
|
||||
generateKey: [
|
||||
{
|
||||
algorithm: { name: "AES-KW", length: 192 } as AesKeyGenParams,
|
||||
extractable: true,
|
||||
keyUsages: ["wrapKey", "unwrapKey"] as KeyUsage[],
|
||||
},
|
||||
],
|
||||
wrapKey: [
|
||||
{
|
||||
key: {
|
||||
format: "raw",
|
||||
algorithm: "AES-KW",
|
||||
data: Buffer.from("000102030405060708090A0B0C0D0E0F1011121314151617", "hex"),
|
||||
extractable: true,
|
||||
keyUsages: ["wrapKey", "unwrapKey"],
|
||||
},
|
||||
wKey: {
|
||||
format: "raw" as KeyFormat,
|
||||
data: Buffer.from("00112233445566778899AABBCCDDEEFF0001020304050607", "hex"),
|
||||
algorithm: "AES-KW",
|
||||
extractable: true,
|
||||
keyUsages: ["wrapKey", "unwrapKey"],
|
||||
},
|
||||
algorithm: {
|
||||
name: "AES-KW",
|
||||
},
|
||||
wrappedKey: Buffer.from("031D33264E15D33268F24EC260743EDCE1C6C7DDEE725A936BA814915C6762D2", "hex")
|
||||
},
|
||||
],
|
||||
import: [
|
||||
{
|
||||
name: "raw",
|
||||
format: "raw" as KeyFormat,
|
||||
data: Buffer.from("1234567890abcdef12345678"),
|
||||
algorithm: "AES-KW",
|
||||
extractable: true,
|
||||
keyUsages: ["wrapKey", "unwrapKey"] as KeyUsage[],
|
||||
},
|
||||
{
|
||||
name: "jwk",
|
||||
format: "jwk",
|
||||
data: {
|
||||
kty: "oct",
|
||||
alg: "A192KW",
|
||||
k: "MTIzNDU2Nzg5MGFiY2RlZjEyMzQ1Njc4",
|
||||
ext: true,
|
||||
key_ops: ["wrapKey", "unwrapKey"],
|
||||
},
|
||||
algorithm: "AES-KW",
|
||||
extractable: true,
|
||||
keyUsages: ["wrapKey", "unwrapKey"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AES-256-KW",
|
||||
actions: {
|
||||
generateKey: [
|
||||
{
|
||||
algorithm: { name: "AES-KW", length: 256 } as AesKeyGenParams,
|
||||
extractable: true,
|
||||
keyUsages: ["wrapKey", "unwrapKey"],
|
||||
},
|
||||
],
|
||||
wrapKey: [
|
||||
{
|
||||
key: {
|
||||
format: "raw",
|
||||
algorithm: "AES-KW",
|
||||
data: Buffer.from("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", "hex"),
|
||||
extractable: true,
|
||||
keyUsages: ["wrapKey", "unwrapKey"],
|
||||
},
|
||||
wKey: {
|
||||
format: "raw" as KeyFormat,
|
||||
data: Buffer.from("00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F", "hex"),
|
||||
algorithm: "AES-KW",
|
||||
extractable: true,
|
||||
keyUsages: ["wrapKey", "unwrapKey"],
|
||||
},
|
||||
algorithm: {
|
||||
name: "AES-KW",
|
||||
},
|
||||
wrappedKey: Buffer.from("28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21", "hex"),
|
||||
},
|
||||
],
|
||||
import: [
|
||||
{
|
||||
name: "raw",
|
||||
format: "raw",
|
||||
data: Buffer.from("1234567890abcdef1234567890abcdef"),
|
||||
algorithm: "AES-KW",
|
||||
extractable: true,
|
||||
keyUsages: ["wrapKey", "unwrapKey"],
|
||||
},
|
||||
{
|
||||
name: "jwk",
|
||||
format: "jwk",
|
||||
data: {
|
||||
kty: "oct",
|
||||
alg: "A256KW",
|
||||
k: "MTIzNDU2Nzg5MGFiY2RlZjEyMzQ1Njc4OTBhYmNkZWY",
|
||||
ext: true,
|
||||
key_ops: ["wrapKey", "unwrapKey"],
|
||||
},
|
||||
algorithm: "AES-KW",
|
||||
extractable: true,
|
||||
keyUsages: ["wrapKey", "unwrapKey"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
//#endregion
|
||||
|
||||
]);
|
||||
|
||||
});
|
||||
|
|
Reference in New Issue