Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

miscreant

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

miscreant - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

src/exceptions/integrity_error.ts

2

package.json
{
"name": "miscreant",
"version": "0.1.0",
"version": "0.2.0",
"description": "Misuse resistant symmetric encryption using the AES-SIV (RFC 5297) and CHAIN/STREAM constructions",

@@ -5,0 +5,0 @@ "homepage": "https://github.com/miscreant/miscreant/tree/master/js/",

@@ -120,3 +120,3 @@ # miscreant.js [![Latest Version][npm-shield]][npm-link] [![Build Status][build-image]][build-link] [![Known Vulnerabilities][snyk-image]][snyk-link] [![MIT licensed][license-image]][license-link] [![Gitter Chat][gitter-image]][gitter-link]

```
Miscreant.importKey(keyData, algorithm[, crypto = window.crypto])
Miscreant.importKey(keyData, algorithm[, provider = Miscreant.webCryptoProvider()])
```

@@ -129,6 +129,10 @@

SIV uses two distinct AES keys to perform its operations.
* **algorithm**: a string describing the algorithm to use. The only algorithm
presently supported is `"AES-SIV"`.
* **crypto**: a cryptography provider that implements the WebCrypto API's
[Crypto] interface.
* **algorithm**: a string describing the algorithm to use. The following
algorithms are supported:
* `"AES-SIV"`: CMAC-based construction described in [RFC 5297]. Slower but
standardized and more common.
* `"AES-PMAC-SIV"`: PMAC-based construction. Supports potentially faster
implementations, but is non-standard and only available in Miscreant libraries.
* **provider**: a cryptography provider that implements Miscreant's
[ICryptoProvider] interface.

@@ -159,3 +163,3 @@ #### Return Value

let key = await Miscreant.importKey(keyData, "AES-SIV");
let key = await Miscreant.importKey(keyData, "AES-PMAC-SIV");
```

@@ -195,3 +199,3 @@

let key = await Miscreant.importKey(keyData, "AES-SIV");
let key = await Miscreant.importKey(keyData, "AES-PMAC-SIV");

@@ -209,3 +213,4 @@ // Encrypt plaintext

The **open()** method decrypts a message which has been encrypted using **AES-SIV**.
The **open()** method decrypts a message which has been encrypted using
**AES-SIV** or **AES-PMAC-SIV**.

@@ -240,3 +245,3 @@ #### Syntax

let key = await Miscreant.importKey(keyData, "AES-SIV");
let key = await Miscreant.importKey(keyData, "AES-PMAC-SIV");

@@ -283,3 +288,3 @@ // Encrypt plaintext

```
Miscreant.getCryptoProvider("polyfill")
Miscreant.polyfillCryptoProvider()
```

@@ -290,6 +295,14 @@

```
const polyfillCrypto = Miscreant.getCryptoProvider("polyfill");
const key = Miscreant.importKey(keyData, "AES-SIV", polyfillCrypto);
const key = Miscreant.importKey(keyData, "AES-PMAC-SIV", Miscreant.polyfillCryptoProvider());
```
## Code of Conduct
We abide by the [Contributor Covenant][cc] and ask that you do as well.
For more information, please see [CODE_OF_CONDUCT.md].
[cc]: https://contributor-covenant.org
[CODE_OF_CONDUCT.md]: https://github.com/miscreant/miscreant/blob/master/CODE_OF_CONDUCT.md
## Contributing

@@ -296,0 +309,0 @@

// Copyright (C) 2017 Dmitry Chestnykh, Tony Arcieri
// MIT License. See LICENSE file for details.
import { equal } from "./constant-time";
import { dbl, defaultCryptoProvider, wipe, xor, zeroIVBits } from "./util";
import { equal } from "./util/constant-time";
import { wipe } from "./util/wipe";
import { xor } from "./util/xor";
import IntegrityError from "./exceptions/integrity_error";
import NotImplementedError from "./exceptions/not_implemented_error";
import { ICmacLike, ICtrLike, ISivLike } from "./interfaces";
import IntegrityError from "../exceptions/integrity_error";
import NotImplementedError from "../exceptions/not_implemented_error";
import Block from "./block";
import { ICryptoProvider, ICtrLike, IMacLike, ISivLike } from "./interfaces";
import PolyfillCrypto from "./polyfill";
import PolyfillAes from "./polyfill/aes";
import PolyfillAesCmac from "./polyfill/aes_cmac";
import PolyfillAesCtr from "./polyfill/aes_ctr";
import WebCryptoAesCmac from "./webcrypto/aes_cmac";
import WebCryptoAesCtr from "./webcrypto/aes_ctr";
import Cmac from "./mac/cmac";
import Pmac from "./mac/pmac";

@@ -25,4 +23,5 @@ /** Maximum number of associated data items */

public static async importKey(
provider: ICryptoProvider,
alg: string,
keyData: Uint8Array,
crypto: Crypto | PolyfillCrypto = defaultCryptoProvider(),
): Promise<AesSiv> {

@@ -37,37 +36,32 @@ // We only support AES-128 and AES-256. AES-SIV needs a key 2X as long the intended security level

if (crypto instanceof PolyfillCrypto) {
const mac = new PolyfillAesCmac(new PolyfillAes(macKey));
const ctr = new PolyfillAesCtr(new PolyfillAes(encKey));
return new AesSiv(mac, ctr, null);
} else {
const mac = await WebCryptoAesCmac.importKey(macKey, crypto);
let mac: IMacLike;
try {
const ctr = await WebCryptoAesCtr.importKey(encKey, crypto);
return new AesSiv(mac, ctr, crypto);
} catch (e) {
if (e.message.includes("unsupported")) {
throw new NotImplementedError("AES-SIV: unsupported crypto backend (CTR missing). Use PolyfillCrypto.");
} else {
throw e;
}
}
switch (alg) {
case "AES-SIV":
mac = await Cmac.importKey(provider, macKey);
break;
case "AES-CMAC-SIV":
mac = await Cmac.importKey(provider, macKey);
break;
case "AES-PMAC-SIV":
mac = await Pmac.importKey(provider, macKey);
break;
default:
throw new NotImplementedError(`Miscreant: algorithm not supported: ${alg}`);
}
const ctr = await provider.importAesCtrKey(encKey);
return new AesSiv(mac, ctr);
}
public tagLength: number;
private _mac: ICmacLike;
private _mac: IMacLike;
private _ctr: ICtrLike;
private _tmp1: Uint8Array;
private _tmp2: Uint8Array;
private _crypto: Crypto | null;
private _tmp1: Block;
private _tmp2: Block;
constructor(mac: ICmacLike, ctr: ICtrLike, crypto: Crypto | null = defaultCryptoProvider()) {
constructor(mac: IMacLike, ctr: ICtrLike) {
this._mac = mac;
this._ctr = ctr;
this._crypto = crypto;
this._tmp1 = new Uint8Array(this._mac.digestLength);
this._tmp2 = new Uint8Array(this._mac.digestLength);
this.tagLength = this._mac.digestLength;
this._tmp1 = new Block();
this._tmp2 = new Block();
}

@@ -82,3 +76,3 @@

// Allocate space for sealed ciphertext.
const resultLength = this.tagLength + plaintext.length;
const resultLength = Block.SIZE + plaintext.length;
const result = new Uint8Array(resultLength);

@@ -92,3 +86,3 @@

zeroIVBits(iv);
result.set(await this._ctr.encrypt(iv, plaintext), iv.length);
result.set(await this._ctr.encryptCtr(iv, plaintext), iv.length);
return result;

@@ -103,3 +97,3 @@ }

if (sealed.length < this.tagLength) {
if (sealed.length < Block.SIZE) {
throw new IntegrityError("AES-SIV: ciphertext is truncated");

@@ -109,8 +103,9 @@ }

// Decrypt.
const tag = sealed.subarray(0, this.tagLength);
const iv = this._tmp1;
const tag = sealed.subarray(0, Block.SIZE);
const iv = this._tmp1.data;
iv.set(tag);
zeroIVBits(iv);
const result = await this._ctr.decrypt(iv, sealed.subarray(this.tagLength));
// NOTE: "encryptCtr" is intentional. CTR encryption/decryption are the same
const result = await this._ctr.encryptCtr(iv, sealed.subarray(Block.SIZE));

@@ -129,8 +124,7 @@ // Authenticate.

/** Make a best effort to wipe memory used by this AesSiv instance */
public clean(): this {
wipe(this._tmp1);
wipe(this._tmp2);
this._ctr.clean();
this._mac.clean();
this.tagLength = 0;
public clear(): this {
this._tmp1.clear();
this._tmp2.clear();
this._ctr.clear();
this._mac.clear();

@@ -148,3 +142,3 @@ return this;

this._mac.reset();
wipe(this._tmp1);
this._tmp1.clear();

@@ -155,5 +149,5 @@ // Note: the standalone S2V returns CMAC(1) if the number of passed

// if it's zero-length), so we omit this case.
await this._mac.update(this._tmp1);
wipe(this._tmp2);
this._tmp2 = await this._mac.finish();
await this._mac.update(this._tmp1.data);
this._tmp2.clear();
this._tmp2.data.set(await this._mac.finish());
this._mac.reset();

@@ -163,24 +157,33 @@

await this._mac.update(ad);
wipe(this._tmp1);
this._tmp1 = await this._mac.finish();
this._tmp1.clear();
this._tmp1.data.set(await this._mac.finish());
this._mac.reset();
dbl(this._tmp2, this._tmp2);
xor(this._tmp2, this._tmp1);
this._tmp2.dbl();
xor(this._tmp2.data, this._tmp1.data);
}
wipe(this._tmp1);
this._tmp1.clear();
if (plaintext.length >= this._mac.blockSize) {
const n = plaintext.length - this._mac.blockSize;
this._tmp1.set(plaintext.subarray(n));
if (plaintext.length >= Block.SIZE) {
const n = plaintext.length - Block.SIZE;
this._tmp1.data.set(plaintext.subarray(n));
await this._mac.update(plaintext.subarray(0, n));
} else {
this._tmp1.set(plaintext);
this._tmp1[plaintext.length] = 0x80;
dbl(this._tmp2, this._tmp2);
this._tmp1.data.set(plaintext);
this._tmp1.data[plaintext.length] = 0x80;
this._tmp2.dbl();
}
xor(this._tmp1, this._tmp2);
await this._mac.update(this._tmp1);
xor(this._tmp1.data, this._tmp2.data);
await this._mac.update(this._tmp1.data);
return this._mac.finish();
}
}
/** Zero out the top bits in the last 32-bit words of the IV */
function zeroIVBits(iv: Uint8Array) {
// "We zero-out the top bit in each of the last two 32-bit words
// of the IV before assigning it to Ctr"
// — http://web.cs.ucdavis.edu/~rogaway/papers/siv.pdf
iv[iv.length - 8] &= 0x7f;
iv[iv.length - 4] &= 0x7f;
}
/** Shared interfaces for cryptographic algorithms */
/** A cipher which provides a SIV-like interface and properties */
export interface ISivLike {
seal(plaintext: Uint8Array, associatedData: Uint8Array[]): Promise<Uint8Array>;
open(sealed: Uint8Array, associatedData: Uint8Array[]): Promise<Uint8Array>;
clean(): this;
import Block from "./block";
/**
* A block cipher (with 128-bit blocks, i.e. AES)
*
*
* WARNING: This interface should not be used directly!
* That is why it is hiding under internal.
*
* It should only be used to implement a cipher mode.
* This library uses it to implement AES-SIV.
*/
export interface IBlockCipher {
clear(): this;
/** Encrypt 16-byte block in-place, replacing its contents with ciphertext. */
encryptBlock(block: Block): Promise<this>;
}
/** A cipher which provides CTR (counter mode) encryption */
/**
* A backend which provides an implementation of cryptographic primitives
*/
export interface ICryptoProvider {
importAesKey(keyData: Uint8Array): Promise<IBlockCipher>;
importAesCtrKey(keyData: Uint8Array): Promise<ICtrLike>;
}
/**
* A cipher which provides CTR (counter mode) encryption
*/
export interface ICtrLike {
encrypt(iv: Uint8Array, plaintext: Uint8Array): Promise<Uint8Array>;
decrypt(iv: Uint8Array, ciphertext: Uint8Array): Promise<Uint8Array>;
clean(): this;
encryptCtr(iv: Uint8Array, plaintext: Uint8Array): Promise<Uint8Array>;
clear(): this;
}
/** An implementation of the CMAC message authentication code */
export interface ICmacLike {
blockSize: number;
digestLength: number;
/**
* An implementation of a message authentication code (MAC)
*/
export interface IMacLike {
reset(): this;
clean(): void;
clear(): void;
update(data: Uint8Array): Promise<this>;
finish(): Promise<Uint8Array>;
}
/**
* A cipher which provides a SIV-like interface and properties
*/
export interface ISivLike {
seal(plaintext: Uint8Array, associatedData: Uint8Array[]): Promise<Uint8Array>;
open(sealed: Uint8Array, associatedData: Uint8Array[]): Promise<Uint8Array>;
clear(): this;
}
// Copyright (C) 2016 Dmitry Chestnykh
// MIT License. See LICENSE file for details.
import Block from "../block";
import { ICtrLike } from "../interfaces";
import { wipe } from "../util";

@@ -19,4 +19,4 @@ import PolyfillAes from "./aes";

export default class PolyfillAesCtr implements ICtrLike {
private _counter: Uint8Array;
private _buffer: Uint8Array;
private _counter: Block;
private _buffer: Block;
private _cipher: PolyfillAes;

@@ -29,10 +29,17 @@

// Allocate space for counter.
this._counter = new Uint8Array(cipher.blockSize);
this._counter = new Block();
// Allocate buffer for encrypted block.
this._buffer = new Uint8Array(cipher.blockSize);
this._buffer = new Block();
}
public async encrypt(iv: Uint8Array, plaintext: Uint8Array): Promise<Uint8Array> {
if (iv.length !== this._counter.length) {
public clear(): this {
this._buffer.clear();
this._counter.clear();
this._cipher.clear();
return this;
}
public async encryptCtr(iv: Uint8Array, plaintext: Uint8Array): Promise<Uint8Array> {
if (iv.length !== Block.SIZE) {
throw new Error("CTR: iv length must be equal to cipher block size");

@@ -42,7 +49,7 @@ }

// Copy IV to counter, overwriting it.
this._counter.set(iv);
this._counter.data.set(iv);
// Set buffer position to length of buffer
// so that the first cipher block is generated.
let bufpos = this._buffer.length;
let bufferPos = Block.SIZE;

@@ -52,8 +59,9 @@ const result = new Uint8Array(plaintext.length);

for (let i = 0; i < plaintext.length; i++) {
if (bufpos === this._buffer.length) {
this._cipher.encryptBlock(this._counter, this._buffer);
bufpos = 0;
if (bufferPos === Block.SIZE) {
this._buffer.copy(this._counter);
this._cipher.encryptBlock(this._buffer);
bufferPos = 0;
incrementCounter(this._counter);
}
result[i] = plaintext[i] ^ this._buffer[bufpos++];
result[i] = plaintext[i] ^ this._buffer.data[bufferPos++];
}

@@ -63,28 +71,13 @@

}
public async decrypt(iv: Uint8Array, ciphertext: Uint8Array): Promise<Uint8Array> {
// AES-CTR decryption is identical to encryption
return this.encrypt(iv, ciphertext);
}
public clean(): this {
wipe(this._buffer);
wipe(this._counter);
this._cipher.clean();
return this;
}
}
function incrementCounter(counter: Uint8Array) {
// Increment an AES-CTR mode counter, intentionally wrapping/overflowing
function incrementCounter(counter: Block) {
let carry = 1;
for (let i = counter.length - 1; i >= 0; i--) {
carry += (counter[i] & 0xff) | 0;
counter[i] = carry & 0xff;
for (let i = Block.SIZE - 1; i >= 0; i--) {
carry += (counter.data[i] & 0xff) | 0;
counter.data[i] = carry & 0xff;
carry >>>= 8;
}
if (carry > 0) {
throw new Error("CTR: counter overflow");
}
}

@@ -1,2 +0,2 @@

// Copyright (C) 2016 Dmitry Chestnykh
// Copyright (C) 2016-2017 Dmitry Chestnykh, Tony Arcieri
// MIT License. See LICENSE file for details.

@@ -14,3 +14,5 @@

import { wipe } from "../util";
import Block from "../block";
import { IBlockCipher } from "../interfaces";
import { wipe } from "../util/wipe";

@@ -76,2 +78,125 @@ // Powers of x mod poly in GF(2).

/**
* Polyfill for the AES block cipher.
*
* This implementation uses lookup tables, so it's susceptible to cache-timing
* side-channel attacks. A constant-time version we tried was super slow (a few
* kilobytes per second), so we'll have to live with it.
*
* Key size: 16 or 32 bytes, block size: 16 bytes.
*/
export default class PolyfillAes implements IBlockCipher {
// Expanded encryption key.
private _encKey: Uint32Array;
// A placeholder promise we always return to match the WebCrypto API
private _emptyPromise: Promise<this>;
/**
* Constructs AES with the given 16 or 32-byte key
* for AES-128 or AES-256.
*/
constructor(keyData: Uint8Array) {
if (!isInitialized) {
initialize();
}
// Only AES-128 and AES-256 supported. AES-192 is not.
if (keyData.length !== 16 && keyData.length !== 32) {
throw new Error(`Miscreant: invalid key length: ${keyData.length} (expected 16 or 32 bytes)`);
}
this._encKey = expandKey(keyData);
this._emptyPromise = Promise.resolve(this);
}
/**
* Cleans expanded keys from memory, setting them to zeros.
*/
public clear(): this {
if (this._encKey) {
wipe(this._encKey);
}
return this;
}
/**
* Encrypt 16-byte block in-place, replacing its contents with ciphertext.
*
* This function should not be used to encrypt data without any
* cipher mode! It should only be used to implement a cipher mode.
* This library uses it to implement AES-SIV.
*/
public encryptBlock(block: Block): Promise<this> {
const src = block.data;
const dst = block.data;
let s0 = readUint32BE(src, 0);
let s1 = readUint32BE(src, 4);
let s2 = readUint32BE(src, 8);
let s3 = readUint32BE(src, 12);
// First round just XORs input with key.
s0 ^= this._encKey[0];
s1 ^= this._encKey[1];
s2 ^= this._encKey[2];
s3 ^= this._encKey[3];
let t0 = 0;
let t1 = 0;
let t2 = 0;
let t3 = 0;
// Middle rounds shuffle using tables.
// Number of rounds is set by length of expanded key.
const nr = this._encKey.length / 4 - 2; // - 2: one above, one more below
let k = 4;
for (let r = 0; r < nr; r++) {
t0 = this._encKey[k + 0] ^ Te0[(s0 >>> 24) & 0xff] ^ Te1[(s1 >>> 16) & 0xff] ^
Te2[(s2 >>> 8) & 0xff] ^ Te3[s3 & 0xff];
t1 = this._encKey[k + 1] ^ Te0[(s1 >>> 24) & 0xff] ^ Te1[(s2 >>> 16) & 0xff] ^
Te2[(s3 >>> 8) & 0xff] ^ Te3[s0 & 0xff];
t2 = this._encKey[k + 2] ^ Te0[(s2 >>> 24) & 0xff] ^ Te1[(s3 >>> 16) & 0xff] ^
Te2[(s0 >>> 8) & 0xff] ^ Te3[s1 & 0xff];
t3 = this._encKey[k + 3] ^ Te0[(s3 >>> 24) & 0xff] ^ Te1[(s0 >>> 16) & 0xff] ^
Te2[(s1 >>> 8) & 0xff] ^ Te3[s2 & 0xff];
k += 4;
s0 = t0;
s1 = t1;
s2 = t2;
s3 = t3;
}
// Last round uses s-box directly and XORs to produce output.
s0 = (SBOX0[t0 >>> 24] << 24) | (SBOX0[(t1 >>> 16) & 0xff]) << 16 |
(SBOX0[(t2 >>> 8) & 0xff]) << 8 | (SBOX0[t3 & 0xff]);
s1 = (SBOX0[t1 >>> 24] << 24) | (SBOX0[(t2 >>> 16) & 0xff]) << 16 |
(SBOX0[(t3 >>> 8) & 0xff]) << 8 | (SBOX0[t0 & 0xff]);
s2 = (SBOX0[t2 >>> 24] << 24) | (SBOX0[(t3 >>> 16) & 0xff]) << 16 |
(SBOX0[(t0 >>> 8) & 0xff]) << 8 | (SBOX0[t1 & 0xff]);
s3 = (SBOX0[t3 >>> 24] << 24) | (SBOX0[(t0 >>> 16) & 0xff]) << 16 |
(SBOX0[(t1 >>> 8) & 0xff]) << 8 | (SBOX0[t2 & 0xff]);
s0 ^= this._encKey[k + 0];
s1 ^= this._encKey[k + 1];
s2 ^= this._encKey[k + 2];
s3 ^= this._encKey[k + 3];
writeUint32BE(s0, dst, 0);
writeUint32BE(s1, dst, 4);
writeUint32BE(s2, dst, 8);
writeUint32BE(s3, dst, 12);
return this._emptyPromise;
}
}
// Initialize generates encryption and decryption tables.

@@ -160,111 +285,2 @@ function initialize() {

/**
* Polyfill for the AES block cipher.
*
* This implementation uses lookup tables, so it's susceptible to cache-timing
* side-channel attacks. A constant-time version we tried was super slow (a few
* kilobytes per second), so we'll have to live with it.
*
* Key size: 16, 24 or 32 bytes, block size: 16 bytes.
*/
export default class PolyfillAes {
// AES block size in bytes.
public readonly blockSize = 16;
// Key byte length.
private _keyLen: number;
// Expanded encryption key.
private _encKey: Uint32Array;
// Expanded decryption key. May be undefined if instance
// was created "noDecryption" option set to true.
private _decKey: Uint32Array | undefined;
/**
* Constructs AES with the given 16, 24 or 32-byte key
* for AES-128, AES-192, or AES-256.
*
* If noDecryption is true, decryption key will not expanded,
* saving time and memory for cipher modes when decryption
* is not used (such as AES-CTR).
*
*/
constructor(key: Uint8Array, noDecryption = false) {
if (!isInitialized) {
initialize();
}
this._keyLen = key.length;
this.setKey(key, noDecryption);
}
/**
* Re-initializes this instance with the new key.
*
* This is helpful to avoid allocations.
*/
public setKey(key: Uint8Array, noDecryption = false): this {
if (key.length !== 16 && key.length !== 24 && key.length !== 32) {
throw new Error("AES: wrong key size (must be 16, 24 or 32)");
}
if (this._keyLen !== key.length) {
throw new Error("AES: initialized with different key size");
}
// If we haven't yet, allocate space for expanded keys.
if (!this._encKey) {
this._encKey = new Uint32Array(key.length + 28);
}
if (noDecryption) {
// Wipe decryption key, as we no longer need it.
if (this._decKey) {
wipe(this._decKey);
}
} else {
if (!this._decKey) {
this._decKey = new Uint32Array(key.length + 28);
}
}
expandKey(key, this._encKey, this._decKey);
return this;
}
/**
* Cleans expanded keys from memory, setting them to zeros.
*/
public clean(): this {
if (this._encKey) {
wipe(this._encKey);
}
if (this._decKey) {
wipe(this._decKey);
}
return this;
}
// TODO(dchest): specify if blocks can be the same array.
/**
* Encrypt 16-byte block src into 16-byte block dst.
*
* This function should not be used to encrypt data without any
* cipher mode! It should only be used to implement a cipher mode.
* This library uses it to implement AES-SIV.
*/
public encryptBlock(src: Uint8Array, dst: Uint8Array): this {
// Check block lengths.
if (src.length < this.blockSize) {
throw new Error("AES: source block too small");
}
if (dst.length < this.blockSize) {
throw new Error("AES: destination block too small");
}
// Encrypt block.
encryptBlock(this._encKey, src, dst);
return this;
}
}
// Apply sbox0 to each byte in w.

@@ -283,10 +299,14 @@ function subw(w: number): number {

function expandKey(key: Uint8Array, encKey: Uint32Array, decKey?: Uint32Array): void {
function expandKey(key: Uint8Array): Uint32Array {
const encKey = new Uint32Array(key.length + 28);
const nk = key.length / 4 | 0;
const n = encKey.length;
for (let i = 0; i < nk; i++) {
encKey[i] = readUint32BE(key, i * 4);
}
for (let i = nk; i < n; i++) {
let t = encKey[i - 1];
if (i % nk === 0) {

@@ -297,153 +317,7 @@ t = subw(rotw(t)) ^ (POWX[i / nk - 1] << 24);

}
encKey[i] = encKey[i - nk] ^ t;
}
if (decKey) {
// Derive decryption key from encryption key.
// Reverse the 4-word round key sets from enc to produce dec.
// All sets but the first and last get the MixColumn transform applied.
for (let i = 0; i < n; i += 4) {
const ei = n - i - 4;
for (let j = 0; j < 4; j++) {
let x = encKey[ei + j];
if (i > 0 && i + 4 < n) {
x = Td0[SBOX0[(x >>> 24) & 0xff]] ^ Td1[SBOX0[(x >>> 16) & 0xff]] ^
Td2[SBOX0[(x >>> 8) & 0xff]] ^ Td3[SBOX0[x & 0xff]];
}
decKey[i + j] = x;
}
}
}
return encKey;
}
function encryptBlock(xk: Uint32Array, src: Uint8Array, dst: Uint8Array): void {
let s0 = readUint32BE(src, 0);
let s1 = readUint32BE(src, 4);
let s2 = readUint32BE(src, 8);
let s3 = readUint32BE(src, 12);
// First round just XORs input with key.
s0 ^= xk[0];
s1 ^= xk[1];
s2 ^= xk[2];
s3 ^= xk[3];
let t0 = 0;
let t1 = 0;
let t2 = 0;
let t3 = 0;
// Middle rounds shuffle using tables.
// Number of rounds is set by length of expanded key.
const nr = xk.length / 4 - 2; // - 2: one above, one more below
let k = 4;
for (let r = 0; r < nr; r++) {
t0 = xk[k + 0] ^ Te0[(s0 >>> 24) & 0xff] ^ Te1[(s1 >>> 16) & 0xff] ^
Te2[(s2 >>> 8) & 0xff] ^ Te3[s3 & 0xff];
t1 = xk[k + 1] ^ Te0[(s1 >>> 24) & 0xff] ^ Te1[(s2 >>> 16) & 0xff] ^
Te2[(s3 >>> 8) & 0xff] ^ Te3[s0 & 0xff];
t2 = xk[k + 2] ^ Te0[(s2 >>> 24) & 0xff] ^ Te1[(s3 >>> 16) & 0xff] ^
Te2[(s0 >>> 8) & 0xff] ^ Te3[s1 & 0xff];
t3 = xk[k + 3] ^ Te0[(s3 >>> 24) & 0xff] ^ Te1[(s0 >>> 16) & 0xff] ^
Te2[(s1 >>> 8) & 0xff] ^ Te3[s2 & 0xff];
k += 4;
s0 = t0;
s1 = t1;
s2 = t2;
s3 = t3;
}
// Last round uses s-box directly and XORs to produce output.
s0 = (SBOX0[t0 >>> 24] << 24) | (SBOX0[(t1 >>> 16) & 0xff]) << 16 |
(SBOX0[(t2 >>> 8) & 0xff]) << 8 | (SBOX0[t3 & 0xff]);
s1 = (SBOX0[t1 >>> 24] << 24) | (SBOX0[(t2 >>> 16) & 0xff]) << 16 |
(SBOX0[(t3 >>> 8) & 0xff]) << 8 | (SBOX0[t0 & 0xff]);
s2 = (SBOX0[t2 >>> 24] << 24) | (SBOX0[(t3 >>> 16) & 0xff]) << 16 |
(SBOX0[(t0 >>> 8) & 0xff]) << 8 | (SBOX0[t1 & 0xff]);
s3 = (SBOX0[t3 >>> 24] << 24) | (SBOX0[(t0 >>> 16) & 0xff]) << 16 |
(SBOX0[(t1 >>> 8) & 0xff]) << 8 | (SBOX0[t2 & 0xff]);
s0 ^= xk[k + 0];
s1 ^= xk[k + 1];
s2 ^= xk[k + 2];
s3 ^= xk[k + 3];
writeUint32BE(s0, dst, 0);
writeUint32BE(s1, dst, 4);
writeUint32BE(s2, dst, 8);
writeUint32BE(s3, dst, 12);
}
function decryptBlock(xk: Uint32Array, src: Uint8Array, dst: Uint8Array): void {
let s0 = readUint32BE(src, 0);
let s1 = readUint32BE(src, 4);
let s2 = readUint32BE(src, 8);
let s3 = readUint32BE(src, 12);
// First round just XORs input with key.
s0 ^= xk[0];
s1 ^= xk[1];
s2 ^= xk[2];
s3 ^= xk[3];
let t0 = 0;
let t1 = 0;
let t2 = 0;
let t3 = 0;
// Middle rounds shuffle using tables.
// Number of rounds is set by length of expanded key.
const nr = xk.length / 4 - 2; // - 2: one above, one more below
let k = 4;
for (let r = 0; r < nr; r++) {
t0 = xk[k + 0] ^ Td0[(s0 >>> 24) & 0xff] ^ Td1[(s3 >>> 16) & 0xff] ^
Td2[(s2 >>> 8) & 0xff] ^ Td3[s1 & 0xff];
t1 = xk[k + 1] ^ Td0[(s1 >>> 24) & 0xff] ^ Td1[(s0 >>> 16) & 0xff] ^
Td2[(s3 >>> 8) & 0xff] ^ Td3[s2 & 0xff];
t2 = xk[k + 2] ^ Td0[(s2 >>> 24) & 0xff] ^ Td1[(s1 >>> 16) & 0xff] ^
Td2[(s0 >>> 8) & 0xff] ^ Td3[s3 & 0xff];
t3 = xk[k + 3] ^ Td0[(s3 >>> 24) & 0xff] ^ Td1[(s2 >>> 16) & 0xff] ^
Td2[(s1 >>> 8) & 0xff] ^ Td3[s0 & 0xff];
k += 4;
s0 = t0;
s1 = t1;
s2 = t2;
s3 = t3;
}
// Last round uses s-box directly and XORs to produce output.
s0 = (SBOX1[t0 >>> 24] << 24) | (SBOX1[(t3 >>> 16) & 0xff]) << 16 |
(SBOX1[(t2 >>> 8) & 0xff]) << 8 | (SBOX1[t1 & 0xff]);
s1 = (SBOX1[t1 >>> 24] << 24) | (SBOX1[(t0 >>> 16) & 0xff]) << 16 |
(SBOX1[(t3 >>> 8) & 0xff]) << 8 | (SBOX1[t2 & 0xff]);
s2 = (SBOX1[t2 >>> 24] << 24) | (SBOX1[(t1 >>> 16) & 0xff]) << 16 |
(SBOX1[(t0 >>> 8) & 0xff]) << 8 | (SBOX1[t3 & 0xff]);
s3 = (SBOX1[t3 >>> 24] << 24) | (SBOX1[(t2 >>> 16) & 0xff]) << 16 |
(SBOX1[(t1 >>> 8) & 0xff]) << 8 | (SBOX1[t0 & 0xff]);
s0 ^= xk[k + 0];
s1 ^= xk[k + 1];
s2 ^= xk[k + 2];
s3 ^= xk[k + 3];
writeUint32BE(s0, dst, 0);
writeUint32BE(s1, dst, 4);
writeUint32BE(s2, dst, 8);
writeUint32BE(s3, dst, 12);
}
import { ICtrLike } from "../interfaces";
import { defaultCryptoProvider } from "../util";
/** AES-CTR using a WebCrypto (or similar) API */
/**
* AES-CTR using a WebCrypto (or similar) API
*/
export default class WebCryptoAesCtr implements ICtrLike {
public static async importKey(keyData: Uint8Array, crypto = defaultCryptoProvider()): Promise<WebCryptoAesCtr> {
public static async importKey(crypto: Crypto, keyData: Uint8Array): Promise<WebCryptoAesCtr> {
// Only AES-128 and AES-256 supported. AES-192 is not.
if (keyData.length !== 16 && keyData.length !== 32) {
throw new Error(`invalid key ${keyData.length} (expected 16 or 32 bytes)`);
throw new Error(`Miscreant: invalid key length: ${keyData.length} (expected 16 or 32 bytes)`);
}

@@ -18,6 +19,6 @@

readonly key: CryptoKey,
readonly crypto = defaultCryptoProvider(),
readonly crypto: Crypto,
) { }
public async encrypt(iv: Uint8Array, plaintext: Uint8Array): Promise<Uint8Array> {
public async encryptCtr(iv: Uint8Array, plaintext: Uint8Array): Promise<Uint8Array> {
const ciphertext = await this.crypto.subtle.encrypt(

@@ -32,11 +33,6 @@ { name: "AES-CTR", counter: iv, length: 16 },

public async decrypt(iv: Uint8Array, ciphertext: Uint8Array): Promise<Uint8Array> {
// AES-CTR decryption is identical to encryption
return this.encrypt(iv, ciphertext);
}
public clean(): this {
// TODO: actually clean something. Do we need to?
public clear(): this {
// TODO: actually clear something. Do we need to?
return this;
}
}
/** miscreant.ts: Main entry point to the Miscreant library */
import { ISivLike } from "./internal/interfaces";
import { defaultCryptoProvider } from "./internal/util";
import NotImplementedError from "./exceptions/not_implemented_error";
import { ICryptoProvider, ISivLike } from "./internal/interfaces";
import AesSiv from "./internal/aes_siv";
import PolyfillCrypto from "./internal/polyfill";
import PolyfillCryptoProvider from "./internal/polyfill/provider";
import WebCryptoProvider from "./internal/webcrypto/provider";

@@ -15,21 +16,37 @@ /** Miscreant: A misuse-resistant symmetric encryption library */

alg: string,
crypto: Crypto | PolyfillCrypto = defaultCryptoProvider(),
provider: ICryptoProvider = Miscreant.webCryptoProvider(),
): Promise<ISivLike> {
if (alg === "AES-SIV") {
return AesSiv.importKey(keyData, crypto);
} else {
throw new Error(`unsupported algorithm: ${alg}`);
}
return AesSiv.importKey(provider, alg, keyData);
}
/** Obtain a cryptographic provider */
public static getCryptoProvider(providerName = "default"): Crypto | PolyfillCrypto {
if (providerName === "default") {
return defaultCryptoProvider();
} else if (providerName === "polyfill") {
return new PolyfillCrypto();
} else {
throw new Error(`unsupported provider: ${providerName}`);
/**
* Autodetect and return the default WebCrypto provider for this environment.
*
* Cryptography providers returned by this function should implement
* cryptography natively and not rely on JavaScript polyfills.
*/
public static webCryptoProvider(crypto: Crypto = window.crypto): WebCryptoProvider {
try {
return new WebCryptoProvider(crypto);
} catch (e) {
// Handle the case where window is undefined because we're not in a browser
if (e instanceof ReferenceError) {
throw new NotImplementedError("Miscreant: window.crypto unavailable in this environment");
} else {
throw e;
}
}
}
/**
* Obtain a polyfill cryptographic provider
*
* WARNING: The polyfill implementation is not constant-time and may have
* potentially severe security issues, including leaking secret keys!
*
* Please use the Web Crypto provider if at all possible.
*/
public static polyfillCryptoProvider(): PolyfillCryptoProvider {
return new PolyfillCryptoProvider();
}
}

@@ -9,7 +9,6 @@ // Copyright (C) 2016 Dmitry Chestnykh

import WebCrypto = require("node-webcrypto-ossl");
import PolyfillCryptoProvider from "../src/internal/polyfill/provider";
import WebCryptoProvider from "../src/internal/webcrypto/provider";
import Cmac from "../src/internal/mac/cmac";
import PolyfillAes from "../src/internal/polyfill/aes";
import PolyfillAesCmac from "../src/internal/polyfill/aes_cmac";
import WebCryptoAesCmac from "../src/internal/webcrypto/aes_cmac";
@suite class PolyfillAesCmacSpec {

@@ -23,4 +22,6 @@ static vectors: AesCmacExample[];

@test async "passes the AES-CMAC test vectors"() {
const polyfillProvider = new PolyfillCryptoProvider();
for (let v of PolyfillAesCmacSpec.vectors) {
const mac = new PolyfillAesCmac(new PolyfillAes(v.key));
const mac = await Cmac.importKey(polyfillProvider, v.key);
await mac.update(v.message);

@@ -40,4 +41,6 @@ expect(await mac.finish()).to.eql(v.tag);

@test async "passes the AES-CMAC test vectors"() {
const webCryptoProvider = new WebCryptoProvider(new WebCrypto());
for (let v of PolyfillAesCmacSpec.vectors) {
const mac = await WebCryptoAesCmac.importKey(v.key, new WebCrypto());
const mac = await Cmac.importKey(webCryptoProvider, v.key);
await mac.update(v.message);

@@ -44,0 +47,0 @@ expect(await mac.finish()).to.eql(v.tag);

@@ -24,3 +24,3 @@ // Copyright (C) 2016 Dmitry Chestnykh

const ctrPolyfill = new PolyfillAesCtr(new PolyfillAes(v.key));
let ciphertext = await ctrPolyfill.encrypt(v.iv, v.plaintext);
let ciphertext = await ctrPolyfill.encryptCtr(v.iv, v.plaintext);
expect(ciphertext).to.eql(v.ciphertext);

@@ -40,4 +40,4 @@ }

for (let v of WebCryptoAesCtrSpec.vectors) {
const ctrNative = await WebCryptoAesCtr.importKey(v.key, new WebCrypto());
let ciphertext = await ctrNative.encrypt(v.iv, v.plaintext);
const ctrNative = await WebCryptoAesCtr.importKey(new WebCrypto(), v.key);
let ciphertext = await ctrNative.encryptCtr(v.iv, v.plaintext);
expect(ciphertext).to.eql(v.ciphertext);

@@ -44,0 +44,0 @@ }

@@ -10,6 +10,7 @@ // Copyright (C) 2017 Dmitry Chestnykh

import WebCrypto = require("node-webcrypto-ossl");
import PolyfillCryptoProvider from "../src/internal/polyfill/provider";
import WebCryptoProvider from "../src/internal/webcrypto/provider";
import AesSiv from "../src/internal/aes_siv";
import PolyfillCrypto from "../src/internal/polyfill";
import IntegrityError from "../src/internal/exceptions/integrity_error";
import IntegrityError from "../src/exceptions/integrity_error";

@@ -27,4 +28,6 @@ let expect = chai.expect;

@test async "should correctly seal and open with polyfill cipher implementations"() {
const polyfillProvider = new PolyfillCryptoProvider();
for (let v of AesSivSpec.vectors) {
const siv = await AesSiv.importKey(v.key, new PolyfillCrypto());
const siv = await AesSiv.importKey(polyfillProvider, "AES-SIV", v.key);
const sealed = await siv.seal(v.plaintext, v.ad);

@@ -36,3 +39,3 @@ expect(sealed).to.eql(v.ciphertext);

expect(unsealed!).to.eql(v.plaintext);
expect(() => siv.clean()).not.to.throw();
expect(() => siv.clear()).not.to.throw();
}

@@ -42,4 +45,6 @@ }

@test async "should correctly seal and open with WebCrypto cipher implementations"() {
const webCryptoProvider = new WebCryptoProvider(new WebCrypto());
for (let v of AesSivSpec.vectors) {
const siv = await AesSiv.importKey(v.key, new WebCrypto());
const siv = await AesSiv.importKey(webCryptoProvider, "AES-SIV", v.key);
const sealed = await siv.seal(v.plaintext, v.ad);

@@ -51,3 +56,3 @@ expect(sealed).to.eql(v.ciphertext);

expect(unsealed!).to.eql(v.plaintext);
expect(() => siv.clean()).not.to.throw();
expect(() => siv.clear()).not.to.throw();
}

@@ -57,2 +62,4 @@ }

@test async "should correctly seal and open different plaintext under the same key"() {
const polyfillProvider = new PolyfillCryptoProvider();
const key = byteSeq(64);

@@ -65,3 +72,3 @@ const ad1 = [byteSeq(32), byteSeq(10)];

const siv = await AesSiv.importKey(key, new PolyfillCrypto());
const siv = await AesSiv.importKey(polyfillProvider, "AES-SIV", key);

@@ -78,6 +85,8 @@ const sealed1 = await siv.seal(pt1, ad1);

expect(() => siv.clean()).not.to.throw();
expect(() => siv.clear()).not.to.throw();
}
@test async "should not open with incorrect key"() {
const polyfillProvider = new PolyfillCryptoProvider();
for (let v of AesSivSpec.vectors) {

@@ -89,3 +98,3 @@ const badKey = v.key;

const siv = await AesSiv.importKey(badKey, new PolyfillCrypto());
const siv = await AesSiv.importKey(polyfillProvider, "AES-SIV", badKey);
expect(siv.open(v.ciphertext, v.ad)).to.be.rejectedWith(IntegrityError);

@@ -96,2 +105,4 @@ }

@test async "should not open with incorrect associated data"() {
const polyfillProvider = new PolyfillCryptoProvider();
for (let v of AesSivSpec.vectors) {

@@ -101,3 +112,3 @@ const badAd = v.ad;

const siv = await AesSiv.importKey(v.key, new PolyfillCrypto());
const siv = await AesSiv.importKey(polyfillProvider, "AES-SIV", v.key);
return expect(siv.open(v.ciphertext, badAd)).to.be.rejectedWith(IntegrityError);

@@ -108,2 +119,4 @@ }

@test async "should not open with incorrect ciphertext"() {
const polyfillProvider = new PolyfillCryptoProvider();
for (let v of AesSivSpec.vectors) {

@@ -115,3 +128,3 @@ const badOutput = v.ciphertext;

const siv = await AesSiv.importKey(v.key, new PolyfillCrypto());
const siv = await AesSiv.importKey(polyfillProvider, "AES-SIV", v.key);
return expect(siv.open(badOutput, v.ad)).to.be.rejectedWith(IntegrityError);

@@ -118,0 +131,0 @@ }

@@ -1,10 +0,17 @@

// Copyright (C) 2016 Dmitry Chestnykh
// Copyright (C) 2016-2017 Dmitry Chestnykh, Tony Arcieri
// MIT License. See LICENSE file for details.
import { suite, test } from "mocha-typescript";
import { expect } from "chai";
import * as chai from "chai";
import * as chaiAsPromised from "chai-as-promised";
import { AesExample } from "./support/test_vectors";
import Block from "../src/internal/block";
import WebCrypto = require("node-webcrypto-ossl");
import WebCryptoAes from "../src/internal/webcrypto/aes";
import PolyfillAes from "../src/internal/polyfill/aes";
let expect = chai.expect;
chai.use(chaiAsPromised);
@suite class PolyfillAesSpec {

@@ -18,16 +25,12 @@ static vectors: AesExample[];

@test "should not accept wrong key length"() {
expect(() => new PolyfillAes(new Uint8Array(10))).to.throw(/^AES/);
expect(() => new PolyfillAes(new Uint8Array(10))).to.throw(/invalid key length/);
}
@test "should not accept different key in setKey()"() {
const cipher = new PolyfillAes(new Uint8Array(32));
expect(() => cipher.setKey(new Uint8Array(16))).to.throw(/^AES/);
}
@test "should correctly encrypt block"() {
@test "should correctly encrypt blocks"() {
for (let v of PolyfillAesSpec.vectors) {
const cipher = new PolyfillAes(v.key);
const dst = new Uint8Array(16);
cipher.encryptBlock(v.src, dst);
expect(dst).to.eql(v.dst);
const block = new Block();
block.data.set(v.src);
cipher.encryptBlock(block);
expect(block.data).to.eql(v.dst);
}

@@ -38,3 +41,3 @@ }

let key = new Uint8Array(32);
let block = new Uint8Array(16);
let block = new Block();
const newKey = new Uint8Array(32);

@@ -44,6 +47,6 @@ for (let i = 0; i < 100; i++) {

for (let j = 0; j < 100; j++) {
cipher.encryptBlock(block, block);
cipher.encryptBlock(block);
}
newKey.set(key.subarray(16, 32)); // move 16 bytes to left
newKey.set(block, 16); // fill the rest 16 bytes with block
newKey.set(block.data, 16); // fill the rest 16 bytes with block
key.set(newKey);

@@ -53,4 +56,29 @@ }

let expected = new Uint8Array([58, 111, 217, 50, 246, 8, 131, 95, 31, 86, 217, 220, 31, 206, 207, 163]);
expect(block).to.eql(expected);
expect(block.data).to.eql(expected);
}
}
@suite class WebCryptoAesSpec {
static vectors: AesExample[];
static async before() {
this.vectors = await AesExample.loadAll();
}
@test "should not accept wrong key length"() {
const crypto = new WebCrypto();
expect(WebCryptoAes.importKey(crypto, new Uint8Array(10))).to.be.rejectedWith(Error);
}
@test async "should correctly encrypt blocks"() {
const crypto = new WebCrypto();
for (let v of WebCryptoAesSpec.vectors) {
const cipher = await WebCryptoAes.importKey(crypto, v.key);
const block = new Block();
block.data.set(v.src);
await cipher.encryptBlock(block);
expect(block.data).to.eql(v.dst);
}
}
}

@@ -6,3 +6,3 @@ // Copyright (C) 2016 Dmitry Chestnykh

import { expect } from "chai";
import { select, compare, equal } from "../src/internal/constant-time";
import { select, compare, equal } from "../src/internal/util/constant-time";

@@ -9,0 +9,0 @@ @suite class SelectSpec {

@@ -6,3 +6,4 @@ // Copyright (C) 2017 Dmitry Chestnykh

import { expect } from "chai";
import { AesSivExample } from "./support/test_vectors";
import { AesSivExample, AesPmacSivExample } from "./support/test_vectors";
import WebCryptoProvider from "../src/internal/webcrypto/provider";

@@ -13,3 +14,3 @@ import WebCrypto = require("node-webcrypto-ossl");

@suite class SivSpec {
@suite class MiscreantAesSivSpec {
static vectors: AesSivExample[];

@@ -21,5 +22,21 @@

@test async "AES-SIV: should correctly seal and open with PolyfillCrypto"() {
const polyfillProvider = Miscreant.polyfillCryptoProvider();
for (let v of MiscreantAesSivSpec.vectors) {
const siv = await Miscreant.importKey(v.key, "AES-SIV", polyfillProvider);
const sealed = await siv.seal(v.plaintext, v.ad);
expect(sealed).to.eql(v.ciphertext);
const unsealed = await siv.open(sealed, v.ad);
expect(unsealed).not.to.be.null;
expect(unsealed!).to.eql(v.plaintext);
expect(() => siv.clear()).not.to.throw();
}
}
@test async "AES-SIV: should correctly seal and open with WebCrypto"() {
for (let v of SivSpec.vectors) {
const siv = await Miscreant.importKey(v.key, "AES-SIV", new WebCrypto());
const webCryptoProvider = new WebCryptoProvider(new WebCrypto());
for (let v of MiscreantAesSivSpec.vectors) {
const siv = await Miscreant.importKey(v.key, "AES-SIV", webCryptoProvider);
const sealed = await siv.seal(v.plaintext, v.ad);

@@ -31,9 +48,18 @@ expect(sealed).to.eql(v.ciphertext);

expect(unsealed!).to.eql(v.plaintext);
expect(() => siv.clean()).not.to.throw();
expect(() => siv.clear()).not.to.throw();
}
}
}
@test async "AES-SIV: should correctly seal and open with PolyfillCrypto"() {
for (let v of SivSpec.vectors) {
const siv = await Miscreant.importKey(v.key, "AES-SIV", Miscreant.getCryptoProvider("polyfill"));
@suite class MiscreantAesPmacSivSpec {
static vectors: AesPmacSivExample[];
static async before() {
this.vectors = await AesPmacSivExample.loadAll();
}
@test async "AES-PMAC-SIV: should correctly seal and open with PolyfillCrypto"() {
const polyfillProvider = Miscreant.polyfillCryptoProvider();
for (let v of MiscreantAesPmacSivSpec.vectors) {
const siv = await Miscreant.importKey(v.key, "AES-PMAC-SIV", polyfillProvider);
const sealed = await siv.seal(v.plaintext, v.ad);

@@ -45,5 +71,20 @@ expect(sealed).to.eql(v.ciphertext);

expect(unsealed!).to.eql(v.plaintext);
expect(() => siv.clean()).not.to.throw();
expect(() => siv.clear()).not.to.throw();
}
}
@test async "AES-PMAC-SIV: should correctly seal and open with WebCrypto"() {
const webCryptoProvider = new WebCryptoProvider(new WebCrypto());
for (let v of MiscreantAesPmacSivSpec.vectors) {
const siv = await Miscreant.importKey(v.key, "AES-PMAC-SIV", webCryptoProvider);
const sealed = await siv.seal(v.plaintext, v.ad);
expect(sealed).to.eql(v.ciphertext);
const unsealed = await siv.open(sealed, v.ad);
expect(unsealed).not.to.be.null;
expect(unsealed!).to.eql(v.plaintext);
expect(() => siv.clear()).not.to.throw();
}
}
}

@@ -27,2 +27,25 @@ import * as fs from "async-file";

/** AES-PMAC-SIV test vectors */
export class AesPmacSivExample {
static readonly DEFAULT_EXAMPLES_PATH = "../vectors/aes_pmac_siv.tjson";
public readonly name: string;
public readonly key: Uint8Array;
public readonly ad: Uint8Array[];
public readonly plaintext: Uint8Array;
public readonly ciphertext: Uint8Array;
static async loadAll(): Promise<AesPmacSivExample[]> {
return AesPmacSivExample.loadFromFile(AesPmacSivExample.DEFAULT_EXAMPLES_PATH);
}
static async loadFromFile(filename: string): Promise<AesPmacSivExample[]> {
let tjson = TJSON.parse(await fs.readFile(filename, "utf8"));
return tjson["examples"].map((ex: any) => {
let obj = Object.create(AesPmacSivExample.prototype);
return Object.assign(obj, ex);
});
}
}
/** AES (raw block function) test vectors */

@@ -92,2 +115,23 @@ export class AesExample {

/** AES-PMAC test vectors */
export class AesPmacExample {
static readonly DEFAULT_EXAMPLES_PATH = "../vectors/aes_pmac.tjson";
public readonly key: Uint8Array;
public readonly message: Uint8Array;
public readonly tag: Uint8Array;
static async loadAll(): Promise<AesPmacExample[]> {
return AesPmacExample.loadFromFile(AesPmacExample.DEFAULT_EXAMPLES_PATH);
}
static async loadFromFile(filename: string): Promise<AesPmacExample[]> {
let tjson = TJSON.parse(await fs.readFile(filename, "utf8"));
return tjson["examples"].map((ex: any) => {
let obj = Object.create(AesPmacExample.prototype);
return Object.assign(obj, ex);
});
}
}
/** dbl() test vectors */

@@ -94,0 +138,0 @@ export class DblExample {

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc