Skip to content

Commit

Permalink
factoring
Browse files Browse the repository at this point in the history
  • Loading branch information
OR13 committed Nov 13, 2023
1 parent 57da658 commit 329743e
Show file tree
Hide file tree
Showing 24 changed files with 582 additions and 602 deletions.
7 changes: 6 additions & 1 deletion src/diagnostic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,14 @@ const alternateDiagnostic = async (
let text = await cbor.diagnose(data, {
separator: '\n'
})
text = text.replace(/\{/gm, '{\n')
text = text.replace(/\}/gm, '\n}')

text = text.replace(/\[/gm, '[\n')
text = text.replace(/, /gm, ',\n')
text = text.replace(/\]/gm, '\n]')

text = text.replace(/, /gm, ',\n')

return text

}
Expand Down
2 changes: 1 addition & 1 deletion test/cometre/consistency-proof.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
},
h'430b6fd7...f74c7fc4', / Payload /
h'46c9ddd5...3b7ccc71' / Signature /
h'd379a1af...06bb94c8' / Signature /
]
)
~~~~
Expand Down
2 changes: 1 addition & 1 deletion test/cometre/inclusion-proof.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
},
nil, / Detached payload /
h'22c282ce...dcc30d44' / Signature /
h'f50218fb...5d604ccd' / Signature /
]
)
~~~~
Expand Down
51 changes: 12 additions & 39 deletions test/hpke/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ Inspired by https://datatracker.ietf.org/doc/html/rfc7516#section-7.2.1
"crv": "P-256",
"alg": "HPKE-Base-P256-SHA256-AES128GCM",
"kid": "test-key-42",
"x": "BFzUqQqyrg5c3wkZN7Qs6shAxKRJXqlN2MVSoLprpmE",
"y": "UCvYMCp-7MCOl7JRRYUXdP7pPNRVFLrc2RZ_yLp5cqM",
"x": "2JStVF6Qnj_okF-tMh83YmHGloNG0YAUnUm7ft0EZNo",
"y": "LFkWC9_frlU71b1yNKc7f_eAsosKCOuwZ7-3GjTo3f8",
"use": "enc",
"key_ops": [
"deriveBits"
Expand All @@ -44,9 +44,9 @@ Inspired by https://datatracker.ietf.org/doc/html/rfc7516#section-7.2.1
"crv": "P-256",
"alg": "HPKE-Base-P256-SHA256-AES128GCM",
"kid": "test-key-42",
"x": "BFzUqQqyrg5c3wkZN7Qs6shAxKRJXqlN2MVSoLprpmE",
"y": "UCvYMCp-7MCOl7JRRYUXdP7pPNRVFLrc2RZ_yLp5cqM",
"d": "87Vyg4ckRaep1giXTZMG_q6dBISG3Wn8Whnp3HPn4fQ",
"x": "2JStVF6Qnj_okF-tMh83YmHGloNG0YAUnUm7ft0EZNo",
"y": "LFkWC9_frlU71b1yNKc7f_eAsosKCOuwZ7-3GjTo3f8",
"d": "aba0qLA8Usjo9-a_BCIQmpBpx0R8txWw9ghqfhNyU0o",
"key_ops": [
"deriveBits"
]
Expand All @@ -59,8 +59,8 @@ https://datatracker.ietf.org/doc/html/draft-rha-jose-hpke-encrypt-01#section-4.1

~~~~ json
{
"protected": "eyJhbGciOiJIUEtFLUJhc2UtUDI1Ni1TSEEyNTYtQUVTMTI4R0NNIiwiZW5jIjoiQkpPV1JGNHRWZmVWZkRxUjBRTExuM2FlWnh6ankzeW8xaDNhVjNFbnh6LVpwamxJdzZWY3BLZ1lPR2FweEdOd2c1N0s5b3FFUnF0MjVqSWp0R0lJSFZzIiwia2lkIjoidGVzdC1rZXktNDIifQ",
"ciphertext": "-yHU4AniXNB1CvQqC-9whZ3vpsNiw_PqLlM_"
"protected": "eyJhbGciOiJIUEtFLUJhc2UtUDI1Ni1TSEEyNTYtQUVTMTI4R0NNIiwiZW5jIjoiQkZvRnhpQU5KdnBNZ0t5dUlOdU0wVzhJTF9vdnQxTy1QUkZHTVdPcFByR3gtWTMzMEFHSDlKTGYzNDNRVFZzSXJZV2F4bnc4WHdvaVFfd1I3dk0xdWxvIiwia2lkIjoidGVzdC1rZXktNDIifQ",
"ciphertext": "QlzHZ4vj-N2ZBqidEpzg6XKZ1tDGHsFntXnu"
}
~~~~

Expand All @@ -75,13 +75,13 @@ https://datatracker.ietf.org/doc/html/draft-rha-jose-hpke-encrypt-01#section-4.1
"recipients": [
{
"kid": "test-key-42",
"enc": "BLO6UFa5-QKzLAIbsy8I7J9hy6eD0X0iPxHkPLPWkAiPejDZQA89SlJQM9g-6scp3XjedYATtXC3xr71ot7DiXI",
"encrypted_key": "2i2tygZC46UFgwIZbdGoS2RGKgKOMDz1xWKWcw42Jrs"
"enc": "BGSJWJGMxKF2eihNqjLfTS9TNPq43QwKJvQCJVRyqIMree-kM_bcF475OU0mqvIwt-IPp9PDdIVd2eVIeK2TuUY",
"encrypted_key": "YwtPrU7hK7_j5QoFoWoyOaoAsVTAWCo8mtIrlU_XhaA"
}
]
},
"iv": "4TTSFSPxE3lsq7v_",
"ciphertext": "0tSAg4olHnqs5Cb_1e-M8OJdBaTY2ekQo7Ev"
"iv": "ZJ-tN_AYmy8TtGsx",
"ciphertext": "3_csqoDkolTdG3VgtG-sm7ZpuWYa0kG4_N8m"
}
~~~~

Expand Down Expand Up @@ -117,33 +117,6 @@ Enc_structure = [
~~~~

## Public Key

~~~~ cbor-diag
{ / COSE Key /
1: 2, / Type /
2: h'74657374...792d3432', / Identifier /
3: TBD, / Algorithm /
-1: 1, / Curve /
-2: h'045cd4a9...ba6ba661', / x public key component /
-3: h'502bd830...ba7972a3', / y public key component /
}
~~~~

## Private Key

~~~~ cbor-diag
{ / COSE Key /
1: 2, / Type /
2: h'74657374...792d3432', / Identifier /
3: TBD, / Algorithm /
-1: 1, / Curve /
-2: h'045cd4a9...ba6ba661', / x public key component /
-3: h'502bd830...ba7972a3', / y public key component /
-4: h'f3b57283...73e7e1f4', / d private key component /
}
~~~~

## Single Recipient / One Layer Structure

See https://datatracker.ietf.org/doc/html/draft-ietf-cose-hpke-07#section-3.1.1
Expand All @@ -169,7 +142,7 @@ See https://datatracker.ietf.org/doc/html/draft-ietf-cose-hpke-07#section-3.1.2
h'4F1EE8FE6B430057B83500FDC807EE679E0FE59F34B462CAC4AA8A', / encrypted content /
[
[
h'A10139D902', / protected header (repeated why?) /
h'A10139D902', / protected header /
{
-22222: h'04E8A00C...273E9D83',
4: h'746573742D6B65792D3432', / recipient kid /
Expand Down
49 changes: 49 additions & 0 deletions test/hpke/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@

import { AeadId, KdfId, KemId, CipherSuite, } from 'hpke-js'
import * as jose from 'jose'

export type Suite0 = `HPKE-Base-P256-SHA256-AES128GCM`
export const Suite0 = 'HPKE-Base-P256-SHA256-AES128GCM' as Suite0 // aka APPLE-HPKE-v1

export type PublicCoseKeyMap = Map<string | number, string | number | Buffer | ArrayBuffer>
export type SecretCoseKeyMap = Map<string | number, string | number | Buffer | ArrayBuffer>

export const encapsulated_key_header_label = -22222;
export const example_suite_label = -55555;

const suite0 = new CipherSuite({
kem: KemId.DhkemP256HkdfSha256,
kdf: KdfId.HkdfSha256,
aead: AeadId.Aes128Gcm,
})

export const coseSuites = {
[example_suite_label]: suite0,
} as Record<number, CipherSuite>



export const joseSuites = {
[Suite0]: suite0,
} as Record<string, CipherSuite>


export type Suite0CurveName = `P-256`

export type SuiteNames = Suite0
export type CurveNames = Suite0CurveName


export const algToCrv = {
[Suite0]: 'P-256',
} as Record<SuiteNames, CurveNames>


// https://datatracker.ietf.org/doc/html/draft-rha-jose-hpke-encrypt-01#section-4.1.1
// In both modes, the sender MUST specify the 'alg' parameter in the protected header to indicate the use of HPKE.

export const craftProtectedHeader = ({ alg, enc, kid }: { alg: Suite0, enc?: string, kid?: string }) => {
return jose.base64url.encode(JSON.stringify({
alg, enc, kid
}))
}
30 changes: 30 additions & 0 deletions test/hpke/cose/direct.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

import generate from '../jose/generate'
import direct from './direct'
import * as coseKey from '../../../src/key'
import alternateDiagnostic from '../../../src/diagnostic'

import { Suite0 } from '../common'

import directExample from '../ecdh-direct-example.json'

it('sanity', async () => {
const k = await generate(Suite0)
const pt = 'hello world'
const m = new TextEncoder().encode(pt)
const k2 = {
cosePublicKey: coseKey.importJWK(k.publicKeyJwk),
cosePrivateKey: coseKey.importJWK(k.privateKeyJwk)
}
const c3 = await direct.encrypt(m, k2.cosePublicKey)
const c3Diagnostic = await alternateDiagnostic(c3)
console.log('/ COSE HPKE Direct /\n' + c3Diagnostic)
// https://github.com/cose-wg/Examples/blob/3221310e2cf50ad13213daa7ca278209a8bc85fd/ecdh-direct-examples/p256-hkdf-256-01.json
// Compare to direct mode ecdh
const ecdhDirect = await alternateDiagnostic(Buffer.from(directExample.output.cbor, 'hex'))
console.log('/ COSE ECDH Direct /\n' + ecdhDirect)
const d3 = await direct.decrypt(c3, k2.cosePrivateKey)
const rpt3 = new TextDecoder().decode(d3)
expect(rpt3).toBe(pt)

})
82 changes: 82 additions & 0 deletions test/hpke/cose/direct.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import crypto from 'crypto'
import * as cbor from 'cbor-web'

import * as coseKey from '../../../src/key'
// eslint-disable-next-line @typescript-eslint/no-var-requires

import { coseSuites, example_suite_label, encapsulated_key_header_label, PublicCoseKeyMap, SecretCoseKeyMap } from '../common'


const directMode = {
// todo: use jwks instead...
encrypt: async (plaintext: Uint8Array, recipientPublic: PublicCoseKeyMap) => {
const alg = recipientPublic.get(3) || example_suite_label
const kid = recipientPublic.get(2)
if (alg !== example_suite_label) {
throw new Error('Unsupported algorithm')
}
const publicKeyJwk = coseKey.exportJWK(recipientPublic);
const publicKey = await crypto.subtle.importKey(
'jwk',
publicKeyJwk,
{
name: 'ECDH',
namedCurve: 'P-256',
},
true,
[],
)
const sender = await coseSuites[alg].createSenderContext({
recipientPublicKey: publicKey,
})
const protectedHeaderMap = new Map();
protectedHeaderMap.set(1, alg) // alg : TBD / restrict alg by recipient key /
const encodedProtectedHeader = cbor.encode(protectedHeaderMap)
const unprotectedHeaderMap = new Map();
unprotectedHeaderMap.set(4, kid) // kid : ...
unprotectedHeaderMap.set(encapsulated_key_header_label, sender.enc) // https://datatracker.ietf.org/doc/html/draft-ietf-cose-hpke-07#section-3.1
const external_aad = Buffer.from(new Uint8Array())
const Enc_structure = ["Encrypt0", encodedProtectedHeader, external_aad]
const internal_aad = cbor.encode(Enc_structure)
const ciphertext = await sender.seal(plaintext, internal_aad)
return cbor.encode([
encodedProtectedHeader,
unprotectedHeaderMap,
ciphertext
])

// cbor.encodeAsync(new Tagged(Sign1Tag, coseSign1Structure), { canonical: true })

},
decrypt: async (coseEnc: ArrayBuffer, recipientPrivate: SecretCoseKeyMap) => {
const decoded = await cbor.decode(coseEnc)
const alg = recipientPrivate.get(3) || example_suite_label
if (alg !== example_suite_label) {
throw new Error('Unsupported algorithm')
}
const privateKeyJwk = coseKey.exportJWK(recipientPrivate) as any;
const privateKey = await crypto.subtle.importKey(
'jwk',
privateKeyJwk,
{
name: 'ECDH',
namedCurve: privateKeyJwk.crv,
},
true,
['deriveBits'],
)
const [encodedProtectedHeader, unprotectedHeaderMap, ciphertext] = decoded
const external_aad = Buffer.from(new Uint8Array())
const Enc_structure = ["Encrypt0", encodedProtectedHeader, external_aad]
const internal_aad = cbor.encode(Enc_structure)
const enc = unprotectedHeaderMap.get(encapsulated_key_header_label)
const recipient = await coseSuites[alg].createRecipientContext({
recipientKey: privateKey, // rkp (CryptoKeyPair) is also acceptable.
enc
})
const pt = await recipient.open(ciphertext, internal_aad)
return new Uint8Array(pt)
}
}

export default directMode
9 changes: 9 additions & 0 deletions test/hpke/cose/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import direct from './direct'
import wrap from './wrap'

const hpke = {
direct,
wrap
}
const api = { hpke }
export default api
19 changes: 19 additions & 0 deletions test/hpke/cose/wrap.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

import generate from '../jose/generate'
import wrap from './wrap'
import * as coseKey from '../../../src/key'
import { Suite0 } from '../common'

it('sanity', async () => {
const k = await generate(Suite0)
const pt = 'hello world'
const m = new TextEncoder().encode(pt)
const k2 = {
cosePublicKey: coseKey.importJWK(k.publicKeyJwk),
cosePrivateKey: coseKey.importJWK(k.privateKeyJwk)
}
const c4 = await wrap.encrypt(m, k2.cosePublicKey)
const d4 = await wrap.decrypt(c4, k2.cosePrivateKey)
const rpt4 = new TextDecoder().decode(d4)
expect(rpt4).toBe(pt)
})
Loading

0 comments on commit 329743e

Please sign in to comment.