Comparing version 0.2.0 to 0.3.0
{ | ||
"name": "miscreant", | ||
"version": "0.2.0", | ||
"description": "Misuse resistant symmetric encryption using the AES-SIV (RFC 5297) and CHAIN/STREAM constructions", | ||
"version": "0.3.0", | ||
"description": "Misuse resistant symmetric encryption library providing AES-SIV (RFC 5297), AES-PMAC-SIV, and STREAM constructions", | ||
"homepage": "https://github.com/miscreant/miscreant/tree/master/js/", | ||
@@ -6,0 +6,0 @@ "main": "index.js", |
500
README.md
@@ -17,6 +17,12 @@ # 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] | ||
JavaScript-compatible TypeScript implementation of **Miscreant**: | ||
Advanced symmetric encryption using the [AES-SIV] ([RFC 5297]) and [CHAIN/STREAM] | ||
constructions, providing easy-to-use (or rather, hard-to-misuse) encryption of | ||
individual messages or message streams. | ||
Advanced symmetric encryption library which provides the [AES-SIV] ([RFC 5297]), | ||
[AES-PMAC-SIV], and [STREAM] constructions. These algorithms are easy-to-use | ||
(or rather, hard-to-misuse) and support encryption of individual messages or | ||
message streams. | ||
[AES-SIV]: https://github.com/miscreant/miscreant/wiki/AES-SIV | ||
[RFC 5297]: https://tools.ietf.org/html/rfc5297 | ||
[AES-PMAC-SIV]: https://github.com/miscreant/miscreant/wiki/AES-PMAC-SIV | ||
[STREAM]: https://github.com/miscreant/miscreant/wiki/STREAM | ||
**AES-SIV** provides [nonce-reuse misuse-resistance] (NRMR): accidentally | ||
@@ -32,7 +38,3 @@ reusing a nonce with this construction is not a security catastrophe, | ||
[Phil Rogaway]: https://en.wikipedia.org/wiki/Phillip_Rogaway | ||
[AES-SIV]: https://www.iacr.org/archive/eurocrypt2006/40040377/40040377.pdf | ||
[RFC 5297]: https://tools.ietf.org/html/rfc5297 | ||
[CHAIN/STREAM]: http://web.cs.ucdavis.edu/~rogaway/papers/oae.pdf | ||
[nonce-reuse misuse-resistance]: https://www.lvh.io/posts/nonce-misuse-resistance-101.html | ||
[nonce-reuse misuse-resistance]: https://github.com/miscreant/miscreant/wiki/Nonce-Reuse-Misuse-Resistance | ||
[AES-GCM]: https://en.wikipedia.org/wiki/Galois/Counter_Mode | ||
@@ -106,19 +108,28 @@ [chosen ciphertext attacks]: https://en.wikipedia.org/wiki/Chosen-ciphertext_attack | ||
Import **miscreant.js** into your project with: | ||
Import Miscreant into your project with: | ||
```js | ||
import Miscreant from "miscreant"; | ||
import * as miscreant from "miscreant"; | ||
``` | ||
## API | ||
## AEAD API (Use this!) | ||
### Miscreant.importKey() | ||
The Authenticated Encryption with Associated Data API, or `AEAD` API, is the | ||
recommended API for encrypting and decrypting data with Miscreant. It accepts | ||
a nonce, optional associated data (i.e. data you'd like to authenticate along | ||
with the encrypted message), and a message to encrypt. | ||
The **Miscreant.importKey()** method creates a new instance of an **AES-SIV** | ||
encryptor/decryptor. | ||
When decrypting, the same nonce and associated data must be supplied as were | ||
passed at the time of encryption. If anything is amiss, e.g. if the ciphertext | ||
has been tampered with, the cipher will detect it and throw an error. | ||
### miscreant.AEAD.importKey() | ||
The **miscreant.AEAD.importKey()** method creates a new instance of an | ||
**AES-SIV** AEAD encryptor/decryptor. | ||
#### Syntax | ||
``` | ||
Miscreant.importKey(keyData, algorithm[, provider = Miscreant.webCryptoProvider()]) | ||
miscreant.AEAD.importKey(keyData, algorithm[, provider = new miscreant.WebCryptoProvider()]) | ||
``` | ||
@@ -142,12 +153,12 @@ | ||
The **Miscreant.importKey()** method returns a [Promise] that, when fulfilled, | ||
returns a SIV encryptor/decryptor. | ||
The **miscreant.AEAD.importKey()** method returns a [Promise] that, when | ||
fulfilled, returns an `AEAD` encryptor/decryptor. | ||
#### Exceptions | ||
The **Miscreant.importKey()** method will throw an error if it's attempting to use | ||
the default `window.crypto` provider either doesn't exist (e.g. `window` is | ||
not defined because we're on Node.js) or if that provider does not provide | ||
native implementations of the cryptographic primitives **AES-SIV** is built | ||
on top of. | ||
The **miscreant.AEAD.importKey()** method will throw an error if it's | ||
attempting to use the default `window.crypto` provider either doesn't exist | ||
(e.g. `window` is not defined because we're on Node.js) or if that provider | ||
does not provide native implementations of the cryptographic primitives | ||
**AES-SIV** is built on top of. | ||
@@ -159,9 +170,182 @@ In these cases, you may choose to use `PolyfillCrypto`, but be aware this may | ||
```typescript | ||
import * as miscreant from "miscreant"; | ||
let keyData = new Uint32Array(32); | ||
// Assuming window.crypto.getRandomValues is available | ||
window.crypto.getRandomValues(keyData); | ||
let key = await miscreant.AEAD.importKey(keyData, "AES-PMAC-SIV"); | ||
``` | ||
### seal() | ||
The **seal()** method encrypts a message along with an optional | ||
*associated data* value which will be authenticated along with the message. | ||
#### Syntax | ||
``` | ||
key.seal(plaintext, nonce[, associatedData = ""]) | ||
``` | ||
#### Parameters | ||
* **plaintext**: [Uint8Array] data to be encrypted. | ||
* **nonce**: a single-use value which MUST be unique per encrypted message. | ||
Can be any length, and use any uniqueness strategy you like, e.g. a counter | ||
or a cryptographically secure random number generator. | ||
* **associatedData**: (optional) [Uint8Array] that will be *authenticated* | ||
along with the message (but not encrypted). | ||
#### Return Value | ||
The **seal()** method returns a [Promise] that, when fulfilled, returns a | ||
[Uint8Array] containing the resulting ciphertext. | ||
#### Example | ||
```typescript | ||
import * as miscreant from "miscreant"; | ||
let keyData = new Uint8Array(32); | ||
// Assuming window.crypto.getRandomValues is available | ||
window.crypto.getRandomValues(keyData); | ||
let key = await miscreant.SIV.importKey(keyData, "AES-PMAC-SIV"); | ||
// Encrypt plaintext | ||
let plaintext = new Uint8Array([2,3,5,7,11,13,17,19,23,29]); | ||
let nonce = new Uint8Array(16); | ||
window.crypto.getRandomValues(nonce); | ||
let ciphertext = await key.seal(plaintext, nonce); | ||
``` | ||
### open() | ||
The **open()** method decrypts a message which has been encrypted using | ||
**AES-SIV** or **AES-PMAC-SIV**. | ||
#### Syntax | ||
``` | ||
key.open(ciphertext, nonce[, associatedData = ""]) | ||
``` | ||
#### Parameters | ||
* **ciphertext**: [Uint8Array] containing an encrypted message. | ||
* **nonce**: [Uint8Array] supplied when the message was originally encrypted. | ||
* **associatedData**: (optional) [Uint8Array] supplied when the message was | ||
originally encrypted. | ||
#### Return Value | ||
The **open()** method returns a [Promise] that, when fulfilled, | ||
returns a [Uint8Array] containing the decrypted plaintext. | ||
#### Exceptions | ||
If the message has been tampered with or is otherwise corrupted, the promise | ||
will be rejected with an **IntegrityError**. | ||
#### Example | ||
```typescript | ||
import * as miscreant from "miscreant"; | ||
let keyData = new Uint8Array(32); | ||
// Assuming window.crypto.getRandomValues is available | ||
window.crypto.getRandomValues(keyData); | ||
let key = await miscreant.SIV.importKey(keyData, "AES-PMAC-SIV"); | ||
// Encrypt plaintext | ||
let plaintext = new Uint8Array([2,3,5,7,11,13,17,19,23,29]); | ||
let nonce = new Uint8Array(16); | ||
window.crypto.getRandomValues(nonce); | ||
let ciphertext = await key.seal(plaintext, nonce); | ||
// Decrypt ciphertext | ||
var decrypted = await key.open(ciphertext, nonce); | ||
``` | ||
## STREAM API | ||
Miscreant implements an interface that permits incremental processing of | ||
encrypted data based on the [STREAM] construction, which is provably secure | ||
against a wide range of attacks including truncation and reordering attacks. | ||
The API is provided in the form of `miscreant.StreamEncryptor` and | ||
`miscreant.StreamDecryptor` classes, which each take a per-***STREAM*** key and | ||
nonce, and from there operate a message-at-a-time on input plaintext/ciphertext | ||
along with optional per-message associated data (i.e. data you'd like to | ||
authenticate along with the encrypted message). | ||
[STREAM]: https://github.com/miscreant/miscreant/wiki/STREAM | ||
### miscreant.StreamEncryptor.importKey() | ||
The **miscreant.StreamEncryptor.importKey()** method creates a new instance of | ||
a **STREAM** encryptor, capable of encrypting a stream of authenticated | ||
messages and ensuring their integrity, ordering, and termination. | ||
#### Syntax | ||
``` | ||
miscreant.StreamEncryptor.importKey(keyData, nonceData, algorithm[, provider = new miscreant.WebCryptoProvider()]) | ||
``` | ||
#### Parameters | ||
* **keyData**: a [Uint8Array] containing the encryption key to use. | ||
Key must be 32-bytes (for AES-128) or 64-bytes (for AES-256), as | ||
SIV uses two distinct AES keys to perform its operations. | ||
* **nonceData**: a 64-bit (8-byte) [Uint8Array] which MUST be unique to this | ||
message stream (for a given key). | ||
* **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. | ||
#### Return Value | ||
The **miscreant.StreamEncryptor.importKey()** method returns a [Promise] that, when | ||
fulfilled, returns a `StreamEncryptor` object. | ||
#### Exceptions | ||
The **miscreant.StreamEncryptor.importKey()** method will throw an error if it's | ||
attempting to use the default `window.crypto` provider either doesn't exist | ||
(e.g. `window` is not defined because we're on Node.js) or if that provider | ||
does not provide native implementations of the cryptographic primitives | ||
**AES-SIV** is built on top of. | ||
In these cases, you may choose to use `PolyfillCrypto`, but be aware this may | ||
decrease security. | ||
#### Example | ||
```typescript | ||
import * as miscreant from "miscreant"; | ||
let keyData = new Uint32Array(32); | ||
let nonceData = new Uint8Array(8); | ||
// Assuming window.crypto.getRandomValues is available | ||
window.crypto.getRandomValues(keyData); | ||
window.crypto.getRandomValues(nonceData); | ||
let key = await Miscreant.importKey(keyData, "AES-PMAC-SIV"); | ||
let encryptor = await miscreant.StreamEncryptor.importKey(keyData, nonceData, "AES-PMAC-SIV"); | ||
``` | ||
@@ -171,2 +355,232 @@ | ||
The **seal()** method of `miscreant.StreamEncryptor` encrypts a message, and | ||
also takes an optional *associated data* value which will be authenticated | ||
along with the message (but not encrypted). | ||
Note that unlike the `AEAD` API, **STREAM** encodes the position of the message | ||
into the message stream, so the order in which `seal()` is called is significant. | ||
#### Syntax | ||
``` | ||
encryptor.seal(plaintext, [lastBlock = false[, associatedData = ""]]) | ||
``` | ||
#### Parameters | ||
* **plaintext**: [Uint8Array] data to be encrypted. | ||
* **lastBlock**: (optional; default: false) is this the last block in the stream? | ||
* **associatedData**: (optional) [Uint8Array] that will be *authenticated* | ||
along with the message (but not encrypted). | ||
#### Return Value | ||
The **seal()** method returns a [Promise] that, when fulfilled, returns a | ||
[Uint8Array] containing the resulting ciphertext. | ||
#### Example | ||
```typescript | ||
import * as miscreant from "miscreant"; | ||
let keyData = new Uint32Array(32); | ||
let nonceData = new Uint8Array(8); | ||
// Assuming window.crypto.getRandomValues is available | ||
window.crypto.getRandomValues(keyData); | ||
window.crypto.getRandomValues(nonceData); | ||
let encryptor = await miscreant.StreamEncryptor.importKey(keyData, nonceData, "AES-PMAC-SIV"); | ||
// Encrypt plaintext | ||
let msg1 = new Uint8Array([1,2]); | ||
let msg2 = new Uint8Array([3,4,5]); | ||
let msg3 = new Uint8Array([6,7,8,9]); | ||
let ciphertext1 = await encryptor.seal(msg1); | ||
let ciphertext2 = await encryptor.seal(msg2); | ||
let ciphertext3 = await encryptor.seal(msg3, true); | ||
``` | ||
### miscreant.StreamDecryptor.importKey() | ||
The **miscreant.StreamDecryptor.importKey()** method creates a new instance of | ||
a **STREAM** decryptor, capable of decrypting a previously encrypted stream of | ||
authenticated messages and ensuring their integrity, ordering, and termination. | ||
#### Syntax | ||
``` | ||
miscreant.StreamDecryptor.importKey(keyData, nonceData, algorithm[, provider = new miscreant.WebCryptoProvider()]) | ||
``` | ||
#### Parameters | ||
* **keyData**: a [Uint8Array] containing the encryption key to use. | ||
Key must be 32-bytes (for AES-128) or 64-bytes (for AES-256), as | ||
SIV uses two distinct AES keys to perform its operations. | ||
* **nonceData**: a 64-bit (8-byte) [Uint8Array] which MUST be unique to this | ||
message stream (for a given key). | ||
* **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. | ||
#### Return Value | ||
The **miscreant.StreamDecryptor.importKey()** method returns a [Promise] that, when | ||
fulfilled, returns a `StreamDecryptor` object. | ||
#### Exceptions | ||
The **miscreant.StreamDecryptor.importKey()** method will throw an error if it's | ||
attempting to use the default `window.crypto` provider either doesn't exist | ||
(e.g. `window` is not defined because we're on Node.js) or if that provider | ||
does not provide native implementations of the cryptographic primitives | ||
**AES-SIV** is built on top of. | ||
In these cases, you may choose to use `PolyfillCrypto`, but be aware this may | ||
decrease security. | ||
#### Example | ||
```typescript | ||
import * as miscreant from "miscreant"; | ||
let keyData = new Uint32Array(32); | ||
let nonceData = new Uint8Array(8); | ||
// Assuming window.crypto.getRandomValues is available | ||
window.crypto.getRandomValues(keyData); | ||
window.crypto.getRandomValues(nonceData); | ||
let decryptor = await miscreant.StreamDecryptor.importKey(keyData, nonceData, "AES-PMAC-SIV"); | ||
``` | ||
### open() | ||
The **open()** method decrypts a stream of messages which has been encrypted | ||
using **AES-SIV** or **AES-PMAC-SIV**. | ||
#### Syntax | ||
``` | ||
decryptor.open(ciphertext, [lastBlock = false[, associatedData = ""]]) | ||
``` | ||
#### Parameters | ||
* **ciphertext**: [Uint8Array] containing an encrypted message. | ||
* **lastBlock**: (optional; default: false) is this the last block in the stream? | ||
* **associatedData**: (optional) [Uint8Array] supplied when the message was | ||
originally encrypted. | ||
#### Return Value | ||
The **open()** method returns a [Promise] that, when fulfilled, | ||
returns a [Uint8Array] containing the decrypted plaintext. | ||
#### Exceptions | ||
If the message has been tampered with or is otherwise corrupted, the promise | ||
will be rejected with an **IntegrityError**. | ||
#### Example | ||
```typescript | ||
import * as miscreant from "miscreant"; | ||
let keyData = new Uint32Array(32); | ||
let nonceData = new Uint8Array(8); | ||
// Assuming window.crypto.getRandomValues is available | ||
window.crypto.getRandomValues(keyData); | ||
window.crypto.getRandomValues(nonceData); | ||
let encryptor = await miscreant.StreamEncryptor.importKey(keyData, nonceData, "AES-PMAC-SIV"); | ||
// Encrypt plaintext | ||
let msg1 = new Uint8Array([1,2]); | ||
let msg2 = new Uint8Array([3,4,5]); | ||
let msg3 = new Uint8Array([6,7,8,9]); | ||
let ciphertext1 = await encryptor.seal(msg1); | ||
let ciphertext2 = await encryptor.seal(msg2); | ||
let ciphertext3 = await encryptor.seal(msg3, true); | ||
// Decrypt ciphertext | ||
let decryptor = await miscreant.StreamDecryptor.importKey(keyData, nonceData, "AES-PMAC-SIV"); | ||
var decrypted1 = await key.open(ciphertext1); | ||
var decrypted2 = await key.open(ciphertext2); | ||
var decrypted3 = await key.open(ciphertext3, true); | ||
``` | ||
## SIV API | ||
The `SIV` API is a power-user API that allows you to make full use of the | ||
multiple header feature the SIV construction provides. | ||
### miscreant.SIV.importKey() | ||
The **miscreant.SIV.importKey()** method creates a new instance of an | ||
**AES-SIV** encryptor/decryptor. | ||
#### Syntax | ||
``` | ||
miscreant.SIV.importKey(keyData, algorithm[, provider = new miscreant.WebCryptoProvider()]) | ||
``` | ||
#### Parameters | ||
* **keyData**: a [Uint8Array] containing the encryption key to use. | ||
Key must be 32-bytes (for AES-128) or 64-bytes (for AES-256), as | ||
SIV uses two distinct AES keys to perform its operations. | ||
* **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. | ||
#### Return Value | ||
The **miscreant.SIV.importKey()** method returns a [Promise] that, when | ||
fulfilled, returns a SIV encryptor/decryptor. | ||
#### Exceptions | ||
The **miscreant.SIV.importKey()** method will throw an error if it's | ||
attempting to use the default `window.crypto` provider either doesn't exist | ||
(e.g. `window` is not defined because we're on Node.js) or if that provider | ||
does not provide native implementations of the cryptographic primitives | ||
**AES-SIV** is built on top of. | ||
In these cases, you may choose to use `PolyfillCrypto`, but be aware this may | ||
decrease security. | ||
#### Example | ||
```typescript | ||
import * as miscreant from "miscreant"; | ||
let keyData = new Uint32Array(32); | ||
// Assuming window.crypto.getRandomValues is available | ||
window.crypto.getRandomValues(keyData); | ||
let key = await miscreant.SIV.importKey(keyData, "AES-PMAC-SIV"); | ||
``` | ||
### seal() | ||
The **seal()** method encrypts a message along with a set of message headers | ||
@@ -187,3 +601,3 @@ known as *associated data*. | ||
message is encrypted twice, the ciphertext will not repeat. | ||
* **plaintext**: a [Uint8Array] of data to be encrypted. | ||
* **plaintext**: a [Uint8Array] data to be encrypted. | ||
@@ -197,9 +611,11 @@ #### Return Value | ||
``` | ||
// Assuming window.crypto.getRandomValues is available | ||
```typescript | ||
import * as miscreant from "miscreant"; | ||
let keyData = new Uint8Array(32); | ||
// Assuming window.crypto.getRandomValues is available | ||
window.crypto.getRandomValues(keyData); | ||
let key = await Miscreant.importKey(keyData, "AES-PMAC-SIV"); | ||
let key = await miscreant.SIV.importKey(keyData, "AES-PMAC-SIV"); | ||
@@ -212,3 +628,3 @@ // Encrypt plaintext | ||
let ciphertext = await key.seal([nonce], plaintext); | ||
let ciphertext = await key.seal(plaintext, [nonce]); | ||
``` | ||
@@ -243,9 +659,11 @@ | ||
``` | ||
// Assuming window.crypto.getRandomValues is available | ||
```typescript | ||
import * as miscreant from "miscreant"; | ||
let keyData = new Uint8Array(32); | ||
// Assuming window.crypto.getRandomValues is available | ||
window.crypto.getRandomValues(keyData); | ||
let key = await Miscreant.importKey(keyData, "AES-PMAC-SIV"); | ||
let key = await SIV.importKey(keyData, "AES-PMAC-SIV"); | ||
@@ -258,6 +676,6 @@ // Encrypt plaintext | ||
let ciphertext = await key.seal([nonce], plaintext); | ||
let ciphertext = await key.seal(plaintext, [nonce]); | ||
// Decrypt ciphertext | ||
var decrypted = await key.open([nonce], ciphertext); | ||
var decrypted = await key.open(ciphertext, [nonce]); | ||
``` | ||
@@ -278,3 +696,3 @@ | ||
However, this library also contains a `PolyfillCrypto` implementation which | ||
can be passed as the second parameter to `Miscreant.importKey()`. This implementation | ||
can be passed as the second parameter to `SIV.importKey()`. This implementation | ||
uses pure JavaScript, however is not provided by default because there are | ||
@@ -290,15 +708,9 @@ security concerns around its implementation. | ||
If you have already read the [Polyfill Security Warning](#polyfill-security-warning), | ||
understand the security concerns, and would like to use it anyway, call the | ||
following to obtain a `PolyfillCrypto` instance: | ||
understand the security concerns, and would like to use it anyway, create a | ||
`PolyfillCryptoProvider` instance and pass it into a constructor: | ||
```typescript | ||
const key = miscreant.AEAD.importKey(keyData, "AES-PMAC-SIV", new miscreant.PolyfillCryptoProvider()); | ||
``` | ||
Miscreant.polyfillCryptoProvider() | ||
``` | ||
You can pass it to `Miscreant.importKey()` like so: | ||
``` | ||
const key = Miscreant.importKey(keyData, "AES-PMAC-SIV", Miscreant.polyfillCryptoProvider()); | ||
``` | ||
## Code of Conduct | ||
@@ -305,0 +717,0 @@ |
/** Thrown when ciphertext fails to verify as authentic */ | ||
export default class IntegrityError extends Error { | ||
export class IntegrityError extends Error { | ||
constructor(m: string) { | ||
@@ -4,0 +4,0 @@ super(m); |
/** Thrown when we attempt to use an unsupported crypto algorithm via WebCrypto */ | ||
export default class NotImplementedError extends Error { | ||
export class NotImplementedError extends Error { | ||
constructor(m: string) { | ||
@@ -4,0 +4,0 @@ super(m); |
@@ -9,5 +9,3 @@ // 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 * as miscreant from "../src/index"; | ||
@@ -22,6 +20,6 @@ @suite class PolyfillAesCmacSpec { | ||
@test async "passes the AES-CMAC test vectors"() { | ||
const polyfillProvider = new PolyfillCryptoProvider(); | ||
const polyfillProvider = new miscreant.PolyfillCryptoProvider(); | ||
for (let v of PolyfillAesCmacSpec.vectors) { | ||
const mac = await Cmac.importKey(polyfillProvider, v.key); | ||
const mac = await miscreant.CMAC.importKey(polyfillProvider, v.key); | ||
await mac.update(v.message); | ||
@@ -41,6 +39,6 @@ expect(await mac.finish()).to.eql(v.tag); | ||
@test async "passes the AES-CMAC test vectors"() { | ||
const webCryptoProvider = new WebCryptoProvider(new WebCrypto()); | ||
const webCryptoProvider = new miscreant.WebCryptoProvider(new WebCrypto()); | ||
for (let v of PolyfillAesCmacSpec.vectors) { | ||
const mac = await Cmac.importKey(webCryptoProvider, v.key); | ||
const mac = await miscreant.CMAC.importKey(webCryptoProvider, v.key); | ||
await mac.update(v.message); | ||
@@ -47,0 +45,0 @@ expect(await mac.finish()).to.eql(v.tag); |
@@ -10,5 +10,5 @@ // Copyright (C) 2016 Dmitry Chestnykh | ||
import PolyfillAes from "../src/internal/polyfill/aes"; | ||
import PolyfillAesCtr from "../src/internal/polyfill/aes_ctr"; | ||
import WebCryptoAesCtr from "../src/internal/webcrypto/aes_ctr"; | ||
import PolyfillAes from "../src/providers/polyfill/aes"; | ||
import PolyfillAesCtr from "../src/providers/polyfill/aes_ctr"; | ||
import WebCryptoAesCtr from "../src/providers/webcrypto/aes_ctr"; | ||
@@ -15,0 +15,0 @@ @suite class PolyfillAesCtrSpec { |
@@ -10,8 +10,4 @@ // Copyright (C) 2017 Tony Arcieri, Dmitry Chestnykh | ||
import WebCrypto = require("node-webcrypto-ossl"); | ||
import PolyfillCryptoProvider from "../src/internal/polyfill/provider"; | ||
import WebCryptoProvider from "../src/internal/webcrypto/provider"; | ||
import * as miscreant from "../src/index"; | ||
import AesSiv from "../src/internal/aes_siv"; | ||
import IntegrityError from "../src/exceptions/integrity_error"; | ||
let expect = chai.expect; | ||
@@ -28,6 +24,6 @@ chai.use(chaiAsPromised); | ||
@test async "should correctly seal and open with polyfill cipher implementations"() { | ||
const polyfillProvider = new PolyfillCryptoProvider(); | ||
const polyfillProvider = new miscreant.PolyfillCryptoProvider(); | ||
for (let v of AesPmacSivSpec.vectors) { | ||
const siv = await AesSiv.importKey(polyfillProvider, "AES-PMAC-SIV", v.key); | ||
const siv = await miscreant.SIV.importKey(v.key, "AES-PMAC-SIV", polyfillProvider); | ||
const sealed = await siv.seal(v.plaintext, v.ad); | ||
@@ -44,6 +40,6 @@ expect(sealed).to.eql(v.ciphertext); | ||
@test async "should correctly seal and open with WebCrypto cipher implementations"() { | ||
const webCryptoProvider = new WebCryptoProvider(new WebCrypto()); | ||
const webCryptoProvider = new miscreant.WebCryptoProvider(new WebCrypto()); | ||
for (let v of AesPmacSivSpec.vectors) { | ||
const siv = await AesSiv.importKey(webCryptoProvider, "AES-PMAC-SIV", v.key); | ||
const siv = await miscreant.SIV.importKey(v.key, "AES-PMAC-SIV", webCryptoProvider); | ||
const sealed = await siv.seal(v.plaintext, v.ad); | ||
@@ -60,3 +56,3 @@ expect(sealed).to.eql(v.ciphertext); | ||
@test async "should not open with incorrect associated data"() { | ||
const polyfillProvider = new PolyfillCryptoProvider(); | ||
const polyfillProvider = new miscreant.PolyfillCryptoProvider(); | ||
@@ -67,4 +63,4 @@ for (let v of AesPmacSivSpec.vectors) { | ||
const siv = await AesSiv.importKey(polyfillProvider, "AES-PMAC-SIV", v.key); | ||
return expect(siv.open(v.ciphertext, badAd)).to.be.rejectedWith(IntegrityError); | ||
const siv = await miscreant.SIV.importKey(v.key, "AES-PMAC-SIV", polyfillProvider); | ||
await expect(siv.open(v.ciphertext, badAd)).to.be.rejectedWith(miscreant.IntegrityError); | ||
} | ||
@@ -74,3 +70,3 @@ } | ||
@test async "should not open with incorrect ciphertext"() { | ||
const polyfillProvider = new PolyfillCryptoProvider(); | ||
const polyfillProvider = new miscreant.PolyfillCryptoProvider(); | ||
@@ -83,6 +79,6 @@ for (let v of AesPmacSivSpec.vectors) { | ||
const siv = await AesSiv.importKey(polyfillProvider, "AES-PMAC-SIV", v.key); | ||
return expect(siv.open(badOutput, v.ad)).to.be.rejectedWith(IntegrityError); | ||
const siv = await miscreant.SIV.importKey(v.key, "AES-PMAC-SIV", polyfillProvider); | ||
await expect(siv.open(badOutput, v.ad)).to.be.rejectedWith(miscreant.IntegrityError); | ||
} | ||
} | ||
} |
@@ -9,6 +9,5 @@ // Copyright (C) 2016-2017 Dmitry Chestnykh, Tony Arcieri | ||
import WebCrypto = require("node-webcrypto-ossl"); | ||
import PolyfillCryptoProvider from "../src/internal/polyfill/provider"; | ||
import WebCryptoProvider from "../src/internal/webcrypto/provider"; | ||
import Pmac from "../src/internal/mac/pmac"; | ||
import * as miscreant from "../src/index"; | ||
@suite class PolyfillAesPmacSpec { | ||
@@ -22,6 +21,6 @@ static vectors: AesPmacExample[]; | ||
@test async "passes the AES-PMAC test vectors"() { | ||
const polyfillProvider = new PolyfillCryptoProvider(); | ||
const polyfillProvider = new miscreant.PolyfillCryptoProvider(); | ||
for (let v of PolyfillAesPmacSpec.vectors) { | ||
const mac = await Pmac.importKey(polyfillProvider, v.key); | ||
const mac = await miscreant.PMAC.importKey(polyfillProvider, v.key); | ||
await mac.update(v.message); | ||
@@ -41,6 +40,6 @@ expect(v.tag).to.eql(await mac.finish()); | ||
@test async "passes the AES-PMAC test vectors"() { | ||
const webCryptoProvider = new WebCryptoProvider(new WebCrypto()); | ||
const webCryptoProvider = new miscreant.WebCryptoProvider(new WebCrypto()); | ||
for (let v of PolyfillAesPmacSpec.vectors) { | ||
const mac = await Pmac.importKey(webCryptoProvider, v.key); | ||
const mac = await miscreant.PMAC.importKey(webCryptoProvider, v.key); | ||
await mac.update(v.message); | ||
@@ -47,0 +46,0 @@ expect(v.tag).to.eql(await mac.finish()); |
@@ -10,8 +10,4 @@ // 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 * as miscreant from "../src/index"; | ||
import AesSiv from "../src/internal/aes_siv"; | ||
import IntegrityError from "../src/exceptions/integrity_error"; | ||
let expect = chai.expect; | ||
@@ -28,10 +24,10 @@ chai.use(chaiAsPromised); | ||
@test async "should correctly seal and open with polyfill cipher implementations"() { | ||
const polyfillProvider = new PolyfillCryptoProvider(); | ||
const polyfillProvider = new miscreant.PolyfillCryptoProvider(); | ||
for (let v of AesSivSpec.vectors) { | ||
const siv = await AesSiv.importKey(polyfillProvider, "AES-SIV", v.key); | ||
const siv = await miscreant.SIV.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, ); | ||
const unsealed = await siv.open(sealed, v.ad); | ||
expect(unsealed).not.to.be.null; | ||
@@ -44,10 +40,10 @@ expect(unsealed!).to.eql(v.plaintext); | ||
@test async "should correctly seal and open with WebCrypto cipher implementations"() { | ||
const webCryptoProvider = new WebCryptoProvider(new WebCrypto()); | ||
const webCryptoProvider = new miscreant.WebCryptoProvider(new WebCrypto()); | ||
for (let v of AesSivSpec.vectors) { | ||
const siv = await AesSiv.importKey(webCryptoProvider, "AES-SIV", v.key); | ||
const siv = await miscreant.SIV.importKey(v.key, "AES-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, ); | ||
const unsealed = await siv.open(sealed, v.ad); | ||
expect(unsealed).not.to.be.null; | ||
@@ -60,3 +56,3 @@ expect(unsealed!).to.eql(v.plaintext); | ||
@test async "should correctly seal and open different plaintext under the same key"() { | ||
const polyfillProvider = new PolyfillCryptoProvider(); | ||
const polyfillProvider = new miscreant.PolyfillCryptoProvider(); | ||
@@ -70,6 +66,6 @@ const key = byteSeq(64); | ||
const siv = await AesSiv.importKey(polyfillProvider, "AES-SIV", key); | ||
const siv = await miscreant.SIV.importKey(key, "AES-SIV", polyfillProvider); | ||
const sealed1 = await siv.seal(pt1, ad1); | ||
const opened1 = await siv.open(sealed1, ad1, ); | ||
const opened1 = await siv.open(sealed1, ad1); | ||
expect(opened1).not.to.be.null; | ||
@@ -87,3 +83,3 @@ expect(opened1!).to.eql(pt1); | ||
@test async "should not open with incorrect key"() { | ||
const polyfillProvider = new PolyfillCryptoProvider(); | ||
const polyfillProvider = new miscreant.PolyfillCryptoProvider(); | ||
@@ -96,4 +92,4 @@ for (let v of AesSivSpec.vectors) { | ||
const siv = await AesSiv.importKey(polyfillProvider, "AES-SIV", badKey); | ||
expect(siv.open(v.ciphertext, v.ad)).to.be.rejectedWith(IntegrityError); | ||
const siv = await miscreant.SIV.importKey(badKey, "AES-SIV", polyfillProvider); | ||
await expect(siv.open(v.ciphertext, v.ad)).to.be.rejectedWith(miscreant.IntegrityError); | ||
} | ||
@@ -103,3 +99,3 @@ } | ||
@test async "should not open with incorrect associated data"() { | ||
const polyfillProvider = new PolyfillCryptoProvider(); | ||
const polyfillProvider = new miscreant.PolyfillCryptoProvider(); | ||
@@ -110,4 +106,4 @@ for (let v of AesSivSpec.vectors) { | ||
const siv = await AesSiv.importKey(polyfillProvider, "AES-SIV", v.key); | ||
return expect(siv.open(v.ciphertext, badAd)).to.be.rejectedWith(IntegrityError); | ||
const siv = await miscreant.SIV.importKey(v.key, "AES-SIV", polyfillProvider); | ||
await expect(siv.open(v.ciphertext, badAd)).to.be.rejectedWith(miscreant.IntegrityError); | ||
} | ||
@@ -117,3 +113,3 @@ } | ||
@test async "should not open with incorrect ciphertext"() { | ||
const polyfillProvider = new PolyfillCryptoProvider(); | ||
const polyfillProvider = new miscreant.PolyfillCryptoProvider(); | ||
@@ -126,4 +122,4 @@ for (let v of AesSivSpec.vectors) { | ||
const siv = await AesSiv.importKey(polyfillProvider, "AES-SIV", v.key); | ||
return expect(siv.open(badOutput, v.ad)).to.be.rejectedWith(IntegrityError); | ||
const siv = await miscreant.SIV.importKey(v.key, "AES-SIV", polyfillProvider); | ||
await expect(siv.open(badOutput, v.ad)).to.be.rejectedWith(miscreant.IntegrityError); | ||
} | ||
@@ -130,0 +126,0 @@ } |
@@ -8,7 +8,7 @@ // Copyright (C) 2016-2017 Dmitry Chestnykh, Tony Arcieri | ||
import { AesExample } from "./support/test_vectors"; | ||
import Block from "../src/internal/block"; | ||
import Block from "../src/internals/block"; | ||
import WebCrypto = require("node-webcrypto-ossl"); | ||
import WebCryptoAes from "../src/internal/webcrypto/aes"; | ||
import PolyfillAes from "../src/internal/polyfill/aes"; | ||
import WebCryptoAes from "../src/providers/webcrypto/aes"; | ||
import PolyfillAes from "../src/providers/polyfill/aes"; | ||
@@ -15,0 +15,0 @@ let expect = chai.expect; |
import { suite, test } from "mocha-typescript"; | ||
import { expect } from "chai"; | ||
import Block from "../src/internal/block"; | ||
import Block from "../src/internals/block"; | ||
@@ -5,0 +5,0 @@ import { DblExample } from "./support/test_vectors"; |
@@ -6,3 +6,3 @@ // Copyright (C) 2016 Dmitry Chestnykh | ||
import { expect } from "chai"; | ||
import { select, compare, equal } from "../src/internal/util/constant-time"; | ||
import { select, compare, equal } from "../src/internals/constant-time"; | ||
@@ -9,0 +9,0 @@ @suite class SelectSpec { |
@@ -50,2 +50,56 @@ import * as fs from "async-file"; | ||
/** AEAD (AES-SIV/AES-PMAC-SIV) test vectors */ | ||
export class AEADExample { | ||
static readonly DEFAULT_EXAMPLES_PATH = "../vectors/aes_siv_aead.tjson"; | ||
public readonly name: string; | ||
public readonly alg: string; | ||
public readonly key: Uint8Array; | ||
public readonly ad: Uint8Array; | ||
public readonly nonce: Uint8Array; | ||
public readonly plaintext: Uint8Array; | ||
public readonly ciphertext: Uint8Array; | ||
static async loadAll(): Promise<AEADExample[]> { | ||
return AEADExample.loadFromFile(AEADExample.DEFAULT_EXAMPLES_PATH); | ||
} | ||
static async loadFromFile(filename: string): Promise<AEADExample[]> { | ||
let tjson = TJSON.parse(await fs.readFile(filename, "utf8")); | ||
return tjson["examples"].map((ex: any) => { | ||
let obj = Object.create(AEADExample.prototype); | ||
return Object.assign(obj, ex); | ||
}); | ||
} | ||
} | ||
export class STREAMBlock { | ||
public readonly ad: Uint8Array; | ||
public readonly plaintext: Uint8Array; | ||
public readonly ciphertext: Uint8Array; | ||
} | ||
/** STREAM (AES-SIV/AES-PMAC-SIV) test vectors */ | ||
export class STREAMExample { | ||
static readonly DEFAULT_EXAMPLES_PATH = "../vectors/aes_siv_stream.tjson"; | ||
public readonly name: string; | ||
public readonly alg: string; | ||
public readonly key: Uint8Array; | ||
public readonly nonce: Uint8Array; | ||
public readonly blocks: STREAMBlock[]; | ||
static async loadAll(): Promise<STREAMExample[]> { | ||
return STREAMExample.loadFromFile(STREAMExample.DEFAULT_EXAMPLES_PATH); | ||
} | ||
static async loadFromFile(filename: string): Promise<STREAMExample[]> { | ||
let tjson = TJSON.parse(await fs.readFile(filename, "utf8")); | ||
return tjson["examples"].map((ex: any) => { | ||
let obj = Object.create(STREAMExample.prototype); | ||
return Object.assign(obj, ex); | ||
}); | ||
} | ||
} | ||
/** AES (raw block function) test vectors */ | ||
@@ -52,0 +106,0 @@ export class AesExample { |
import { suite, test } from "mocha-typescript"; | ||
import { expect } from "chai"; | ||
import { wipe } from "../src/internal/util/wipe"; | ||
import { wipe } from "../src/internals/wipe"; | ||
@@ -5,0 +5,0 @@ @suite class WipeSpec { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
162070
47
2264
727