Skip to content

Commit

Permalink
$mol_crypto_key - new async crypto api, more sync
Browse files Browse the repository at this point in the history
  • Loading branch information
jin committed Nov 19, 2023
1 parent daa39c1 commit af8de22
Show file tree
Hide file tree
Showing 2 changed files with 191 additions and 0 deletions.
127 changes: 127 additions & 0 deletions crypto/key/key.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
namespace $ {

const algorithm = {
name: 'ECDSA',
hash: 'SHA-256',
namedCurve: "P-256",
}

export class $mol_crypto_key extends $mol_buffer {

static from< This extends typeof $mol_crypto_key >( this: This, serial: string | Uint8Array ) {

if( typeof serial === 'string' ) {
serial = new Uint8Array([
... $mol_base64_decode_safe( serial.slice( 0, 43 ) ),
... $mol_base64_decode_safe( serial.slice( 43, 86 ) ),
... $mol_base64_decode_safe( serial.slice( 86, 129 ) ),
])
}

return new this( serial.buffer, serial.byteOffset, serial.byteLength ) as InstanceType< This >
}

asArray() {
return new Uint8Array( this.buffer, this.byteOffset, this.byteLength )
}

@ $mol_memo.method
toString() {
const arr = this.asArray()
return $mol_base64_encode_safe( arr.subarray( 0, 32 ) )
+ $mol_base64_encode_safe( arr.subarray( 32, 64 ) )
+ $mol_base64_encode_safe( arr.subarray( 64 ) )
}

}

export class $mol_crypto_key_public extends $mol_crypto_key {

static size_str = 86
static size_bin = 64

@ $mol_memo.method
async native() {
const str = this.toString()
return $mol_crypto_native.subtle.importKey(
'jwk',
{
crv: "P-256",
ext: true,
key_ops: [ 'verify' ],
kty: "EC",
x: str.slice( 0, 43 ),
y: str.slice( 43, 86 ),
},
algorithm,
true,
[ 'verify' ],
)
}

async verify( data: BufferSource, sign: BufferSource ) {
return await $mol_crypto_native.subtle.verify(
algorithm,
await this.native(),
sign,
data,
)
}

}

export class $mol_crypto_key_private extends $mol_crypto_key {

static size_str = 129
static size_bin = 96
static size_sign = 64

static async generate() {

const pair = await $mol_crypto_native.subtle.generateKey(
algorithm,
true,
[ 'sign', 'verify' ]
)

const { x, y, d } = await $mol_crypto_native.subtle.exportKey( 'jwk', pair.privateKey )
return $mol_crypto_key_private.from( x + y! + d! )

}

@ $mol_memo.method
async native() {
const str = this.toString()
return await $mol_crypto_native.subtle.importKey(
'jwk',
{
crv: "P-256",
ext: true,
key_ops: [ 'sign' ],
kty: "EC",
x: str.slice( 0, 43 ),
y: str.slice( 43, 86 ),
d: str.slice( 86, 129 ),
},
algorithm,
true,
[ 'sign' ],
)
}

@ $mol_memo.method
public() {
return new $mol_crypto_key_public( this.buffer, this.byteOffset, this.byteOffset + 64 )
}

async sign( data: BufferSource ) {
return await $mol_crypto_native.subtle.sign(
algorithm,
await this.native(),
data
)
}

}

}
64 changes: 64 additions & 0 deletions crypto/key/key.web.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
namespace $ {
$mol_test({

async 'str sizes'() {

const key_private = await $$.$mol_crypto_key_private.generate()
const key_public = key_private.public()

$mol_assert_equal( key_private.toString().length, $mol_crypto_key_private.size_str )
$mol_assert_equal( key_public.toString().length, $mol_crypto_key_public.size_str )

$mol_assert_equal( key_private.asArray().length, $mol_crypto_key_private.size_bin )
$mol_assert_equal( key_public.asArray().length, $mol_crypto_key_public.size_bin )

const data = new Uint8Array([ 1, 2, 3 ])
const sign = await key_private.sign( data )
$mol_assert_equal( sign.byteLength, $mol_crypto_key_private.size_sign )

},

async 'verify self signed with auto generated key'() {

const Alice = await $$.$mol_crypto_key_private.generate()
const data = new Uint8Array([ 1, 2, 3 ])
const sign = await Alice.sign( data )

$mol_assert_ok( await Alice.public().verify( data, sign ) )

},

async 'verify signed with str exported auto generated key'() {

const Alice = await $$.$mol_crypto_key_private.generate()
const data = new Uint8Array([ 1, 2, 3 ])

const Bella = $mol_crypto_key_private.from( Alice.toString() )
const sign = await Bella.sign( data )

const Catie = $mol_crypto_key_public.from( Alice.public().toString() )
$mol_assert_ok( await Catie.verify( data, sign ) )

const Diana = $mol_crypto_key_public.from( Alice.toString() )
$mol_assert_ok( await Diana.verify( data, sign ) )

},

async 'verify signed with bin exported auto generated key'() {

const Alice = await $$.$mol_crypto_key_private.generate()
const data = new Uint8Array([ 1, 2, 3 ])

const Bella = $mol_crypto_key_private.from( Alice.asArray() )
const sign = await Bella.sign( data )

const Catie = $mol_crypto_key_public.from( Alice.public().asArray() )
$mol_assert_ok( await Catie.verify( data, sign ) )

const Diana = $mol_crypto_key_public.from( Alice.asArray() )
$mol_assert_ok( await Diana.verify( data, sign ) )

},

})
}

0 comments on commit af8de22

Please sign in to comment.