Implement asym box
This commit is contained in:
+45
-12
@@ -1,24 +1,57 @@
|
||||
import {Result} from 'result'
|
||||
import * as misc from 'misc'
|
||||
|
||||
export type PubKey = void
|
||||
export type PrivKey = void
|
||||
export type PubKey = CryptoKey
|
||||
export type PrivKey = CryptoKey
|
||||
|
||||
export class PrivateBox<T> {
|
||||
public static gen_keypair() : [PrivKey, PubKey] {
|
||||
throw "todo"
|
||||
const algorithm: RsaOaepParams = {name: "RSA-OAEP"}
|
||||
|
||||
export class PrivateBox<T extends ArrayBufferView> {
|
||||
readonly cipher: Uint8Array;
|
||||
readonly _phantom!: T;
|
||||
|
||||
private constructor(cipher: Uint8Array) {
|
||||
this.cipher = cipher
|
||||
}
|
||||
|
||||
public static encrypt<T>(key: PubKey, data: Uint8Array) : PrivateBox<T> {
|
||||
throw "todo"
|
||||
public static async gen_keypair(extractable: boolean = false): Promise<[PrivKey, PubKey]> {
|
||||
const keys = await window.crypto.subtle.generateKey(
|
||||
{
|
||||
name: "RSA-OAEP",
|
||||
modulusLength: 4096,
|
||||
publicExponent: new Uint8Array([1, 0, 1]),
|
||||
hash: {name: "SHA-512"}
|
||||
},
|
||||
extractable,
|
||||
["encrypt", "decrypt"]
|
||||
)
|
||||
|
||||
return [keys.privateKey, keys.publicKey]
|
||||
}
|
||||
public decrypt(key: PrivKey) : Result<Uint8Array> {
|
||||
throw "todo"
|
||||
|
||||
public static async encrypt<T extends ArrayBufferView>(key: PubKey, data: T): Promise<Result<PrivateBox<T>>> {
|
||||
try {
|
||||
const cipher = await window.crypto.subtle.encrypt(algorithm, key, data)
|
||||
return Result.ok(new PrivateBox(new Uint8Array(cipher)))
|
||||
} catch(_) {}
|
||||
|
||||
return Result.error([])
|
||||
}
|
||||
public async decrypt(key: PrivKey): Promise<Result<Uint8Array>> {
|
||||
try {
|
||||
const plain = await window.crypto.subtle.decrypt(algorithm, key, this.cipher)
|
||||
return Result.ok(new Uint8Array(plain))
|
||||
} catch(_) {}
|
||||
|
||||
return Result.error([])
|
||||
}
|
||||
|
||||
public toString() : string {
|
||||
throw "todo"
|
||||
return misc.a2b64(new Uint8Array(this.cipher))
|
||||
}
|
||||
public static fromString<T>(data: string) : Result<PrivateBox<T>> {
|
||||
throw "todo"
|
||||
public static fromString<T extends ArrayBufferView>(data: string) : Result<PrivateBox<T>> {
|
||||
const res = misc.b642a(data)
|
||||
if (res.error()) return Result.error([])
|
||||
return Result.ok(new PrivateBox(res.unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import {beforeAll, expect, test} from 'bun:test'
|
||||
|
||||
import * as asymmetric from 'boxes/asymmetric'
|
||||
|
||||
let k1!: [asymmetric.PrivKey, asymmetric.PubKey];
|
||||
let k2!: [asymmetric.PrivKey, asymmetric.PubKey];
|
||||
|
||||
beforeAll(async () => {
|
||||
k1 = await asymmetric.PrivateBox.gen_keypair(false)
|
||||
k2 = await asymmetric.PrivateBox.gen_keypair(true)
|
||||
|
||||
expect(k1[0].extractable).toBe(false)
|
||||
expect(k1[1].extractable).toBe(true)
|
||||
expect(k2[0].extractable).toBe(true)
|
||||
expect(k2[1].extractable).toBe(true)
|
||||
})
|
||||
|
||||
test('base case', async () => {
|
||||
const [priv, pub] = k1
|
||||
const data = new Uint8Array([1, 2, 3, 4, 5])
|
||||
|
||||
const box = (await asymmetric.PrivateBox.encrypt<Uint8Array>(pub, data)).expect("Should encrypt the data")
|
||||
const result = (await box.decrypt(priv)).expect("Should decrypt the data")
|
||||
|
||||
expect(result).toEqual(data)
|
||||
})
|
||||
|
||||
test('toString and fromString are inverses', async () => {
|
||||
const [priv, pub] = k1
|
||||
const data = new Uint8Array([1, 2, 3, 4, 5])
|
||||
|
||||
const box = (await asymmetric.PrivateBox.encrypt<Uint8Array>(pub, data)).expect("Should encrypt the data")
|
||||
const str = box.toString()
|
||||
const box2 = asymmetric.PrivateBox.fromString<Uint8Array>(str).expect("Should parse the string")
|
||||
const plain = (await box2.decrypt(priv)).expect("Should decrypt the data")
|
||||
|
||||
expect(plain).toEqual(data)
|
||||
})
|
||||
|
||||
test('Tampered cipher fails', async () => {
|
||||
const [priv, pub] = k1
|
||||
const data = new Uint8Array([1, 2, 3, 4, 5])
|
||||
|
||||
const box = (await asymmetric.PrivateBox.encrypt<Uint8Array>(pub, data)).expect("Should encrypt the data")
|
||||
box.cipher[0] += 1
|
||||
;(await box.decrypt(priv)).expect_err("Should fail to decrypt the data")
|
||||
})
|
||||
|
||||
test('Wrong pubkey should fail', async () => {
|
||||
const [_priv, pub] = k1
|
||||
const [priv, _pub] = k2
|
||||
const data = new Uint8Array([1, 2, 3, 4, 5])
|
||||
|
||||
const box = (await asymmetric.PrivateBox.encrypt(pub, data)).expect("Should encrypt the data")
|
||||
;(await box.decrypt(priv)).expect_err("Should fail to decrypt the data")
|
||||
})
|
||||
Reference in New Issue
Block a user