Skip to content

Commit

Permalink
feat: Initial commit
Browse files Browse the repository at this point in the history
Extracted from monorepo
  • Loading branch information
franky47 committed Mar 13, 2020
0 parents commit ba63c38
Show file tree
Hide file tree
Showing 24 changed files with 5,560 additions and 0 deletions.
39 changes: 39 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Continuous Delivery

on:
push:
branches:
- master

jobs:
cd:
name: Continuous Delivery
runs-on: ubuntu-latest
steps:
- id: yarn-cache
name: Get Yarn cache path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/checkout@722adc6
- uses: actions/setup-node@1c5c137
with:
node-version: 12.x
- uses: actions/cache@70655ec
name: Load Yarn cache
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- run: yarn install --ignore-scripts
name: Install dependencies
- run: yarn build
name: Build package

# Continuous Delivery Pipeline --

- uses: codfish/semantic-release-action@a313b22
name: Semantic Release
id: semantic
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
44 changes: 44 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Continuous Integration

on:
push:
branches:
- next
- feature/*

jobs:
ci:
name: Continuous Integration
runs-on: ubuntu-latest
steps:
- id: yarn-cache
name: Get Yarn cache path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/checkout@722adc6
- uses: actions/setup-node@1c5c137
with:
node-version: 12.x
- uses: actions/cache@70655ec
name: Load Yarn cache
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- run: yarn install --ignore-scripts
name: Install dependencies
- run: yarn ci
name: Run integration tests
- uses: coverallsapp/github-action@832e70b
name: Report code coverage
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- uses: 8398a7/action-slack@78391c2
name: Notify on Slack
if: always() # Pick up events even if the job fails or is canceled.
with:
status: ${{ job.status }}
author_name: Continuous Integration
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules/
dist/
coverage/
.env
yarn-error.log
# Docker containers with persistance
.volumes/
7 changes: 7 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
**/*.test.ts
tsconfig.json
.env
.volumes/
yarn-error.log
.github/**
src/**
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# @chiffre/crypto

[![NPM](https://img.shields.io/npm/v/@chiffre/crypto?color=red)](https://www.npmjs.com/package/@chiffre/crypto)
[![MIT License](https://img.shields.io/github/license/chiffre-io/crypto.svg?color=blue)](https://github.com/chiffre-io/crypto/blob/master/LICENSE)
[![Continuous Integration](https://github.com/chiffre-io/crypto/workflows/Continuous%20Integration/badge.svg?branch=next)](https://github.com/chiffre-io/crypto/actions)
[![Coverage Status](https://coveralls.io/repos/github/chiffre-io/crypto/badge.svg?branch=next)](https://coveralls.io/github/chiffre-io/crypto?branch=next)
[![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=chiffre-io/crypto)](https://dependabot.com)

Cryptographic primitives & constructs for the Chiffre platform

## License

[MIT](https://github.com/chiffre-io/crypto/blob/master/LICENSE) - Made with ❤️ by [François Best](https://francoisbest.com).
100 changes: 100 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
{
"name": "@chiffre/crypto",
"version": "0.0.0-semantically-released",
"description": "Cryptographic primitives & constructs for the Chiffre platform",
"main": "dist/index.js",
"license": "MIT",
"author": {
"name": "François Best",
"email": "francois.best@chiffre.io",
"url": "https://chiffre.io"
},
"repository": {
"type": "git",
"url": "https://github.com/chiffre-io/crypto"
},
"keywords": [
"chiffre",
"cryptography",
"tweetnacl",
"aes-256-gcm"
],
"publishConfig": {
"access": "public"
},
"scripts": {
"test": "jest --coverage",
"test:watch": "jest --watch",
"build:clean": "rm -rf ./dist",
"build:ts": "tsc",
"build": "run-s build:clean build:ts",
"ci": "run-s build test"
},
"dependencies": {
"@47ng/cloak": "^0.15.1",
"@47ng/codec": "^0.4.0",
"@chiffre/crypto-box": "^1.0.0",
"@stablelib/tss": "^1.0.0",
"secure-remote-password": "^0.3.1",
"tweetnacl": "^1.0.3"
},
"devDependencies": {
"@commitlint/config-conventional": "^8.3.4",
"@types/faker": "^4.1.10",
"@types/jest": "^25.1.4",
"@types/node": "^13.9.1",
"commitlint": "^8.3.5",
"faker": "^4.1.0",
"husky": "^4.2.3",
"jest": "^25.1.0",
"npm-run-all": "^4.1.5",
"ts-jest": "^25.2.1",
"ts-node": "^8.6.2",
"typescript": "^3.8.3"
},
"jest": {
"verbose": true,
"preset": "ts-jest/presets/js-with-ts",
"testEnvironment": "node"
},
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"commitlint": {
"extends": [
"@commitlint/config-conventional"
],
"rules": {
"type-enum": [
2,
"always",
[
"build",
"chore",
"ci",
"clean",
"doc",
"feat",
"fix",
"perf",
"ref",
"revert",
"style",
"test"
]
],
"subject-case": [
0,
"always",
"sentence-case"
],
"body-leading-blank": [
2,
"always",
true
]
}
}
}
29 changes: 29 additions & 0 deletions src/account.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { generateKey } from '@47ng/cloak'
import { generateSrpSignupEntities } from './srp'
import { createMasterKey, encryptKeychainKey } from './masterKey'
import { createKeychain, lockKeychain } from './keychain'

export async function createSignupEntities(username: string, password: string) {
// Generate SRP entities
const srpEntities = await generateSrpSignupEntities(username, password)

// Create a keychain key & encrypt it with the master key
const { masterKey, masterSalt, shards } = await createMasterKey(
username,
password
)
const keychainKey = generateKey()
const encryptedKeychainKey = await encryptKeychainKey(keychainKey, masterKey)

const unlockedKeychain = createKeychain()
const lockedKeychain = await lockKeychain(unlockedKeychain, keychainKey)
return {
...srpEntities,
masterSalt,
shards,
keychainKey: encryptedKeychainKey,
keychain: {
...lockedKeychain
}
}
}
43 changes: 43 additions & 0 deletions src/demo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { generateKey } from '@47ng/cloak'
import { createKeychain, lockKeychain } from './keychain'
import { packMessage, unpackMessage, Peer } from './peers'
import faker from 'faker'
import { performance } from 'perf_hooks'

const createPeerData = async () => {
const key = generateKey()
const keychain = createKeychain()
const locked = await lockKeychain(keychain, key)
const peer: Peer = {
signature: locked.signature.public,
sharing: locked.sharing.public
}
return { keychain, peer }
}

async function main() {
const { keychain: keychainA, peer: peerA } = await createPeerData()
const { keychain: keychainB, peer: peerB } = await createPeerData()

let msg = ''

let tick = performance.now()
for (let i = 0; i < 100; ++i) {
msg = packMessage(faker.random.words(4), peerB, keychainA)
// // const bToA = packMessage(faker.random.words(4), peerA, keychainB)
// const foo = unpackMessage(aToB, peerA, keychainB)
// // const bar = unpackMessage(bToA, peerB, keychainA)
// //console.dir({ foo, bar, aToB, bToA })
}
let tock = performance.now()
console.log('Send', (100 * 1000) / (tock - tick))

tick = performance.now()
for (let i = 0; i < 100; ++i) {
unpackMessage(msg, peerA, keychainB)
}
tock = performance.now()
console.log('Receive', (100 * 1000) / (tock - tick))
}

main()
9 changes: 9 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export * from './primitives/hash'
export * from './primitives/pbkdf2'
export * from './srp'
export * from './tss'
export * from './masterKey'
export * from './account'
export * from './keychain'
export * from './peers'
export * from './projects'
20 changes: 20 additions & 0 deletions src/keychain.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { generateKey } from '@47ng/cloak'
import { createKeychain, lockKeychain, unlockKeychain } from './keychain'

describe('Keychain', () => {
test('Lock/unlock', async () => {
const keychain = createKeychain()
const key = generateKey()
const locked = await lockKeychain(keychain, key)
const unlocked = await unlockKeychain(locked, key)
expect(keychain).toEqual(unlocked)
})

test('Locking should not be idempotent', async () => {
const keychain = createKeychain()
const key = generateKey()
const locked1 = await lockKeychain(keychain, key)
const locked2 = await lockKeychain(keychain, key)
expect(locked1).not.toEqual(locked2)
})
})
70 changes: 70 additions & 0 deletions src/keychain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import nacl from 'tweetnacl'
import { CloakKey, encryptString, decryptString } from '@47ng/cloak'
import { b64 } from '@47ng/codec'

export interface Keychain {
signature: {
secret: string // base64url, encrypted with the keychain key
public: string // base64url
}
sharing: {
secret: string
public: string
}
}

export interface UnlockedKeychain {
signature: nacl.SignKeyPair
sharing: nacl.BoxKeyPair
}

// --

export function createKeychain(): UnlockedKeychain {
return {
signature: nacl.sign.keyPair(),
sharing: nacl.box.keyPair()
}
}

// --

export async function lockKeychain(
input: UnlockedKeychain,
keychainKey: CloakKey
): Promise<Keychain> {
return {
signature: {
secret: await encryptString(
b64.encode(input.signature.secretKey),
keychainKey
),
public: b64.encode(input.signature.publicKey)
},
sharing: {
secret: await encryptString(
b64.encode(input.sharing.secretKey),
keychainKey
),
public: b64.encode(input.sharing.publicKey)
}
}
}

// --

export async function unlockKeychain(
input: Keychain,
keychainKey: CloakKey
): Promise<UnlockedKeychain> {
const signatureSecret = await decryptString(
input.signature.secret,
keychainKey
)
const sharingSecret = await decryptString(input.sharing.secret, keychainKey)

return {
signature: nacl.sign.keyPair.fromSecretKey(b64.decode(signatureSecret)),
sharing: nacl.box.keyPair.fromSecretKey(b64.decode(sharingSecret))
}
}
Loading

0 comments on commit ba63c38

Please sign in to comment.