Skip to content

Commit

Permalink
Crypto lib with public key compression (bluesky-social#139)
Browse files Browse the repository at this point in the history
* split out crypto lib & add public key compress/decompress

* split out crypto lib & integrate into awake

* better semantics around aes keys
  • Loading branch information
dholms authored Jun 16, 2022
1 parent da922da commit 3d1894d
Show file tree
Hide file tree
Showing 28 changed files with 1,259 additions and 149 deletions.
1 change: 1 addition & 0 deletions awake/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
},
"dependencies": {
"@adxp/auth": "*",
"@adxp/crypto": "*",
"one-webcrypto": "^1.0.3",
"socket.io-client": "^4.5.1",
"ucans": "^0.9.1",
Expand Down
115 changes: 0 additions & 115 deletions awake/src/crypto.ts

This file was deleted.

27 changes: 10 additions & 17 deletions awake/src/provider.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Channel from './channel.js'
import * as messages from './messages.js'
import * as crypto from './crypto.js'
import * as auth from '@adxp/auth'
import * as crypto from '@adxp/crypto'

export type PinParams = {
pin: number
Expand All @@ -14,15 +14,15 @@ export type onSuccess = (channelDid: string) => void
const YEAR_IN_SECONDS = 60 * 60 * 24 * 30 * 12

export class Provider {
sessionKey: CryptoKey | null = null
sessionKey: crypto.AesKey | null = null
negotiateChannel: Channel | null = null
recipientDid: string | null = null

constructor(
public announceChannel: Channel,
public rootDid: string,
public authStore: auth.AuthStore,
public tempKeypair: CryptoKeyPair,
public tempKeypair: crypto.EcdhKeypair,
) {}

static async create(
Expand All @@ -31,7 +31,7 @@ export class Provider {
authStore: auth.AuthStore,
): Promise<Provider> {
const announceChannel = new Channel(host, rootDid)
const tempKeypair = await crypto.makeEcdhKeypair()
const tempKeypair = await crypto.EcdhKeypair.create()
const provider = new Provider(
announceChannel,
rootDid,
Expand Down Expand Up @@ -65,22 +65,15 @@ export class Provider {
const channelDid = reqMsg.channel_did
this.negotiateChannel = new Channel(this.announceChannel.host, channelDid)

const userPubkey = await crypto.pubkeyFromDid(channelDid)
this.sessionKey = await crypto.deriveSharedKey(
this.tempKeypair.privateKey,
userPubkey,
)
this.sessionKey = await this.tempKeypair.deriveSharedKey(channelDid)

const tempDid = await crypto.didForKeypair(this.tempKeypair)
const tempDid = await this.tempKeypair.did()
const sessionUcan = await this.authStore.createAwakeProof(
tempDid,
auth.writeCap(this.rootDid),
)

const encryptedUcan = await crypto.encrypt(
sessionUcan.encoded(),
this.sessionKey,
)
const encryptedUcan = await this.sessionKey.encrypt(sessionUcan.encoded())

this.negotiateChannel.sendMessage(
messages.negotiateSession(tempDid, encryptedUcan),
Expand All @@ -94,11 +87,11 @@ export class Provider {
throw new Error('AWAKE out of sync')
}
const msg = await this.negotiateChannel.awaitMessage(['Awake_Share_Pin'])
const pin = parseInt(await crypto.decrypt(msg.pin, this.sessionKey))
const pin = parseInt(await this.sessionKey.decrypt(msg.pin))
if (isNaN(pin)) {
throw new Error('Bad pin received from client')
}
this.recipientDid = await crypto.decrypt(msg.did, this.sessionKey)
this.recipientDid = await this.sessionKey.decrypt(msg.did)
return pin
}

Expand All @@ -113,7 +106,7 @@ export class Provider {
cap,
YEAR_IN_SECONDS,
)
const encrypted = await crypto.encrypt(token.encoded(), this.sessionKey)
const encrypted = await this.sessionKey.encrypt(token.encoded())
await this.negotiateChannel.sendMessage(messages.delegateCred(encrypted))
})
}
Expand Down
27 changes: 11 additions & 16 deletions awake/src/requester.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import Channel from './channel.js'
import * as messages from './messages.js'
import * as crypto from './crypto.js'
import * as ucan from 'ucans'
import * as auth from '@adxp/auth'
import * as crypto from '@adxp/crypto'

export class Requester {
sessionKey: CryptoKey | null = null
sessionKey: crypto.AesKey | null = null
negotiateChannel: Channel | null = null

constructor(
public announceChannel: Channel | null,
public rootDid: string,
public ownDid: string,
public channelKeypair: CryptoKeyPair,
public channelKeypair: crypto.EcdhKeypair,
public channelDid: string,
public pin: number,
) {}
Expand All @@ -23,8 +23,8 @@ export class Requester {
ownDid: string,
): Promise<Requester> {
const announceChannel = new Channel(host, rootDid)
const channelKeypair = await crypto.makeEcdhKeypair()
const channelDid = await crypto.didForKeypair(channelKeypair)
const channelKeypair = await crypto.EcdhKeypair.create()
const channelDid = await channelKeypair.did()
// 6 digit pin
const pin = Math.floor(Math.random() * 1000000)
const requester = new Requester(
Expand Down Expand Up @@ -70,14 +70,12 @@ export class Requester {
}

private async sendPin(provMsg: messages.NegotiateSession): Promise<number> {
const providerPubkey = await crypto.pubkeyFromDid(provMsg.prov_did)
this.sessionKey = await crypto.deriveSharedKey(
this.channelKeypair.privateKey,
providerPubkey,
this.sessionKey = await this.channelKeypair.deriveSharedKey(
provMsg.prov_did,
)

try {
const decryptedUcan = await crypto.decrypt(provMsg.ucan, this.sessionKey)
const decryptedUcan = await this.sessionKey.decrypt(provMsg.ucan)
// this function validates tokens so we just need to check att on second to the top
const token = await ucan.Chained.fromToken(decryptedUcan)
const prf = token.proofs()[0]
Expand All @@ -93,11 +91,8 @@ export class Requester {
throw new Error(`Invalid negotiation proof: ${e.toString()}`)
}

const encryptedPin = await crypto.encrypt(
this.pin.toString(),
this.sessionKey,
)
const encryptedAppDid = await crypto.encrypt(this.ownDid, this.sessionKey)
const encryptedPin = await this.sessionKey.encrypt(this.pin.toString())
const encryptedAppDid = await this.sessionKey.encrypt(this.ownDid)
if (!this.negotiateChannel) {
throw new Error('AWAKE out of sync: negotiation channel closed')
}
Expand All @@ -118,7 +113,7 @@ export class Requester {
if (!this.sessionKey) {
throw new Error('AWAKE out of sync: no session key')
}
const decrypted = await crypto.decrypt(msg.ucan, this.sessionKey)
const decrypted = await this.sessionKey.decrypt(msg.ucan)
const token = await ucan.Chained.fromToken(decrypted)
this.close()
return token
Expand Down
2 changes: 2 additions & 0 deletions crypto/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
dist
19 changes: 19 additions & 0 deletions crypto/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"root": true,
// parse TypeScript files
// https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser
"parser": "@typescript-eslint/parser",
// configure eslint using options described at
// https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin
"plugins": ["@typescript-eslint"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"prettier"
],
"rules": {
"no-var": "error"
}
}
6 changes: 6 additions & 0 deletions crypto/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"trailingComma": "all",
"tabWidth": 2,
"semi": false,
"singleQuote": true
}
6 changes: 6 additions & 0 deletions crypto/ava.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
extensions: {
ts: 'module',
},
nodeArguments: ['--loader=ts-node/esm'],
}
25 changes: 25 additions & 0 deletions crypto/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@adxp/crypto",
"version": "0.0.1",
"main": "dist/index.js",
"type": "module",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "tsc --project tsconfig.json",
"dev": "tsc -w --project tsconfig.json",
"test": "ava -v test/*.ts",
"lint": "eslint --ext .ts ."
},
"dependencies": {
"big-integer": "^1.6.51",
"ucans": "^0.9.1",
"uint8arrays": "^3.0.0"
},
"devDependencies": {
"ava": "^4.2.0",
"typescript": "^4.7.2"
}
}
Loading

0 comments on commit 3d1894d

Please sign in to comment.