Implemented AES-KW

This commit is contained in:
Liran Nuna 2019-03-01 20:40:35 -08:00
parent eda6bc4f0a
commit c889951dc4
7 changed files with 243 additions and 1 deletions

View File

@ -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 |

40
src/mechs/aes/aes_kw.ts Normal file
View File

@ -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");
}
}
}

View File

@ -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;
}
}

View File

@ -3,3 +3,4 @@ export * from "./aes_cbc";
export * from "./aes_cmac";
export * from "./aes_ctr";
export * from "./aes_gcm";
export * from "./aes_kw";

View File

@ -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");
}

View File

@ -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

View File

@ -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
]);
});