diff --git a/examples/ecdh-wraps-ecdh.test.ts b/examples/ecdh-wraps-ecdh.test.ts deleted file mode 100644 index ab5c6e0..0000000 --- a/examples/ecdh-wraps-ecdh.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {expect} from 'bun:test' - -import {PrivateWrap} from '../index' - -const key_wraps = await PrivateWrap.gen_keypair() -const key_wrapped = await PrivateWrap.gen_keypair() - -const cipher = await PrivateWrap.encrypt(key_wrapped.privateKey, key_wraps.publicKey) -const box = await cipher.toString() -const unbox = await PrivateWrap.fromString(box) -const plain = await unbox.decrypt(key_wraps.privateKey) - -expect(plain).toEqual(key_wrapped.privateKey) -console.log("ecdh-wraps-ecdh OK") diff --git a/examples/ecdh-wraps-key.test.ts b/examples/ecdh-wraps-key.test.ts deleted file mode 100644 index 5d2298b..0000000 --- a/examples/ecdh-wraps-key.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {expect} from 'bun:test' - -import {PrivateWrap, SecretBox} from '../index' - -const k_wraps = await PrivateWrap.gen_keypair() -const k_wrapped = await SecretBox.gen_key() - -const cipher = await PrivateWrap.encrypt(k_wrapped, k_wraps.publicKey) -const box = await cipher.toString() -const unbox = await PrivateWrap.fromString(box) -const plain = await unbox.decrypt(k_wraps.privateKey) as CryptoKey - -expect(plain).toEqual(k_wrapped) -console.log("ecdh-wraps-key OK") diff --git a/examples/key-wraps-ecdh.test.ts b/examples/key-wraps-ecdh.test.ts deleted file mode 100644 index 70bb3d2..0000000 --- a/examples/key-wraps-ecdh.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {expect} from 'bun:test' - -import {SecretWrap, PrivateWrap} from '../index' - -const key_wraps = await SecretWrap.gen_key() -const key_wrapped = await PrivateWrap.gen_keypair() - -const cipher = await SecretWrap.encrypt(key_wrapped.privateKey, key_wraps) -const box = cipher.toString() -const unbox = SecretWrap.fromString(box) -const plain = await unbox.decrypt(key_wraps) - -expect(plain).toEqual(key_wrapped.privateKey) -console.log("key-wraps-ecdh OK") diff --git a/examples/pwd-to-signing.test.ts b/examples/pwd-to-signing.test.ts deleted file mode 100644 index 86b7ce2..0000000 --- a/examples/pwd-to-signing.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import {expect} from 'bun:test' - -import {hkdf, pbkdf, Usage} from '../src/kdf' -import {derive_keypair, sign, verify} from '../src/signature' - -const salt = new Uint8Array(32) -const pwd = "test" -const message = new TextEncoder().encode("Yeet") - -const kd = await pbkdf(salt, pwd) -const source = await hkdf(kd, Usage.sign) as Uint8Array -const [privk, pubk] = await derive_keypair(source) - -const sig = await sign(message, privk) -const verification = await verify(message, pubk, sig) -expect(verification).toBeTrue() -console.log("pwd-to-signing OK") diff --git a/examples/pwd-wraps-ecdh.test.ts b/examples/pwd-wraps-ecdh.test.ts deleted file mode 100644 index 16c9cf7..0000000 --- a/examples/pwd-wraps-ecdh.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {expect} from 'bun:test' - -import {hkdf, pbkdf, Usage} from '../src/kdf' -import {PrivateWrap, SecretWrap} from '../index' - -const salt = new Uint8Array(32) -const pwd = "test" -const keypair = await PrivateWrap.gen_keypair() - -const kd = await pbkdf(salt, pwd) -const k = await hkdf(kd, Usage.wrap) as CryptoKey - -const cipher = await SecretWrap.encrypt(keypair.privateKey, k) -const box = cipher.toString() -const unbox = SecretWrap.fromString(box) -const plain = await unbox.decrypt(k) - -expect(plain).toEqual(keypair.privateKey) -console.log("pwd-wraps-ecdh OK") diff --git a/package.json b/package.json index 8ba07ed..94f0678 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ }, "devDependencies": { "@types/bun": "^1.1.2", + "bun": "^1.1.27", "logger-console": "git+https://git.pband.ch/typescript/logger-console.git", "prettier": "^3.3.3" }, diff --git a/test/kdf.test.ts b/test/kdf.test.ts deleted file mode 100644 index c9d95ad..0000000 --- a/test/kdf.test.ts +++ /dev/null @@ -1,93 +0,0 @@ -import {describe, expect, test} from 'bun:test' -import {kdf, PrivateWrap} from '../index' -import {ecdh} from "../src/kdf"; - -describe('Passwords', () => { - test('Base case', async () => { - const p = "yeet" - const s = new Uint8Array(2) - - const k1 = await kdf.pbkdf(s, p) - const k2 = await kdf.pbkdf(s, p) - - expect(k1).toEqual(k2) - }) - test('Different salt, different key', async () => { - const password = "yeet" - const s1 = new Uint8Array(1) - const s2 = new Uint8Array(2) - expect(s1).not.toEqual(s2) - - const k1 = await kdf.pbkdf(s1, password) - const k2 = await kdf.pbkdf(s2, password) - - expect(k2).not.toEqual(k1) - }) - test('Different password, different key', async () => { - const p1 = "yeet" - const p2 = "yaat" - expect(p1).not.toBe(p2) - const s = new Uint8Array(2) - - const k1 = await kdf.pbkdf(s, p1) - const k2 = await kdf.pbkdf(s, p2) - - expect(k1).not.toBe(k2) - }) -}) -describe('HKDF', () => { - test ('Base case', async () => { - const k = new Uint8Array(12) - const usage = kdf.Usage.sign - - const k1 = await kdf.hkdf(k, usage) - const k2 = await kdf.hkdf(k, usage) - - expect(k2).toEqual(k1) - }) - test('Different usage, different key', async () => { - const k = new Uint8Array(12) - const u1 = kdf.Usage.sign - const u2 = kdf.Usage.wrap - - const k1 = await kdf.hkdf(k, u1) - const k2 = await kdf.hkdf(k, u2) - - expect(k1).not.toEqual(k2) - }) - test('Different input, different output', async () => { - const k1 = new Uint8Array(1) - const k2 = new Uint8Array(2) - const u = kdf.Usage.sign - - const kd1 = await kdf.hkdf(k1, u) - const kd2 = await kdf.hkdf(k2, u) - - expect(kd1).not.toEqual(kd2) - }) - test.todo('Usages are set') - test.todo('Not extractable') -}) -describe('ECDH', () => { - test('Base case', async () => { - const k1 = await PrivateWrap.gen_keypair() - const k2 = await PrivateWrap.gen_keypair() - - const kd1 = await ecdh(k1.privateKey, k2.publicKey) - expect(kd1.extractable).toBe(false) - const kd2 = await ecdh(k2.privateKey, k1.publicKey) - expect(kd2.extractable).toBe(false) - - expect(kd1).toEqual(kd2) - }) - test('Different pubkey, different key', async () => { - const k1 = await PrivateWrap.gen_keypair() - const k2 = await PrivateWrap.gen_keypair() - const k3 = await PrivateWrap.gen_keypair() - - const kd1 = await ecdh(k1.privateKey, k2.publicKey) - const kd2 = await ecdh(k3.privateKey, k1.publicKey) - - expect(kd1).not.toBe(kd2) - }) -}) diff --git a/test/misc.test.ts b/test/misc.test.ts new file mode 100644 index 0000000..790be14 --- /dev/null +++ b/test/misc.test.ts @@ -0,0 +1,45 @@ +import {expect, test} from 'bun:test' +import {PrivateBox, PrivateWrap, SecretBox, signature} from '..' +import {pubkey_fromString, pubkey_toString, Usage} from '../src/misc' + +test('Private box', async () => { + const message = crypto.getRandomValues(new Uint8Array(8)) + const k = await PrivateBox.gen(false) + + const ser = await pubkey_toString(k.publicKey) + const de = await pubkey_fromString(ser, Usage.ecdh) + expect(de).not.toBeNull() + + const box = await PrivateBox.encrypt(message, de!) + const unbox = await box.decrypt(k.privateKey) + expect(unbox).toEqual(message) +}) +test('Private wrap', async () => { + const k = await PrivateWrap.gen(false) + + const ser = await pubkey_toString(k.publicKey) + const de = await pubkey_fromString(ser, Usage.ecdh) + expect(de).not.toBeNull() + + const message = crypto.getRandomValues(new Uint8Array(8)) + const k_wrapped = await SecretBox.gen(true) + const boxed_message = await SecretBox.encrypt(message, k_wrapped) + const box = await PrivateWrap.encrypt(k_wrapped, de!) + const unbox = await box.decrypt(k.privateKey) + expect(unbox).not.toBeNull() + + const unboxed_message = await boxed_message.decrypt(unbox!) + expect(unboxed_message).toEqual(message) +}) +test('Signature', async () => { + const k = await signature.gen(false) + const message = crypto.getRandomValues(new Uint8Array(8)) + const signed = await signature.sign(message, k.privateKey) + + const ser = await pubkey_toString(k.publicKey) + const de = await pubkey_fromString(ser, Usage.sign) + expect(de).not.toBeNull() + + const verification = await signature.verify(message, de!, signed) + expect(verification).toBeTrue() +}) diff --git a/test/private-box.test.ts b/test/private-box.test.ts new file mode 100644 index 0000000..d224277 --- /dev/null +++ b/test/private-box.test.ts @@ -0,0 +1,46 @@ +import {beforeAll, expect, test} from 'bun:test' +import {PrivateBox} from '..' +import {pubkey_toString} from '../src/misc' + +let k1!: CryptoKeyPair; +let k2!: CryptoKeyPair; +let message!: Uint8Array; + +beforeAll(async () => { + k1 = await PrivateBox.gen(false) + k2 = await PrivateBox.gen(true) + message = new TextEncoder().encode("Salut ! ça va ?") +}) + +test('base case', async () => { + const box = await PrivateBox.encrypt(message, k1.publicKey) + const unboxed = await box.decrypt(k1.privateKey) + expect(unboxed).toEqual(message) +}) +test("Different key can't decrypt", async () => { + const box = await PrivateBox.encrypt(message, k1.publicKey) + const unboxed = await box.decrypt(k2.privateKey) + expect(unboxed).toBeNull() +}) + +test('Key generation', async () => { + const ser1 = await pubkey_toString(k1.publicKey) + const ser2 = await pubkey_toString(k2.publicKey) + expect(ser1).not.toEqual(ser2) + + expect(k1.privateKey.extractable).toBeFalse() + expect(k1.publicKey.extractable).toBeTrue() + expect(k2.privateKey.extractable).toBeTrue() + expect(k2.publicKey.extractable).toBeTrue() +}) + +test('serialization', async () => { + const message = new Uint8Array(8) + const box = await PrivateBox.encrypt(message, k1.publicKey) + + const ser = await box.toString() + const de = await PrivateBox.fromString(ser) + expect(de).not.toBeNull() + + expect(de).toEqual(box) +}) diff --git a/test/private-wrap.test.ts b/test/private-wrap.test.ts new file mode 100644 index 0000000..3149f45 --- /dev/null +++ b/test/private-wrap.test.ts @@ -0,0 +1,45 @@ +import {beforeAll, expect, test} from 'bun:test' +import {PrivateWrap, SecretBox} from '..' +import {pubkey_toString} from '../src/misc' + +let k1!: CryptoKeyPair; +let k2!: CryptoKeyPair; +let message!: CryptoKey; + +beforeAll(async () => { + k1 = await PrivateWrap.gen(false) + k2 = await PrivateWrap.gen(true) + message = await SecretBox.gen(true) +}) + +test('base case', async () => { + const box = await PrivateWrap.encrypt(message, k1.publicKey) + const unboxed = await box.decrypt(k1.privateKey) + expect(unboxed).toEqual(message) +}) +test("Different key can't decrypt", async () => { + const box = await PrivateWrap.encrypt(message, k1.publicKey) + const unboxed = await box.decrypt(k2.privateKey) + expect(unboxed).toBeNull() +}) + +test('Key generation', async () => { + const ser1 = await pubkey_toString(k1.publicKey) + const ser2 = await pubkey_toString(k2.publicKey) + expect(ser1).not.toEqual(ser2) + + expect(k1.privateKey.extractable).toBeFalse() + expect(k1.publicKey.extractable).toBeTrue() + expect(k2.privateKey.extractable).toBeTrue() + expect(k2.publicKey.extractable).toBeTrue() +}) + +test('serialization', async () => { + const box = await PrivateWrap.encrypt(message, k1.publicKey) + + const ser = await box.toString() + const de = await PrivateWrap.fromString(ser) + expect(de).not.toBeNull() + + expect(de).toEqual(box) +}) diff --git a/test/pwd-box.test.ts b/test/pwd-box.test.ts new file mode 100644 index 0000000..67d2e64 --- /dev/null +++ b/test/pwd-box.test.ts @@ -0,0 +1,34 @@ +import {beforeAll, expect, test} from 'bun:test' +import {PwdBox} from '..' + +let k1!: string; +let k2!: string; +let message!: Uint8Array; + +beforeAll(async () => { + k1 = "abc" + k2 = "def" + message = new TextEncoder().encode("Salut ! ça va ?") +}) + +test('base case', async () => { + const box = await PwdBox.encrypt(message, k1) + const unboxed = await box.decrypt(k1) + expect(unboxed).toEqual(message) +}) +test("Different key can't decrypt", async () => { + const box = await PwdBox.encrypt(message, k1) + const unboxed = await box.decrypt(k2) + expect(unboxed).toBeNull() +}) + +test('serialization', async () => { + const message = new Uint8Array(8) + const box = await PwdBox.encrypt(message, k1) + + const ser = box.toString() + const de = PwdBox.fromString(ser) + expect(de).not.toBeNull() + + expect(de).toEqual(box) +}) diff --git a/test/pwd-wrap.test.ts b/test/pwd-wrap.test.ts new file mode 100644 index 0000000..d065262 --- /dev/null +++ b/test/pwd-wrap.test.ts @@ -0,0 +1,33 @@ +import {beforeAll, expect, test} from 'bun:test' +import {PwdWrap, SecretBox} from '..' + +let k1!: string; +let k2!: string; +let message!: CryptoKey; + +beforeAll(async () => { + k1 = "abc" + k2 = "def" + message = await SecretBox.gen(true) +}) + +test('base case', async () => { + const box = await PwdWrap.encrypt(message, k1) + const unboxed = await box.decrypt(k1) + expect(unboxed).toEqual(message) +}) +test("Different key can't decrypt", async () => { + const box = await PwdWrap.encrypt(message, k1) + const unboxed = await box.decrypt(k2) + expect(unboxed).toBeNull() +}) + +test('serialization', async () => { + const box = await PwdWrap.encrypt(message, k1) + + const ser = box.toString() + const de = PwdWrap.fromString(ser) + expect(de).not.toBeNull() + + expect(de).toEqual(box) +}) diff --git a/test/secret-box.test.ts b/test/secret-box.test.ts new file mode 100644 index 0000000..8af0864 --- /dev/null +++ b/test/secret-box.test.ts @@ -0,0 +1,39 @@ +import {beforeAll, expect, test} from 'bun:test' +import {SecretBox} from '..' + +let k1!: CryptoKey; +let k2!: CryptoKey; +let message!: Uint8Array; + +beforeAll(async () => { + k1 = await SecretBox.gen(false) + k2 = await SecretBox.gen(true) + message = new TextEncoder().encode("Salut ! ça va ?") +}) + +test('base case', async () => { + const box = await SecretBox.encrypt(message, k1) + const unboxed = await box.decrypt(k1) + expect(unboxed).toEqual(message) +}) +test("Different key can't decrypt", async () => { + const box = await SecretBox.encrypt(message, k1) + const unboxed = await box.decrypt(k2) + expect(unboxed).toBeNull() +}) + +test('Key generation', async () => { + expect(k1.extractable).toBeFalse() + expect(k2.extractable).toBeTrue() +}) + +test('serialization', async () => { + const message = new Uint8Array(8) + const box = await SecretBox.encrypt(message, k1) + + const ser = box.toString() + const de = SecretBox.fromString(ser) + expect(de).not.toBeNull() + + expect(de).toEqual(box) +}) diff --git a/test/secret-wrap.test.ts b/test/secret-wrap.test.ts new file mode 100644 index 0000000..7c85e75 --- /dev/null +++ b/test/secret-wrap.test.ts @@ -0,0 +1,38 @@ +import {beforeAll, expect, test} from 'bun:test' +import {SecretWrap} from '..' + +let k1!: CryptoKey; +let k2!: CryptoKey; +let message!: CryptoKey; + +beforeAll(async () => { + k1 = await SecretWrap.gen(false) + k2 = await SecretWrap.gen(true) + message = await SecretWrap.gen(true) +}) + +test('base case', async () => { + const box = await SecretWrap.encrypt(message, k1) + const unboxed = await box.decrypt(k1) + expect(unboxed).toEqual(message) +}) +test("Different key can't decrypt", async () => { + const box = await SecretWrap.encrypt(message, k1) + const unboxed = await box.decrypt(k2) + expect(unboxed).toBeNull() +}) + +test('Key generation', async () => { + expect(k1.extractable).toBeFalse() + expect(k2.extractable).toBeTrue() +}) + +test('serialization', async () => { + const box = await SecretWrap.encrypt(message, k1) + + const ser = box.toString() + const de = SecretWrap.fromString(ser) + expect(de).not.toBeNull() + + expect(de).toEqual(box) +}) diff --git a/test/signature.test.ts b/test/signature.test.ts index 4cf707d..ac48892 100644 --- a/test/signature.test.ts +++ b/test/signature.test.ts @@ -1,10 +1,10 @@ import {test, expect} from 'bun:test' import {signature} from '../index' -import {gen_keypair, sign, verify} from '../src/signature' +import {gen, sign, verify} from '../src/signature' test('base case', async () => { - const keypair = await gen_keypair() + const keypair = await gen() expect(keypair.privateKey.extractable).toBeTrue() expect(keypair.publicKey.extractable).toBeTrue() const data = new TextEncoder().encode('Message 123 !') @@ -16,9 +16,9 @@ test('base case', async () => { }) test('extractable or not', async () => { - const kp1 = await gen_keypair() - const kp2 = await gen_keypair(true) - const kp3 = await gen_keypair(false) + const kp1 = await gen() + const kp2 = await gen(true) + const kp3 = await gen(false) expect(kp1.privateKey.extractable).toBeTrue() expect(kp2.privateKey.extractable).toBeTrue() @@ -30,14 +30,14 @@ test('extractable or not', async () => { }) test('inverted keys', async () => { - const keypair = await signature.gen_keypair() + const keypair = await signature.gen() const data = new TextEncoder().encode('Message 123 !') expect(async () => await sign(data, keypair.publicKey)).toThrow() }) test('tampered message', async () => { - const keypair = await signature.gen_keypair() + const keypair = await signature.gen() const data1 = new TextEncoder().encode('Message 123 !') const data2 = new TextEncoder().encode('Message 321 !') expect(data1).not.toEqual(data2) @@ -49,8 +49,8 @@ test('tampered message', async () => { }) test('different keypair', async () => { - const keypair = await signature.gen_keypair() - const keypair2 = await signature.gen_keypair() + const keypair = await signature.gen() + const keypair2 = await signature.gen() const data = new TextEncoder().encode('Message 123 !') const sig = await sign(data, keypair.privateKey) @@ -60,7 +60,7 @@ test('different keypair', async () => { }) test('tampered signature', async () => { - const keypair = await signature.gen_keypair() + const keypair = await signature.gen() const data = new TextEncoder().encode('Message 123 !') const sig = await sign(data, keypair.privateKey) diff --git a/test/wrap.test.ts b/test/wrap.test.ts new file mode 100644 index 0000000..7183f4c --- /dev/null +++ b/test/wrap.test.ts @@ -0,0 +1,86 @@ +import {PrivateBox, PrivateWrap, SecretBox, SecretWrap, signature} from '..' +import {beforeAll, expect, test} from 'bun:test' + +let wrap_key!: CryptoKey; + +beforeAll(async () => { + wrap_key = await SecretWrap.gen(true) +}) + +async function seal(key: CryptoKey): Promise { + const box = await SecretWrap.encrypt(key, wrap_key) + const unboxed = await box.decrypt(wrap_key) + expect(unboxed).not.toBeNull() + return unboxed! +} +async function cant_seal(key: CryptoKey): Promise { + expect(key.extractable).toBeFalse() + expect(SecretWrap.encrypt(key, wrap_key)).rejects.toThrow() +} + +test('Signature', async () => { + const k = await signature.gen(true) + const privk = await seal(k.privateKey) + + const message = new Uint8Array(8) + const signed = await signature.sign(message, privk) + const verification = await signature.verify(message, k.publicKey, signed) + expect(verification).toBeTrue() +}) +test('SecretWrap', async () => { + let k = await SecretWrap.gen(true) + const box = await SecretWrap.encrypt(k, k) // Please kids, never do this for real ! + k = await seal(k) + + const unbox = await box.decrypt(k) + expect(unbox).not.toBeNull() + expect(unbox).toEqual(k) +}) +test('SecretBox', async () => { + const message = crypto.getRandomValues(new Uint8Array(8)) + let k = await SecretBox.gen(true) + const box = await SecretBox.encrypt(message, k) + k = await seal(k) + + const unbox = await box.decrypt(k) + expect(unbox).not.toBeNull() + expect(unbox).toEqual(message) +}) +test('PrivateWrap', async () => { + const k = await PrivateWrap.gen(true) + const box = await PrivateWrap.encrypt(wrap_key, k.publicKey) + const privk = await seal(k.privateKey) + + const unbox = await box.decrypt(privk) + expect(unbox).not.toBeNull() + expect(unbox).toEqual(wrap_key) +}) +test('PrivateBox', async () => { + const message = crypto.getRandomValues(new Uint8Array(8)) + let k = await PrivateBox.gen(true) + const box = await PrivateBox.encrypt(message, k.publicKey) + const privk = await seal(k.privateKey) + + const unbox = await box.decrypt(privk) + expect(unbox).not.toBeNull() + expect(unbox).toEqual(message) +}) +test("Can't unwrap with a different key", async () => { + const wrap_k2 = await SecretWrap.gen(false) + const box = await SecretWrap.encrypt(wrap_key, wrap_key) // Never do this kids ! + const unbox = await box.decrypt(wrap_k2) + expect(unbox).toBeNull() +}) +test('Cant wrap non-extractable', async () => { + const k_sb = await SecretBox.gen(false) + const k_sw = await SecretWrap.gen(false) + const k_pb = await PrivateBox.gen(false) + const k_pw = await PrivateWrap.gen(false) + const sig = await signature.gen(false) + + await cant_seal(k_sb) + await cant_seal(k_sw) + await cant_seal(k_pb.privateKey) + await cant_seal(k_pw.privateKey) + await cant_seal(sig.privateKey) +})