Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add xchacha20-poly1305 #1

Merged
merged 1 commit into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .cspell.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"words": [
"chacha",
"ecies",
"hchacha",
"xchacha"
],
"ignorePaths": [
".git",
".github",
".gitignore",
".cspell.jsonc",
"LICENSE",
"package.json"
]
}
2 changes: 1 addition & 1 deletion .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:

- run: pnpm install && pnpm test -- --bail 1

- run: pnpm run build && npm publish --access public
- run: pnpm build && npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_CONFIG_PROVENANCE: true
30 changes: 27 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,42 @@ jobs:
node: [18, 20, 22]
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4

- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: pnpm
cache-dependency-path: pnpm-lock.yaml

- run: pnpm install && pnpm test -- --bail 1
- run: pnpm build && npm publish --dry-run

- uses: codecov/codecov-action@v4
if: matrix.os == 'ubuntu-latest' && matrix.node == 22
with:
token: ${{ secrets.CODECOV_TOKEN }}
- run: pnpm run build && npm publish --dry-run

check-runtimes:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
cache-dependency-path: pnpm-lock.yaml

- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- uses: denoland/setup-deno@v2
with:
deno-version: v2.x

- run: pnpm install && pnpm build
- run: cd example && pnpm install
- run: bun run example/main.js
- run: deno run --allow-read example/main.js
- run: node example/main.js
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ node_modules/
coverage/
dist/

bun.lockb
deno.lock
# example
example/bun.lockb
example/deno.lock
example/pnpm-lock.yaml

.DS_Store
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Release Notes

## 0.2.0

- Add xchacha20-poly1305 support

## 0.1.0

- First beta version release with aes-256-gcm and aes-256-cbc support
51 changes: 47 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,52 @@
# @ecies/ciphers

Node/Pure js symmetric ciphers adapter.
[![License](https://img.shields.io/github/license/ecies/js-ciphers.svg)](https://github.com/ecies/js-ciphers)
[![Npm Package](https://img.shields.io/npm/v/@ecies/ciphers.svg)](https://www.npmjs.com/package/@ecies/ciphers)
[![CI](https://img.shields.io/github/actions/workflow/status/ecies/js-ciphers/ci.yml)](https://github.com/ecies/js-ciphers/actions)
[![Codecov](https://img.shields.io/codecov/c/github/ecies/js-ciphers.svg)](https://codecov.io/gh/ecies/js-ciphers)

On browsers (or deno), it'll use `@noble/ciphers`'s implementation.
Node/Pure JavaScript symmetric ciphers adapter.

On node (or bun), it'll use `node:crypto`'s implementation.
On browsers (or deno), it'll use [`@noble/ciphers`](https://github.com/paulmillr/noble-ciphers)'s implementation for compatibility.

Check the [example](./example/) folder for the bun/deno usage.
On node (or bun), it'll use [`node:crypto`](https://nodejs.org/api/crypto.html#cryptocreatecipherivalgorithm-key-iv-options)'s implementation for efficiency.

> [!NOTE]
> There are some limitations, see [Known limitations](#known-limitations) below.

Check the [example](./example/) folder for bun/deno usage.

## Quick start

```js
import { aes256gcm } from "@ecies/ciphers/aes";
import { randomBytes } from "@noble/ciphers/webcrypto";

const TEXT = "hello world🌍!";
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const msg = encoder.encode(TEXT);

const key = randomBytes();
const nonce = randomBytes(16);
const cipher = aes256gcm(key, nonce);
console.log("decrypted:", decoder.decode(cipher.decrypt(cipher.encrypt(msg))));
```

The API follows `@noble/ciphers`'s API for ease of use, you can check their [examples](https://github.com/paulmillr/noble-ciphers#examples) as well.

## Supported ciphers

- `aes-256-gcm`
- Both 16 bytes and 12 bytes nonce are supported.
- `aes-256-cbc`
- **Only for legacy applications**. You should use `xchacha20-poly1305` or `aes-256-gcm` as possible.
- Nonce is always 16 bytes.
- `xchacha20-poly1305`
- Nonce is always 24 bytes.

## Known limitations

- `xchacha20-poly1305` is implemented with pure JS [`hchacha`](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha#section-2.2) function and `node:crypto`'s `chacha20-poly1305`.
- Currently (Oct 2024), `node:crypto`'s `chacha20-poly1305` is not supported on deno and [bun](https://github.com/oven-sh/bun/issues/8072), `@noble/ciphers`'s implementation is used on both platforms instead.
- `deno` does not support **indirect** conditional exports. If you use this library to build another library, client code of your library probably falls back to the `node:crypto` implementation and may not work properly, specifically `aes-256-gcm` (16 bytes nonce) and `chacha20-poly1305`.
14 changes: 11 additions & 3 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
# example
# runtime-example

## Install

Run with `bun install` (or `pnpm install`)

## bun

Run with `bun install && bun run index.ts`
Run with `bun run main.js`

## deno

Run with `deno run main.ts`
Run with `deno run --allow-read main.js`

## node

Run with `node main.js`
12 changes: 0 additions & 12 deletions example/bun/index.ts

This file was deleted.

14 changes: 0 additions & 14 deletions example/bun/package.json

This file was deleted.

22 changes: 0 additions & 22 deletions example/bun/tsconfig.json

This file was deleted.

9 changes: 0 additions & 9 deletions example/deno/deno.json

This file was deleted.

12 changes: 0 additions & 12 deletions example/deno/main.ts

This file was deleted.

46 changes: 46 additions & 0 deletions example/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { aes256cbc, aes256gcm } from "@ecies/ciphers/aes";
import { xchacha20 } from "@ecies/ciphers/chacha";

import { randomBytes } from "@noble/ciphers/webcrypto";

const TEXT = "hello world🌍!";
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const msg = encoder.encode(TEXT);

const ciphers = [
{
keyLength: 32,
nonceLength: 16,
callback: aes256gcm,
aad: randomBytes(16),
},
{
keyLength: 32,
nonceLength: 12,
callback: aes256gcm,
aad: randomBytes(16),
},
{
keyLength: 32,
nonceLength: 16,
callback: aes256cbc,
aad: undefined,
},
{
keyLength: 32,
nonceLength: 24,
callback: xchacha20,
aad: randomBytes(16),
},
];

for (const { keyLength, nonceLength, callback, aad } of ciphers) {
const key = randomBytes(keyLength);
const nonce = randomBytes(nonceLength);
const cipher = callback(key, nonce, aad);
console.log(
`${callback.name} (nonce length ${nonce.length}) decrypted:`,
decoder.decode(cipher.decrypt(cipher.encrypt(msg)))
);
}
8 changes: 8 additions & 0 deletions example/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "runtime-example",
"main": "main.js",
"type": "module",
"dependencies": {
"@ecies/ciphers": "file:.."
}
}
46 changes: 30 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ecies/ciphers",
"description": "Node/Pure js symmetric ciphers adapter",
"description": "Node/Pure JavaScript symmetric ciphers adapter",
"license": "MIT",
"author": {
"name": "Weiliang Li",
Expand All @@ -11,38 +11,52 @@
"type": "git",
"url": "git+https://github.com/ecies/js-ciphers.git"
},
"version": "0.1.0",
"version": "0.2.0",
"engines": {
"node": ">=16.0.0"
"node": ">=16",
"bun": ">=1",
"deno": ">=2"
},
"keywords": [
"cryptography",
"aes"
"cipher",
"aes",
"chacha",
"xchacha20",
"xchacha20poly1305"
],
"main": "dist/node.js",
"types": "dist/node.d.ts",
"files": [
"dist"
],
"exports": {
"types": "./dist/node.d.ts",
"browser": "./dist/noble.js",
"deno": "./dist/noble.js",
"bun": "./dist/node.js",
"default": "./dist/node.js"
".": null,
"./aes": {
"types": "./dist/aes/node.d.ts",
"browser": "./dist/aes/noble.js",
"deno": "./dist/aes/noble.js",
"bun": "./dist/aes/node.js",
"default": "./dist/aes/node.js"
},
"./chacha": {
"types": "./dist/chacha/node.d.ts",
"browser": "./dist/chacha/noble.js",
"deno": "./dist/chacha/noble.js",
"bun": "./dist/chacha/noble.js",
"default": "./dist/chacha/node.js"
}
},
"scripts": {
"build": "npx tsc",
"test": "vitest"
},
"dependencies": {
"peerDependencies": {
"@noble/ciphers": "^1.0.0"
},
"devDependencies": {
"@types/node": "^22.7.5",
"@vitest/coverage-v8": "^2.1.2",
"@types/node": "^22.7.6",
"@vitest/coverage-v8": "^2.1.3",
"typescript": "^5.6.3",
"vitest": "^2.1.2"
"vitest": "^2.1.3"
},
"packageManager": "pnpm@9.12.1+sha512.e5a7e52a4183a02d5931057f7a0dbff9d5e9ce3161e33fa68ae392125b79282a8a8a470a51dfc8a0ed86221442eb2fb57019b0990ed24fab519bf0e1bc5ccfc4"
"packageManager": "pnpm@9.12.2+sha512.22721b3a11f81661ae1ec68ce1a7b879425a1ca5b991c975b074ac220b187ce56c708fe5db69f4c962c989452eee76c82877f4ee80f474cebd61ee13461b6228"
}
Loading