From f100d7318f43ad56d452a74b88562fb65cc9984c Mon Sep 17 00:00:00 2001 From: Jack Works Date: Fri, 18 Mar 2022 15:31:46 +0800 Subject: [PATCH 1/5] feat: remove aes algr from payload --- docs/rfc/000-Payload-v37.md | 37 +------------------ .../encryption/src/encryption/Decryption.ts | 18 +++------ .../encryption/src/encryption/Encryption.ts | 8 ++-- .../encryption/src/encryption/v37-ecdh.ts | 3 +- .../encryption/src/encryption/v38-ecdh.ts | 3 +- packages/encryption/src/index.ts | 2 - packages/encryption/src/payload/types.ts | 22 +++++------ .../encryption/src/payload_internal/shared.ts | 2 +- .../payload_internal/version-37.encoder.ts | 2 +- .../src/payload_internal/version-37.parser.ts | 27 +++++--------- .../payload_internal/version-38.encoder.ts | 5 +-- .../src/payload_internal/version-38.parser.ts | 8 ++-- packages/encryption/src/utils/crypto.ts | 33 ++++++----------- .../tests/__snapshots__/encryption.ts.snap | 24 +++--------- .../__snapshots__/v37-encode-decode.ts.snap | 7 +--- .../__snapshots__/v38-encode-decode.ts.snap | 10 +---- packages/encryption/tests/encryption.ts | 2 +- .../encryption/tests/v37-encode-decode.ts | 7 +--- .../encryption/tests/v38-encode-decode.ts | 7 +--- 19 files changed, 69 insertions(+), 158 deletions(-) diff --git a/docs/rfc/000-Payload-v37.md b/docs/rfc/000-Payload-v37.md index 0dd058671011..2e07e7bd980c 100644 --- a/docs/rfc/000-Payload-v37.md +++ b/docs/rfc/000-Payload-v37.md @@ -155,7 +155,7 @@ type PublicEncrypted = [kind: EncryptionKind.Public, AES_KEY: AES_KEY, iv: Binar ###### `AES_KEY` -This field represents the AES key of this payload. +This field represents the AES key (JsonWebKey.k) of this payload. ###### `iv` field @@ -218,41 +218,6 @@ Here is an example of the `secp256k1` public key in Binary. ] ``` -### `AES_KEY` - -```typescript -type AES_KEY = [alg: String, k: String] -``` - -This type is used in this specification to represent section 6.4 of a [JsonWebKey][rfc7518] of [AES family key][rfc7518-aes-family-key]. - -[rfc7518]: https://datatracker.ietf.org/doc/html/rfc7518 -[rfc7518-aes-family-key]: https://datatracker.ietf.org/doc/html/rfc7518#section-6.4 - -The implementation MUST fail when the `alg` is not recognized as a known algorithm. -The implementation MUST fail when the `k` is not valid for the given `alg`. - -When encrypting with AES key, the implementation MUST NOT use `additionalData`, the `tagLength` MUST be 128. - -#### Encoding from JsonWebKey `jwk` - -```js -function fromJsonWebKey(jwk) { - return [jwk.alg, jwk.k] -} -``` - -#### Decoding from `key` - -```js -function toJsonWebKey(key) { - const k = { ext: true, key_ops: ['encrypt', 'decrypt'], kty: 'oct' } - k.alg = key[0] - k.k = key[1] - return k -} -``` - ## FAQ ### Why the version number is negative? diff --git a/packages/encryption/src/encryption/Decryption.ts b/packages/encryption/src/encryption/Decryption.ts index e4141bb8462f..8d4d346527a1 100644 --- a/packages/encryption/src/encryption/Decryption.ts +++ b/packages/encryption/src/encryption/Decryption.ts @@ -2,7 +2,7 @@ import { unreachable } from '@dimensiondev/kit' import { decodeTypedMessageFromDocument, decodeTypedMessageV38ToV40Format, TypedMessage } from '@masknet/typed-message' import { AESCryptoKey, EC_Public_CryptoKey, andThenAsync } from '@masknet/shared-base' import { None, Result } from 'ts-results' -import { AESAlgorithmEnum, PayloadParseResult } from '../payload' +import type { PayloadParseResult } from '../payload' import { decryptWithAES, importAESFromJWK } from '../utils' import { DecryptOptions, @@ -40,13 +40,7 @@ export async function* decrypt(options: DecryptOptions, io: DecryptIO): AsyncIte if (AESKey.err) return yield new DecryptError(ErrorReasons.PayloadBroken, AESKey.val) if (iv.err) return yield new DecryptError(ErrorReasons.PayloadBroken, iv.val) // Not calling setPostCache here. It's public post and saving key is wasting storage space. - return yield* decryptWithPostAESKey( - version, - AESKey.val.key as AESCryptoKey, - iv.val, - encrypted, - options.onDecrypted, - ) + return yield* decryptWithPostAESKey(version, AESKey.val, iv.val, encrypted, options.onDecrypted) } else if (encryption.type === 'E2E') { const { iv: _iv, ownersAESKeyEncrypted } = encryption if (_iv.err) return yield new DecryptError(ErrorReasons.PayloadBroken, _iv.val) @@ -202,11 +196,11 @@ async function* decryptByECDH( : await derive(ephemeralPublicKey).then((aesArr) => aesArr.map((aes) => [aes, iv] as const)) for (const [derivedKey, derivedKeyNewIV] of derivedKeys) { const possiblePostKey = await andThenAsync( - decryptWithAES(AESAlgorithmEnum.A256GCM, derivedKey, derivedKeyNewIV, encryptedPostKey), + decryptWithAES(derivedKey, derivedKeyNewIV, encryptedPostKey), postKeyDecoder, ) if (possiblePostKey.err) continue - const decrypted = await decryptWithAES(AESAlgorithmEnum.A256GCM, possiblePostKey.val, iv, encrypted) + const decrypted = await decryptWithAES(possiblePostKey.val, iv, encrypted) if (decrypted.err) continue io.setPostKeyCache(possiblePostKey.val).catch(() => {}) @@ -225,7 +219,7 @@ async function* decryptWithPostAESKey( encrypted: Uint8Array, report: ((message: TypedMessage) => void) | undefined, ): AsyncIterableIterator { - const { err, val } = await decryptWithAES(AESAlgorithmEnum.A256GCM, postAESKey, iv, encrypted) + const { err, val } = await decryptWithAES(postAESKey, iv, encrypted) if (err) return yield new DecryptError(ErrorReasons.DecryptFailed, val) return yield* parseTypedMessage(version, val, report) } @@ -250,7 +244,7 @@ function importAESKeyFromJWKFromTextEncoder(aes_raw: Uint8Array) { const aes_text = new TextDecoder().decode(aes_raw) const aes_jwk = JSON.parse(aes_text) as JsonWebKey if (!aes_jwk.key_ops!.includes('decrypt')) aes_jwk.key_ops!.push('decrypt') - return (await importAESFromJWK.AES_GCM_256(aes_jwk)).unwrap() + return (await importAESFromJWK(aes_jwk)).unwrap() }) } diff --git a/packages/encryption/src/encryption/Encryption.ts b/packages/encryption/src/encryption/Encryption.ts index 6f929aabdbd6..7f42cec8ce56 100644 --- a/packages/encryption/src/encryption/Encryption.ts +++ b/packages/encryption/src/encryption/Encryption.ts @@ -7,7 +7,7 @@ import { SerializableTypedMessages, } from '@masknet/typed-message' import { None, Option, Some } from 'ts-results' -import { AESAlgorithmEnum, EC_Key, encodePayload, PayloadWellFormed } from '../payload' +import { EC_Key, encodePayload, PayloadWellFormed } from '../payload' import { encryptWithAES } from '../utils' import { @@ -33,7 +33,7 @@ export async function encrypt(options: EncryptOptions, io: EncryptIO): Promise encryptWithAES(AESAlgorithmEnum.A256GCM, postKey, postIV, message)) + .then((message) => encryptWithAES(postKey, postIV, message)) .then((x) => x.unwrap()) let encryption: PayloadWellFormed.PublicEncryption | PayloadWellFormed.EndToEndEncryption @@ -43,7 +43,7 @@ export async function encrypt(options: EncryptOptions, io: EncryptIO): Promise + readonly AESKey: RequiredField readonly iv: RequiredField } /** @@ -71,8 +78,8 @@ export declare namespace PayloadWellFormed { */ export interface PublicEncryption { readonly type: 'public' - /** The key used to encrypt the payload. */ - readonly AESKey: AESKey + /** The key used to encrypt the payload. It should be AES-256-GCM */ + readonly AESKey: AESCryptoKey readonly iv: Uint8Array } /** @@ -93,18 +100,11 @@ export interface EC_Key { readonly algr: EC_KeyCurveEnum readonly key: K } -export interface AESKey { - readonly algr: AESAlgorithmEnum - readonly key: CryptoKey -} export enum EC_KeyCurveEnum { ed25519 = 0, secp256p1 = 1, // P-256 secp256k1 = 2, // K-256 } -export enum AESAlgorithmEnum { - A256GCM = 'A256GCM', -} export enum SocialNetworkEnum { Unknown = -1, Facebook = 0, diff --git a/packages/encryption/src/payload_internal/shared.ts b/packages/encryption/src/payload_internal/shared.ts index 3b5b6b772fe7..a768912dc048 100644 --- a/packages/encryption/src/payload_internal/shared.ts +++ b/packages/encryption/src/payload_internal/shared.ts @@ -4,7 +4,7 @@ import { PayloadParseResult, SocialNetworkEnum } from '../payload' import { CryptoException, PayloadException } from '../types' import { importAESFromJWK } from '../utils' -const import_AES_GCM_256 = CheckedError.withErr(importAESFromJWK.AES_GCM_256, CryptoException.InvalidCryptoKey) +const import_AES_GCM_256 = CheckedError.withErr(importAESFromJWK, CryptoException.InvalidCryptoKey) /** * @internal diff --git a/packages/encryption/src/payload_internal/version-37.encoder.ts b/packages/encryption/src/payload_internal/version-37.encoder.ts index 720dca2c4693..89d3d3f2bf27 100644 --- a/packages/encryption/src/payload_internal/version-37.encoder.ts +++ b/packages/encryption/src/payload_internal/version-37.encoder.ts @@ -42,7 +42,7 @@ export async function encode37(payload: PayloadWellFormed.Payload) { payload_arr[Index.encryption] = subArr } else { const { AESKey, iv } = payload.encryption - const subArr = [0, [AESKey.algr, (await crypto.subtle.exportKey('jwk', AESKey.key)).k], iv] + const subArr = [0, (await crypto.subtle.exportKey('jwk', AESKey)).k, iv] payload_arr[Index.encryption] = subArr } payload_arr[Index.data] = payload.encrypted diff --git a/packages/encryption/src/payload_internal/version-37.parser.ts b/packages/encryption/src/payload_internal/version-37.parser.ts index 22fc4327924b..ba6e5c5942de 100644 --- a/packages/encryption/src/payload_internal/version-37.parser.ts +++ b/packages/encryption/src/payload_internal/version-37.parser.ts @@ -1,9 +1,9 @@ import type { PayloadParserResult } from '.' import type { PayloadParseResult } from '../payload' import { CryptoException, PayloadException, assertArray, assertUint8Array } from '../types' -import { andThenAsync, CheckedError, OptionalResult } from '@masknet/shared-base' +import { AESCryptoKey, andThenAsync, CheckedError, OptionalResult } from '@masknet/shared-base' import { Ok, Result } from 'ts-results' -import { AESKey, AESAlgorithmEnum, EC_Key, EC_KeyCurveEnum } from '../payload/types' +import { EC_Key, EC_KeyCurveEnum } from '../payload/types' import { decodeMessagePackF, assertIVLengthEq16, importAESFromJWK, importEC_Key } from '../utils' import { safeUnreachable } from '@dimensiondev/kit' import { parseSignatureContainer } from './SignatureContainer' @@ -86,21 +86,14 @@ async function parseEncryption(encryption: unknown): Promise - - return andThenAsync(assertArray('aes', CryptoException.InvalidCryptoKey)(aes), async (aes): T => { - const [algr, k] = aes - if (typeof k === 'string') { - if (algr === AESAlgorithmEnum.A256GCM) { - const jwk: JsonWebKey = { ext: true, key_ops: ['encrypt', 'decrypt'], kty: 'oct', alg: algr, k } - const key = await importAES256(jwk, algr) - if (key.err) return key - return Ok({ algr, key: key.val }) - } - } - return new CheckedError(CryptoException.UnsupportedAlgorithm, null).toErr() - }) +async function parseAES(aes: unknown) { + if (typeof aes === 'string') { + const jwk: JsonWebKey = { ext: true, key_ops: ['encrypt', 'decrypt'], kty: 'oct', alg: 'A256GCM', k: aes } + const key = await importAES256(jwk) + if (key.err) return key + return Ok(key.val) + } + return new CheckedError(CryptoException.UnsupportedAlgorithm, null).toErr() } function importAsymmetryKey(algr: unknown, key: unknown, name: string) { type T = Promise>> diff --git a/packages/encryption/src/payload_internal/version-38.encoder.ts b/packages/encryption/src/payload_internal/version-38.encoder.ts index 7e8eed3d2230..8b25e1e8ddc8 100644 --- a/packages/encryption/src/payload_internal/version-38.encoder.ts +++ b/packages/encryption/src/payload_internal/version-38.encoder.ts @@ -2,7 +2,6 @@ import { encodeText, encodeArrayBuffer } from '@dimensiondev/kit' import { Ok, Option, Result } from 'ts-results' import type { PayloadWellFormed, Signature } from '..' -import { AESAlgorithmEnum } from '../payload' import { CryptoException, PayloadException } from '../types' import { encryptWithAES, exportCryptoKeyToJWK } from '../utils' import { get_v38PublicSharedCryptoKey } from './shared' @@ -52,7 +51,7 @@ async function encodeAESKeyEncrypted( const publicSharedKey = await get_v38PublicSharedCryptoKey() if (publicSharedKey.err) return publicSharedKey - const jwk = await exportCryptoKeyToJWK(AESKey.key) + const jwk = await exportCryptoKeyToJWK(AESKey) if (jwk.err) return jwk.mapErr((e) => new CheckedError(CryptoException.InvalidCryptoKey, e)) // There is no reason that these two steps will fail. @@ -63,7 +62,7 @@ async function encodeAESKeyEncrypted( const text = `{"alg":"A256GCM","ext":true,"k":"${jwk.val.k}","key_ops":["decrypt","encrypt"],"kty":"oct"}` const ab = encodeText(text) - const encryptedKey = await encryptWithAES(AESAlgorithmEnum.A256GCM, publicSharedKey.val, iv, ab) + const encryptedKey = await encryptWithAES(publicSharedKey.val, iv, ab) if (encryptedKey.err) return encryptedKey.mapErr((e) => new CheckedError(CryptoException.EncryptFailed, e)) return Ok(encodeArrayBuffer(encryptedKey.val.slice())) } diff --git a/packages/encryption/src/payload_internal/version-38.parser.ts b/packages/encryption/src/payload_internal/version-38.parser.ts index b82f3c60b67a..072b4aefad6f 100644 --- a/packages/encryption/src/payload_internal/version-38.parser.ts +++ b/packages/encryption/src/payload_internal/version-38.parser.ts @@ -1,5 +1,5 @@ /* eslint @dimensiondev/unicode-specific-set: ["error", { "only": "code" }] */ -import { AESKey, AESAlgorithmEnum, EC_Key, PayloadParseResult, EC_KeyCurveEnum, Signature } from '../payload' +import { EC_Key, PayloadParseResult, EC_KeyCurveEnum, Signature } from '../payload' import { CryptoException, PayloadException } from '../types' import { Result, Ok, Some } from 'ts-results' import { @@ -114,15 +114,15 @@ async function decodePublicSharedAESKey( const publicSharedKey = await get_v38PublicSharedCryptoKey() if (publicSharedKey.err) return publicSharedKey - const import_AES_GCM_256 = CheckedError.withErr(importAESFromJWK.AES_GCM_256, CryptoException.InvalidCryptoKey) + const import_AES_GCM_256 = CheckedError.withErr(importAESFromJWK, CryptoException.InvalidCryptoKey) const decrypt = CheckedError.withErr(decryptWithAES, CryptoException.InvalidCryptoKey) - const jwk_in_u8arr = await decrypt(AESAlgorithmEnum.A256GCM, publicSharedKey.val, iv.val, encryptedKey.val) + const jwk_in_u8arr = await decrypt(publicSharedKey.val, iv.val, encryptedKey.val) const jwk_in_text = await andThenAsync(jwk_in_u8arr, decodeTextCrypto) const jwk = await andThenAsync(jwk_in_text, JSONParse) const aes = await andThenAsync(jwk, import_AES_GCM_256) - return aes.map((key) => ({ algr: AESAlgorithmEnum.A256GCM, key })) + return aes } async function decodeECDHPublicKey(compressedPublic: string): Promise> { diff --git a/packages/encryption/src/utils/crypto.ts b/packages/encryption/src/utils/crypto.ts index 0d24c95da155..c4b07aa512a2 100644 --- a/packages/encryption/src/utils/crypto.ts +++ b/packages/encryption/src/utils/crypto.ts @@ -1,19 +1,15 @@ import { AESCryptoKey, CheckedError, EC_CryptoKey } from '@masknet/shared-base' import { Result, Ok } from 'ts-results' -import { AESAlgorithmEnum, EC_KeyCurveEnum } from '../payload' +import { EC_KeyCurveEnum } from '../payload' import { CryptoException } from '../types' -export function importAESFromJWK(key: JsonWebKey, kind: AESAlgorithmEnum): Promise> { +export function importAESFromJWK(key: JsonWebKey): Promise> { return Result.wrapAsync(() => { - const param: Record = { - [AESAlgorithmEnum.A256GCM]: { - name: 'AES-GCM', - length: 256, - }, - } - return crypto.subtle.importKey('jwk', key, param[kind], true, ['encrypt', 'decrypt']) as any + return crypto.subtle.importKey('jwk', key, { name: 'AES-GCM', length: 256 }, true, [ + 'encrypt', + 'decrypt', + ]) as any }) } -importAESFromJWK.AES_GCM_256 = (key: JsonWebKey) => importAESFromJWK(key, AESAlgorithmEnum.A256GCM) export function exportCryptoKeyToJWK(key: CryptoKey) { return Result.wrapAsync(() => crypto.subtle.exportKey('jwk', key)) @@ -44,20 +40,15 @@ export function importEC_Key(key: JsonWebKey | Uint8Array, kind: EC_KeyCurveEnum }) } -export function encryptWithAES(kind: AESAlgorithmEnum, key: CryptoKey, iv: Uint8Array, message: Uint8Array) { - const param = { - [AESAlgorithmEnum.A256GCM]: { name: 'AES-GCM', iv } as AesGcmParams, - } as const - return Result.wrapAsync(() => { - return crypto.subtle.encrypt(param[kind], key, message).then((x) => new Uint8Array(x)) +export function encryptWithAES(key: CryptoKey, iv: Uint8Array, message: Uint8Array) { + return Result.wrapAsync(async () => { + const x = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, message) + return new Uint8Array(x) }) } -export function decryptWithAES(kind: AESAlgorithmEnum, key: CryptoKey, iv: Uint8Array, message: Uint8Array) { - const param = { - [AESAlgorithmEnum.A256GCM]: { name: 'AES-GCM', iv } as AesGcmParams, - } as const +export function decryptWithAES(key: CryptoKey, iv: Uint8Array, message: Uint8Array) { return Result.wrapAsync(async () => { - return new Uint8Array(await crypto.subtle.decrypt(param[kind], key, message)) + return new Uint8Array(await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, message)) }) } export function assertIVLengthEq16(arrayBuffer: Uint8Array) { diff --git a/packages/encryption/tests/__snapshots__/encryption.ts.snap b/packages/encryption/tests/__snapshots__/encryption.ts.snap index 725558b0f0e6..00b816036c1a 100644 --- a/packages/encryption/tests/__snapshots__/encryption.ts.snap +++ b/packages/encryption/tests/__snapshots__/encryption.ts.snap @@ -152,7 +152,7 @@ Object { "network": "localhost", "postIV": "AAECAwQFBgcICQoLDA0ODw==", }, - "output": Uint8Array [ 9200c5011c9700a96c6f63616c686f7374a5616c69636502c4583056301006072a8648ce3d020106052b8104000a03420004afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58c931d5975900006531c46a73f84b33a03755dfbe567ec504c470dd244440dd63e930092a74132353647434dd92b4a526872524b796b6d6e6d335362754e77364f6358465f6a69773067496c57335169574e5630316a656145c410000102030405060708090a0b0c0d0e0fc463422847d65139731573ca340118fa81883ae4cffa41cb7c91d378dd43c72ebad227c7af84e61f19fd4820fca920472d68a1076ccbe42f620eb73036bc7e13eb330d6f065c1e6ea02cb219d3e8a06a31a58d3d0b52bf8a8d03a0d001119d1b93f377ceab ], + "output": Uint8Array [ 9200c501139700a96c6f63616c686f7374a5616c69636502c4583056301006072a8648ce3d020106052b8104000a03420004afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58c931d5975900006531c46a73f84b33a03755dfbe567ec504c470dd244440dd63e9300d92b4a526872524b796b6d6e6d335362754e77364f6358465f6a69773067496c57335169574e5630316a656145c410000102030405060708090a0b0c0d0e0fc463422847d65139731573ca340118fa81883ae4cffa41cb7c91d378dd43c72ebad227c7af84e61f19fd4820fca920472d68a1076ccbe42f620eb73036bc7e13eb330d6f065c1e6ea02cb219d3e8a06a31a58d3d0b52bf8a8d03a0d001119d1b93f377ceab ], "postKey": CryptoKey { [opaque crypto key material] }, } `; @@ -211,10 +211,7 @@ Object { })), "encrypted": Ok(Uint8Array [ 422847d65139731573ca340118fa81883ae4cffa41cb7c91d378dd43c72ebad227c7af84e61f19fd4820fca920472d68a1076ccbe42f620eb73036bc7e13eb330d6f065c1e6ea02cb219d3e8a06a31a58d3d0b52bf8a8d03a0d001119d1b93f377ceab ]), "encryption": Ok(Object { - "AESKey": Ok(Object { - "algr": "A256GCM", - "key": CryptoKey { [opaque crypto key material] }, - }), + "AESKey": Ok(CryptoKey { [opaque crypto key material] }), "iv": Ok(Uint8Array [ 000102030405060708090a0b0c0d0e0f ]), "type": "public", }), @@ -234,7 +231,7 @@ Object { "network": "localhost", "postIV": "AAECAwQFBgcICQoLDA0ODw==", }, - "output": Uint8Array [ 9200c4829700a96c6f63616c686f7374a5616c696365c0c0930092a74132353647434dd92b4a526872524b796b6d6e6d335362754e77364f6358465f6a69773067496c57335169574e5630316a656145c410000102030405060708090a0b0c0d0e0fc422422847d751786b14798828024dea879478f32c9aed87c5f427ae352faa7b50a13721 ], + "output": Uint8Array [ 9200c4799700a96c6f63616c686f7374a5616c696365c0c09300d92b4a526872524b796b6d6e6d335362754e77364f6358465f6a69773067496c57335169574e5630316a656145c410000102030405060708090a0b0c0d0e0fc422422847d751786b14798828024dea879478f32c9aed87c5f427ae352faa7b50a13721 ], "postKey": CryptoKey { [opaque crypto key material] }, } `; @@ -263,10 +260,7 @@ Object { "authorPublicKey": Ok(None), "encrypted": Ok(Uint8Array [ 422847d751786b14798828024dea879478f32c9aed87c5f427ae352faa7b50a13721 ]), "encryption": Ok(Object { - "AESKey": Ok(Object { - "algr": "A256GCM", - "key": CryptoKey { [opaque crypto key material] }, - }), + "AESKey": Ok(CryptoKey { [opaque crypto key material] }), "iv": Ok(Uint8Array [ 000102030405060708090a0b0c0d0e0f ]), "type": "public", }), @@ -451,10 +445,7 @@ Object { })), "encrypted": Ok(Uint8Array [ b84dbfba3f98b7136e8820505beab78cb64a1d7440403c589a989a ]), "encryption": Ok(Object { - "AESKey": Ok(Object { - "algr": "A256GCM", - "key": CryptoKey { [opaque crypto key material] }, - }), + "AESKey": Ok(CryptoKey { [opaque crypto key material] }), "iv": Ok(Uint8Array [ 000102030405060708090a0b0c0d0e0f ]), "type": "public", }), @@ -503,10 +494,7 @@ Object { "authorPublicKey": Ok(None), "encrypted": Ok(Uint8Array [ b84dbfba3f98b7136e8820505beab78cb64a1d7440403c589a989a ]), "encryption": Ok(Object { - "AESKey": Ok(Object { - "algr": "A256GCM", - "key": CryptoKey { [opaque crypto key material] }, - }), + "AESKey": Ok(CryptoKey { [opaque crypto key material] }), "iv": Ok(Uint8Array [ 000102030405060708090a0b0c0d0e0f ]), "type": "public", }), diff --git a/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap b/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap index 26cf9f425cc7..043a531c5861 100644 --- a/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap +++ b/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Encode v37 payload: Empty payload 1`] = `Uint8Array [ 9200c4579700c0c0c0c0930092a74132353647434dd92b4a526872524b796b6d6e6d335362754e77364f6358465f6a69773067496c57335169574e5630316a656145c410000102030405060708090a0b0c0d0e0fc4050001020304 ]`; +exports[`Encode v37 payload: Empty payload 1`] = `Uint8Array [ 9200c44e9700c0c0c0c09300d92b4a526872524b796b6d6e6d335362754e77364f6358465f6a69773067496c57335169574e5630316a656145c410000102030405060708090a0b0c0d0e0fc4050001020304 ]`; exports[`Encode v37 payload: Empty payload parsed 1`] = ` Object { @@ -8,10 +8,7 @@ Object { "authorPublicKey": Ok(None), "encrypted": Ok(Uint8Array [ 0001020304 ]), "encryption": Ok(Object { - "AESKey": Ok(Object { - "algr": "A256GCM", - "key": CryptoKey { [opaque crypto key material] }, - }), + "AESKey": Ok(CryptoKey { [opaque crypto key material] }), "iv": Ok(Uint8Array [ 000102030405060708090a0b0c0d0e0f ]), "type": "public", }), diff --git a/packages/encryption/tests/__snapshots__/v38-encode-decode.ts.snap b/packages/encryption/tests/__snapshots__/v38-encode-decode.ts.snap index df67c5c94d82..adbe3f504857 100644 --- a/packages/encryption/tests/__snapshots__/v38-encode-decode.ts.snap +++ b/packages/encryption/tests/__snapshots__/v38-encode-decode.ts.snap @@ -14,10 +14,7 @@ Ok(Object { })), "encrypted": Ok(Uint8Array [ 3a0d6ee692c6f46896b196f14301c01ad2fa26aa ]), "encryption": Ok(Object { - "AESKey": Ok(Object { - "algr": "A256GCM", - "key": CryptoKey { [opaque crypto key material] }, - }), + "AESKey": Ok(CryptoKey { [opaque crypto key material] }), "iv": Ok(Uint8Array [ 0633db7e24805c2bdcff69ea2afda7cd ]), "type": "public", }), @@ -54,10 +51,7 @@ Object { })), "encrypted": Ok(Uint8Array [ 3a0d6ee692c6f46896b196f14301c01ad2fa26aa ]), "encryption": Ok(Object { - "AESKey": Ok(Object { - "algr": "A256GCM", - "key": CryptoKey { [opaque crypto key material] }, - }), + "AESKey": Ok(CryptoKey { [opaque crypto key material] }), "iv": Ok(Uint8Array [ 0633db7e24805c2bdcff69ea2afda7cd ]), "type": "public", }), diff --git a/packages/encryption/tests/encryption.ts b/packages/encryption/tests/encryption.ts index e9204435fe6c..1a620ee6fb93 100644 --- a/packages/encryption/tests/encryption.ts +++ b/packages/encryption/tests/encryption.ts @@ -334,7 +334,7 @@ async function returnFalse(): Promise { return false } async function returnTestKey() { - return (await importAESFromJWK.AES_GCM_256(testKey)).unwrap() + return (await importAESFromJWK(testKey)).unwrap() } function complexMessage() { diff --git a/packages/encryption/tests/v37-encode-decode.ts b/packages/encryption/tests/v37-encode-decode.ts index 58f85f2a6460..d086b2289ca6 100644 --- a/packages/encryption/tests/v37-encode-decode.ts +++ b/packages/encryption/tests/v37-encode-decode.ts @@ -1,6 +1,6 @@ import { test, expect } from '@jest/globals' import { None, Some } from 'ts-results' -import { encodePayload, AESAlgorithmEnum, parsePayload, PayloadWellFormed } from '../src' +import { encodePayload, parsePayload, PayloadWellFormed } from '../src' import { importAESFromJWK } from '../src/utils' import { ProfileIdentifier } from '@masknet/shared-base' import { queryTestPublicKey } from './keys' @@ -55,10 +55,7 @@ test('Encode v37 payload', async () => { }) async function getAESKey(): Promise { - return { - algr: AESAlgorithmEnum.A256GCM, - key: (await importAESFromJWK.AES_GCM_256(testKey)).unwrap(), - } + return (await importAESFromJWK(testKey)).unwrap() } const testKey = { alg: 'A256GCM', diff --git a/packages/encryption/tests/v38-encode-decode.ts b/packages/encryption/tests/v38-encode-decode.ts index f08e35f39b53..ce92f2cfc7da 100644 --- a/packages/encryption/tests/v38-encode-decode.ts +++ b/packages/encryption/tests/v38-encode-decode.ts @@ -1,5 +1,5 @@ import { expect, test } from '@jest/globals' -import { AESAlgorithmEnum, encodePayload, parsePayload, PayloadWellFormed } from '../src' +import { encodePayload, parsePayload, PayloadWellFormed } from '../src' import { None, Some } from 'ts-results' import { ProfileIdentifier } from '@masknet/shared-base' import { importAESFromJWK } from '../src/utils' @@ -23,10 +23,7 @@ test('Encode v38 payload', async () => { encryption: { type: 'public', iv: new Uint8Array(Buffer.from('0633db7e24805c2bdcff69ea2afda7cd', 'hex')), - AESKey: { - algr: AESAlgorithmEnum.A256GCM, - key: await importAESFromJWK(AESKey, AESAlgorithmEnum.A256GCM).then((x) => x.unwrap() as any), - }, + AESKey: await importAESFromJWK(AESKey).then((x) => x.unwrap()), }, signature: None, version: -38, From ba2a6bf276a80bf2e3ed30a1289dbc51c6a7866b Mon Sep 17 00:00:00 2001 From: Jack Works Date: Fri, 18 Mar 2022 15:36:36 +0800 Subject: [PATCH 2/5] feat: switch from jwk to raw --- docs/rfc/000-Payload-v37.md | 2 +- packages/encryption/src/encryption/Decryption.ts | 4 ++-- packages/encryption/src/index.ts | 2 +- packages/encryption/src/payload_internal/shared.ts | 4 ++-- .../src/payload_internal/version-37.encoder.ts | 2 +- .../src/payload_internal/version-37.parser.ts | 14 ++++---------- .../src/payload_internal/version-38.parser.ts | 4 ++-- packages/encryption/src/utils/crypto.ts | 8 +++++++- .../tests/__snapshots__/encryption.ts.snap | 4 ++-- .../tests/__snapshots__/v37-encode-decode.ts.snap | 2 +- packages/encryption/tests/encryption.ts | 4 ++-- packages/encryption/tests/v37-encode-decode.ts | 4 ++-- packages/encryption/tests/v38-encode-decode.ts | 4 ++-- 13 files changed, 29 insertions(+), 29 deletions(-) diff --git a/docs/rfc/000-Payload-v37.md b/docs/rfc/000-Payload-v37.md index 2e07e7bd980c..ce297cb1ff91 100644 --- a/docs/rfc/000-Payload-v37.md +++ b/docs/rfc/000-Payload-v37.md @@ -155,7 +155,7 @@ type PublicEncrypted = [kind: EncryptionKind.Public, AES_KEY: AES_KEY, iv: Binar ###### `AES_KEY` -This field represents the AES key (JsonWebKey.k) of this payload. +This field represents the raw AES-256-GCM key (binary) of this payload. ###### `iv` field diff --git a/packages/encryption/src/encryption/Decryption.ts b/packages/encryption/src/encryption/Decryption.ts index 8d4d346527a1..c67808eb761f 100644 --- a/packages/encryption/src/encryption/Decryption.ts +++ b/packages/encryption/src/encryption/Decryption.ts @@ -3,7 +3,7 @@ import { decodeTypedMessageFromDocument, decodeTypedMessageV38ToV40Format, Typed import { AESCryptoKey, EC_Public_CryptoKey, andThenAsync } from '@masknet/shared-base' import { None, Result } from 'ts-results' import type { PayloadParseResult } from '../payload' -import { decryptWithAES, importAESFromJWK } from '../utils' +import { decryptWithAES, importAES } from '../utils' import { DecryptOptions, DecryptIO, @@ -244,7 +244,7 @@ function importAESKeyFromJWKFromTextEncoder(aes_raw: Uint8Array) { const aes_text = new TextDecoder().decode(aes_raw) const aes_jwk = JSON.parse(aes_text) as JsonWebKey if (!aes_jwk.key_ops!.includes('decrypt')) aes_jwk.key_ops!.push('decrypt') - return (await importAESFromJWK(aes_jwk)).unwrap() + return (await importAES(aes_jwk)).unwrap() }) } diff --git a/packages/encryption/src/index.ts b/packages/encryption/src/index.ts index dbece403981f..b0a5894030f7 100644 --- a/packages/encryption/src/index.ts +++ b/packages/encryption/src/index.ts @@ -65,4 +65,4 @@ export { } from './image-steganography' // TODO: remove them in the future -export { importEC_Key, importAESFromJWK } from './utils' +export { importEC_Key, importAES as importAESFromJWK } from './utils' diff --git a/packages/encryption/src/payload_internal/shared.ts b/packages/encryption/src/payload_internal/shared.ts index a768912dc048..e49e6a1be2c9 100644 --- a/packages/encryption/src/payload_internal/shared.ts +++ b/packages/encryption/src/payload_internal/shared.ts @@ -2,9 +2,9 @@ import { ProfileIdentifier, CheckedError, OptionalResult, EnhanceableSite } from import { Ok } from 'ts-results' import { PayloadParseResult, SocialNetworkEnum } from '../payload' import { CryptoException, PayloadException } from '../types' -import { importAESFromJWK } from '../utils' +import { importAES } from '../utils' -const import_AES_GCM_256 = CheckedError.withErr(importAESFromJWK, CryptoException.InvalidCryptoKey) +const import_AES_GCM_256 = CheckedError.withErr(importAES, CryptoException.InvalidCryptoKey) /** * @internal diff --git a/packages/encryption/src/payload_internal/version-37.encoder.ts b/packages/encryption/src/payload_internal/version-37.encoder.ts index 89d3d3f2bf27..14bc496149c3 100644 --- a/packages/encryption/src/payload_internal/version-37.encoder.ts +++ b/packages/encryption/src/payload_internal/version-37.encoder.ts @@ -42,7 +42,7 @@ export async function encode37(payload: PayloadWellFormed.Payload) { payload_arr[Index.encryption] = subArr } else { const { AESKey, iv } = payload.encryption - const subArr = [0, (await crypto.subtle.exportKey('jwk', AESKey)).k, iv] + const subArr = [0, new Uint8Array(await crypto.subtle.exportKey('raw', AESKey)), iv] payload_arr[Index.encryption] = subArr } payload_arr[Index.data] = payload.encrypted diff --git a/packages/encryption/src/payload_internal/version-37.parser.ts b/packages/encryption/src/payload_internal/version-37.parser.ts index ba6e5c5942de..c92aefa88a28 100644 --- a/packages/encryption/src/payload_internal/version-37.parser.ts +++ b/packages/encryption/src/payload_internal/version-37.parser.ts @@ -1,10 +1,10 @@ import type { PayloadParserResult } from '.' import type { PayloadParseResult } from '../payload' import { CryptoException, PayloadException, assertArray, assertUint8Array } from '../types' -import { AESCryptoKey, andThenAsync, CheckedError, OptionalResult } from '@masknet/shared-base' +import { andThenAsync, CheckedError, OptionalResult } from '@masknet/shared-base' import { Ok, Result } from 'ts-results' import { EC_Key, EC_KeyCurveEnum } from '../payload/types' -import { decodeMessagePackF, assertIVLengthEq16, importAESFromJWK, importEC_Key } from '../utils' +import { decodeMessagePackF, assertIVLengthEq16, importAES, importEC_Key } from '../utils' import { safeUnreachable } from '@dimensiondev/kit' import { parseSignatureContainer } from './SignatureContainer' import { parseAuthor } from './shared' @@ -14,7 +14,7 @@ import { parseAuthor } from './shared' const decode = decodeMessagePackF(PayloadException.InvalidPayload, PayloadException.DecodeFailed) const InvalidPayload = (msg?: string) => new CheckedError(PayloadException.InvalidPayload, msg).toErr() const importSpki = CheckedError.withErr(importEC_Key, CryptoException.InvalidCryptoKey) -const importAES256 = CheckedError.withErr(importAESFromJWK, CryptoException.InvalidCryptoKey) +const importAES256 = CheckedError.withErr(importAES, CryptoException.InvalidCryptoKey) export async function parse37(input: Uint8Array): PayloadParserResult { const signatureContainer = parseSignatureContainer(input) if (signatureContainer.err) return signatureContainer @@ -87,13 +87,7 @@ async function parseEncryption(encryption: unknown): Promise(key.val) - } - return new CheckedError(CryptoException.UnsupportedAlgorithm, null).toErr() + return andThenAsync(assertUint8Array(aes, 'aes', CryptoException.InvalidCryptoKey), importAES256) } function importAsymmetryKey(algr: unknown, key: unknown, name: string) { type T = Promise>> diff --git a/packages/encryption/src/payload_internal/version-38.parser.ts b/packages/encryption/src/payload_internal/version-38.parser.ts index 072b4aefad6f..fe06e2a7a306 100644 --- a/packages/encryption/src/payload_internal/version-38.parser.ts +++ b/packages/encryption/src/payload_internal/version-38.parser.ts @@ -7,7 +7,7 @@ import { decodeTextF, decryptWithAES, assertIVLengthEq16, - importAESFromJWK, + importAES, importEC_Key, JSONParseF, } from '../utils' @@ -114,7 +114,7 @@ async function decodePublicSharedAESKey( const publicSharedKey = await get_v38PublicSharedCryptoKey() if (publicSharedKey.err) return publicSharedKey - const import_AES_GCM_256 = CheckedError.withErr(importAESFromJWK, CryptoException.InvalidCryptoKey) + const import_AES_GCM_256 = CheckedError.withErr(importAES, CryptoException.InvalidCryptoKey) const decrypt = CheckedError.withErr(decryptWithAES, CryptoException.InvalidCryptoKey) const jwk_in_u8arr = await decrypt(publicSharedKey.val, iv.val, encryptedKey.val) diff --git a/packages/encryption/src/utils/crypto.ts b/packages/encryption/src/utils/crypto.ts index c4b07aa512a2..ba32d2ec5ecd 100644 --- a/packages/encryption/src/utils/crypto.ts +++ b/packages/encryption/src/utils/crypto.ts @@ -2,8 +2,14 @@ import { AESCryptoKey, CheckedError, EC_CryptoKey } from '@masknet/shared-base' import { Result, Ok } from 'ts-results' import { EC_KeyCurveEnum } from '../payload' import { CryptoException } from '../types' -export function importAESFromJWK(key: JsonWebKey): Promise> { +export function importAES(key: JsonWebKey | Uint8Array): Promise> { return Result.wrapAsync(() => { + if (key instanceof Uint8Array) { + return crypto.subtle.importKey('raw', key, { name: 'AES-GCM', length: 256 }, true, [ + 'encrypt', + 'decrypt', + ]) as any + } return crypto.subtle.importKey('jwk', key, { name: 'AES-GCM', length: 256 }, true, [ 'encrypt', 'decrypt', diff --git a/packages/encryption/tests/__snapshots__/encryption.ts.snap b/packages/encryption/tests/__snapshots__/encryption.ts.snap index 00b816036c1a..cf7c3aa316f3 100644 --- a/packages/encryption/tests/__snapshots__/encryption.ts.snap +++ b/packages/encryption/tests/__snapshots__/encryption.ts.snap @@ -152,7 +152,7 @@ Object { "network": "localhost", "postIV": "AAECAwQFBgcICQoLDA0ODw==", }, - "output": Uint8Array [ 9200c501139700a96c6f63616c686f7374a5616c69636502c4583056301006072a8648ce3d020106052b8104000a03420004afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58c931d5975900006531c46a73f84b33a03755dfbe567ec504c470dd244440dd63e9300d92b4a526872524b796b6d6e6d335362754e77364f6358465f6a69773067496c57335169574e5630316a656145c410000102030405060708090a0b0c0d0e0fc463422847d65139731573ca340118fa81883ae4cffa41cb7c91d378dd43c72ebad227c7af84e61f19fd4820fca920472d68a1076ccbe42f620eb73036bc7e13eb330d6f065c1e6ea02cb219d3e8a06a31a58d3d0b52bf8a8d03a0d001119d1b93f377ceab ], + "output": Uint8Array [ 9200c501089700a96c6f63616c686f7374a5616c69636502c4583056301006072a8648ce3d020106052b8104000a03420004afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58c931d5975900006531c46a73f84b33a03755dfbe567ec504c470dd244440dd63e9300c42025186b44aca49a79b749bb8dc3a39c5c5fe38b0d202255b742258d574d6379a1c410000102030405060708090a0b0c0d0e0fc463422847d65139731573ca340118fa81883ae4cffa41cb7c91d378dd43c72ebad227c7af84e61f19fd4820fca920472d68a1076ccbe42f620eb73036bc7e13eb330d6f065c1e6ea02cb219d3e8a06a31a58d3d0b52bf8a8d03a0d001119d1b93f377ceab ], "postKey": CryptoKey { [opaque crypto key material] }, } `; @@ -231,7 +231,7 @@ Object { "network": "localhost", "postIV": "AAECAwQFBgcICQoLDA0ODw==", }, - "output": Uint8Array [ 9200c4799700a96c6f63616c686f7374a5616c696365c0c09300d92b4a526872524b796b6d6e6d335362754e77364f6358465f6a69773067496c57335169574e5630316a656145c410000102030405060708090a0b0c0d0e0fc422422847d751786b14798828024dea879478f32c9aed87c5f427ae352faa7b50a13721 ], + "output": Uint8Array [ 9200c46e9700a96c6f63616c686f7374a5616c696365c0c09300c42025186b44aca49a79b749bb8dc3a39c5c5fe38b0d202255b742258d574d6379a1c410000102030405060708090a0b0c0d0e0fc422422847d751786b14798828024dea879478f32c9aed87c5f427ae352faa7b50a13721 ], "postKey": CryptoKey { [opaque crypto key material] }, } `; diff --git a/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap b/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap index 043a531c5861..bfeddd776b02 100644 --- a/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap +++ b/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Encode v37 payload: Empty payload 1`] = `Uint8Array [ 9200c44e9700c0c0c0c09300d92b4a526872524b796b6d6e6d335362754e77364f6358465f6a69773067496c57335169574e5630316a656145c410000102030405060708090a0b0c0d0e0fc4050001020304 ]`; +exports[`Encode v37 payload: Empty payload 1`] = `Uint8Array [ 9200c4439700c0c0c0c09300c42025186b44aca49a79b749bb8dc3a39c5c5fe38b0d202255b742258d574d6379a1c410000102030405060708090a0b0c0d0e0fc4050001020304 ]`; exports[`Encode v37 payload: Empty payload parsed 1`] = ` Object { diff --git a/packages/encryption/tests/encryption.ts b/packages/encryption/tests/encryption.ts index 1a620ee6fb93..f53ac71741cc 100644 --- a/packages/encryption/tests/encryption.ts +++ b/packages/encryption/tests/encryption.ts @@ -10,7 +10,7 @@ import { EncryptOptions, parsePayload, } from '../src' -import { importAESFromJWK } from '../src/utils' +import { importAES } from '../src/utils' import { ProfileIdentifier } from '@masknet/shared-base' import { makeTypedMessageText, makeTypedMessageTupleSerializable } from '@masknet/typed-message' import { @@ -334,7 +334,7 @@ async function returnFalse(): Promise { return false } async function returnTestKey() { - return (await importAESFromJWK(testKey)).unwrap() + return (await importAES(testKey)).unwrap() } function complexMessage() { diff --git a/packages/encryption/tests/v37-encode-decode.ts b/packages/encryption/tests/v37-encode-decode.ts index d086b2289ca6..660a0e4d0556 100644 --- a/packages/encryption/tests/v37-encode-decode.ts +++ b/packages/encryption/tests/v37-encode-decode.ts @@ -1,7 +1,7 @@ import { test, expect } from '@jest/globals' import { None, Some } from 'ts-results' import { encodePayload, parsePayload, PayloadWellFormed } from '../src' -import { importAESFromJWK } from '../src/utils' +import { importAES } from '../src/utils' import { ProfileIdentifier } from '@masknet/shared-base' import { queryTestPublicKey } from './keys' @@ -55,7 +55,7 @@ test('Encode v37 payload', async () => { }) async function getAESKey(): Promise { - return (await importAESFromJWK(testKey)).unwrap() + return (await importAES(testKey)).unwrap() } const testKey = { alg: 'A256GCM', diff --git a/packages/encryption/tests/v38-encode-decode.ts b/packages/encryption/tests/v38-encode-decode.ts index ce92f2cfc7da..489ceee6c246 100644 --- a/packages/encryption/tests/v38-encode-decode.ts +++ b/packages/encryption/tests/v38-encode-decode.ts @@ -2,7 +2,7 @@ import { expect, test } from '@jest/globals' import { encodePayload, parsePayload, PayloadWellFormed } from '../src' import { None, Some } from 'ts-results' import { ProfileIdentifier } from '@masknet/shared-base' -import { importAESFromJWK } from '../src/utils' +import { importAES } from '../src/utils' import { queryTestPublicKey } from './keys' test('Parse v38 encoded by old infra', async () => { @@ -23,7 +23,7 @@ test('Encode v38 payload', async () => { encryption: { type: 'public', iv: new Uint8Array(Buffer.from('0633db7e24805c2bdcff69ea2afda7cd', 'hex')), - AESKey: await importAESFromJWK(AESKey).then((x) => x.unwrap()), + AESKey: await importAES(AESKey).then((x) => x.unwrap()), }, signature: None, version: -38, From 4f6328eaae9857199b4ceb36b41c2ef4256cb3e7 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Fri, 8 Apr 2022 16:34:01 +0800 Subject: [PATCH 3/5] feat: also drop spki --- docs/rfc/000-Payload-v37.md | 23 ++----------------- .../payload_internal/version-37.encoder.ts | 19 ++++++--------- .../src/payload_internal/version-37.parser.ts | 4 ++-- packages/encryption/src/utils/crypto.ts | 5 +--- .../tests/__snapshots__/encryption.ts.snap | 4 ++-- .../__snapshots__/v37-encode-decode.ts.snap | 2 +- 6 files changed, 15 insertions(+), 42 deletions(-) diff --git a/docs/rfc/000-Payload-v37.md b/docs/rfc/000-Payload-v37.md index ce297cb1ff91..7997ad282618 100644 --- a/docs/rfc/000-Payload-v37.md +++ b/docs/rfc/000-Payload-v37.md @@ -123,9 +123,7 @@ The implementation MUST NOT fail if the algorithm is not supported. This field represents the public key of the author. -The value is in the DER encoding of the SubjectPublicKeyInfo (`spki`) structure from [RFC 5280][rfc5280]. - -[rfc5280]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.7 +The value is in the raw format of the EC key. When it is `null`, it represents no this information is available (due to software defeat or user choice to opt-out). @@ -182,7 +180,7 @@ This field represents the iv used to encrypt the message. ###### `authorEphemeralPublicKey` field -This field is a Map of the DER encoding of the SubjectPublicKeyInfo (`spki`) structure from [RFC5280]. +This field is a Map of the raw format of the EC key. The key indicates its format. @@ -199,25 +197,8 @@ The implementation MUST fail when the decryption result is NOT a valid TypedMess ### `secp256k1` -When `spki` is mentioned in this spec, the implementation MUST be able to recognize the SubjectPublicKeyInfo of the curve [`secp256k1`][secp256k1]. This curve is widely used in the Mask Network. - [secp256k1]: https://en.bitcoin.it/wiki/Secp256k1 -Here is an example of the `secp256k1` public key in Binary. - -```plaintext -[ - 48, 86, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, - 1, 6, 5, 43, 129, 4, 0, 10, 3, 66, 0, 4, - 236, 81, 1, 232, 133, 60, 235, 215, 107, 253, 124, 90, - 12, 21, 14, 139, 178, 143, 232, 52, 240, 119, 105, 91, - 196, 232, 84, 33, 238, 69, 42, 104, 223, 226, 96, 216, - 191, 166, 10, 63, 179, 111, 125, 99, 161, 131, 168, 172, - 181, 245, 168, 182, 150, 19, 182, 240, 202, 62, 202, 219, - 21, 175, 144, 205 -] -``` - ## FAQ ### Why the version number is negative? diff --git a/packages/encryption/src/payload_internal/version-37.encoder.ts b/packages/encryption/src/payload_internal/version-37.encoder.ts index 14bc496149c3..33143bb99be0 100644 --- a/packages/encryption/src/payload_internal/version-37.encoder.ts +++ b/packages/encryption/src/payload_internal/version-37.encoder.ts @@ -1,6 +1,6 @@ import { Ok } from 'ts-results' import type { PayloadWellFormed } from '..' -import { encodeMessagePack, exportCryptoKeyToSPKI } from '../utils' +import { encodeMessagePack, exportCryptoKeyToRaw } from '../utils' const enum Index { version = 0, @@ -22,12 +22,12 @@ export async function encode37(payload: PayloadWellFormed.Payload) { if (payload.authorPublicKey.some) { const { algr, key } = payload.authorPublicKey.val payload_arr[Index.authorPublicKeyAlgorithm] = algr - const spki = await exportCryptoKeyToSPKI(key) - if (spki.ok) { - payload_arr[Index.authorPublicKey] = spki.val + const raw = await exportCryptoKeyToRaw(key) + if (raw.ok) { + payload_arr[Index.authorPublicKey] = raw.val } else { payload_arr[Index.authorPublicKey] = null - warn(key, spki.err) + warn(key, raw.err) } } if (payload.encryption.type === 'E2E') { @@ -35,7 +35,7 @@ export async function encode37(payload: PayloadWellFormed.Payload) { const keyMaterials: any = {} const subArr: any[] = [1, ownersAESKeyEncrypted, iv, keyMaterials] for (const [alg, key] of ephemeralPublicKey.entries()) { - const k = await exportCryptoKeyToSPKI(key) + const k = await exportCryptoKeyToRaw(key) if (k.err) warn(key, k.err) else keyMaterials[alg] = k.val } @@ -49,10 +49,5 @@ export async function encode37(payload: PayloadWellFormed.Payload) { return Ok(encodeMessagePack(payload_arr)) } function warn(key: CryptoKey, err: any) { - console.warn( - '[@masknet/encryption] Failed to encode a public key object into spki format. key is', - key, - 'and the error is', - err, - ) + console.warn('[@masknet/encryption] Failed to export public key. key is', key, 'and the error is', err) } diff --git a/packages/encryption/src/payload_internal/version-37.parser.ts b/packages/encryption/src/payload_internal/version-37.parser.ts index c92aefa88a28..3d4e697da0c8 100644 --- a/packages/encryption/src/payload_internal/version-37.parser.ts +++ b/packages/encryption/src/payload_internal/version-37.parser.ts @@ -13,8 +13,8 @@ import { parseAuthor } from './shared' const decode = decodeMessagePackF(PayloadException.InvalidPayload, PayloadException.DecodeFailed) const InvalidPayload = (msg?: string) => new CheckedError(PayloadException.InvalidPayload, msg).toErr() -const importSpki = CheckedError.withErr(importEC_Key, CryptoException.InvalidCryptoKey) const importAES256 = CheckedError.withErr(importAES, CryptoException.InvalidCryptoKey) +const importEC = CheckedError.withErr(importEC_Key, CryptoException.InvalidCryptoKey) export async function parse37(input: Uint8Array): PayloadParserResult { const signatureContainer = parseSignatureContainer(input) if (signatureContainer.err) return signatureContainer @@ -94,7 +94,7 @@ function importAsymmetryKey(algr: unknown, key: unknown, name: string) { return andThenAsync(assertUint8Array(key, name, CryptoException.InvalidCryptoKey), async (pubKey): T => { if (typeof algr === 'number') { if (algr in EC_KeyCurveEnum) { - const key = await importSpki(pubKey, algr) + const key = await importEC(pubKey, algr) if (key.err) return key return Ok({ algr, key: key.val }) } diff --git a/packages/encryption/src/utils/crypto.ts b/packages/encryption/src/utils/crypto.ts index ba32d2ec5ecd..3fcb0c783a4a 100644 --- a/packages/encryption/src/utils/crypto.ts +++ b/packages/encryption/src/utils/crypto.ts @@ -20,9 +20,6 @@ export function importAES(key: JsonWebKey | Uint8Array): Promise crypto.subtle.exportKey('jwk', key)) } -export function exportCryptoKeyToSPKI(key: CryptoKey) { - return Result.wrapAsync(() => crypto.subtle.exportKey('spki', key).then((x) => new Uint8Array(x))) -} export function exportCryptoKeyToRaw(key: CryptoKey) { return Result.wrapAsync(() => crypto.subtle.exportKey('raw', key).then((x) => new Uint8Array(x))) } @@ -39,7 +36,7 @@ export function importEC_Key(key: JsonWebKey | Uint8Array, kind: EC_KeyCurveEnum } const args = [ImportParamsMap[kind], true, DeriveKeyUsage] as const if (key instanceof Uint8Array) { - return crypto.subtle.importKey('spki', key, ...args) as Promise + return crypto.subtle.importKey('raw', key, ...args) as Promise } else { return crypto.subtle.importKey('jwk', key, ...args) as Promise } diff --git a/packages/encryption/tests/__snapshots__/encryption.ts.snap b/packages/encryption/tests/__snapshots__/encryption.ts.snap index cf7c3aa316f3..8e9103780240 100644 --- a/packages/encryption/tests/__snapshots__/encryption.ts.snap +++ b/packages/encryption/tests/__snapshots__/encryption.ts.snap @@ -109,7 +109,7 @@ Object { "network": "localhost", "postIV": "Z/9AS037AaQi7QQQfq+OIw==", }, - "output": Uint8Array [ 9200c501329700a96c6f63616c686f7374a3626f6202c4583056301006072a8648ce3d020106052b8104000a03420004fbdd1a19eeb484e44ced760c141ff185b4bef2eb8998a052054cb7e4548716bf1032b7bbdae5dd881e40cf98e40d196bfd1f0dc2d20c3c8f71e6eb7330b5f1a19401c430e3b51fe6c57b5831460666e8ddf01b49ebb513848cc9eb014a4c322b3afbbf0af21a902912080179494adc12941bc3dbc41067ff404b4dfb01a422ed04107eaf8e2381a132c4583056301006072a8648ce3d020106052b8104000a03420004640c0574dbba0be00e7e6f0080fb2f4428f72245b5adb4d3bd95694d645a6b2423c6d09bab7075a1b9f63d7c6760189bc6b0cfa341ea1be9fe3d8b95fda37268c42251312d4d2137b78846f8cd793113e78726fef59ec68c2335a51d6a27d12d4c78172d ], + "output": Uint8Array [ 9200c501049700a96c6f63616c686f7374a3626f6202c44104fbdd1a19eeb484e44ced760c141ff185b4bef2eb8998a052054cb7e4548716bf1032b7bbdae5dd881e40cf98e40d196bfd1f0dc2d20c3c8f71e6eb7330b5f1a19401c430e3b51fe6c57b5831460666e8ddf01b49ebb513848cc9eb014a4c322b3afbbf0af21a902912080179494adc12941bc3dbc41067ff404b4dfb01a422ed04107eaf8e2381a132c44104640c0574dbba0be00e7e6f0080fb2f4428f72245b5adb4d3bd95694d645a6b2423c6d09bab7075a1b9f63d7c6760189bc6b0cfa341ea1be9fe3d8b95fda37268c42251312d4d2137b78846f8cd793113e78726fef59ec68c2335a51d6a27d12d4c78172d ], "postKey": CryptoKey { [opaque crypto key material] }, } `; @@ -152,7 +152,7 @@ Object { "network": "localhost", "postIV": "AAECAwQFBgcICQoLDA0ODw==", }, - "output": Uint8Array [ 9200c501089700a96c6f63616c686f7374a5616c69636502c4583056301006072a8648ce3d020106052b8104000a03420004afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58c931d5975900006531c46a73f84b33a03755dfbe567ec504c470dd244440dd63e9300c42025186b44aca49a79b749bb8dc3a39c5c5fe38b0d202255b742258d574d6379a1c410000102030405060708090a0b0c0d0e0fc463422847d65139731573ca340118fa81883ae4cffa41cb7c91d378dd43c72ebad227c7af84e61f19fd4820fca920472d68a1076ccbe42f620eb73036bc7e13eb330d6f065c1e6ea02cb219d3e8a06a31a58d3d0b52bf8a8d03a0d001119d1b93f377ceab ], + "output": Uint8Array [ 9200c4f19700a96c6f63616c686f7374a5616c69636502c44104afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58c931d5975900006531c46a73f84b33a03755dfbe567ec504c470dd244440dd63e9300c42025186b44aca49a79b749bb8dc3a39c5c5fe38b0d202255b742258d574d6379a1c410000102030405060708090a0b0c0d0e0fc463422847d65139731573ca340118fa81883ae4cffa41cb7c91d378dd43c72ebad227c7af84e61f19fd4820fca920472d68a1076ccbe42f620eb73036bc7e13eb330d6f065c1e6ea02cb219d3e8a06a31a58d3d0b52bf8a8d03a0d001119d1b93f377ceab ], "postKey": CryptoKey { [opaque crypto key material] }, } `; diff --git a/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap b/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap index bfeddd776b02..986176571fa1 100644 --- a/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap +++ b/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap @@ -17,7 +17,7 @@ Object { } `; -exports[`Encode v37 payload: Full payload 1`] = `Uint8Array [ 9200c4ef9700a96c6f63616c686f7374a7756e6b6e6f776e02c4583056301006072a8648ce3d020106052b8104000a03420004afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58c931d5975900006531c46a73f84b33a03755dfbe567ec504c470dd244440dd63e9401c40605060708090ac410000102030405060708090a0b0c0d0e0f81a132c4583056301006072a8648ce3d020106052b8104000a03420004afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58c931d5975900006531c46a73f84b33a03755dfbe567ec504c470dd244440dd63ec4050001020304 ]`; +exports[`Encode v37 payload: Full payload 1`] = `Uint8Array [ 9200c4c19700a96c6f63616c686f7374a7756e6b6e6f776e02c44104afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58c931d5975900006531c46a73f84b33a03755dfbe567ec504c470dd244440dd63e9401c40605060708090ac410000102030405060708090a0b0c0d0e0f81a132c44104afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58c931d5975900006531c46a73f84b33a03755dfbe567ec504c470dd244440dd63ec4050001020304 ]`; exports[`Encode v37 payload: Full payload parsed 1`] = ` Object { From f21f7d39ebdf8e266b82fab06560a9636209c285 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Fri, 8 Apr 2022 16:46:28 +0800 Subject: [PATCH 4/5] feat: compress k256 key --- docs/rfc/000-Payload-v37.md | 10 ++-------- .../src/payload_internal/version-37.encoder.ts | 11 +++++++++-- .../src/payload_internal/version-37.parser.ts | 5 ++++- .../encryption/tests/__snapshots__/encryption.ts.snap | 4 ++-- .../tests/__snapshots__/v37-encode-decode.ts.snap | 2 +- packages/shared-base/src/crypto/secp256k1.ts | 11 +++++++++++ 6 files changed, 29 insertions(+), 14 deletions(-) diff --git a/docs/rfc/000-Payload-v37.md b/docs/rfc/000-Payload-v37.md index 7997ad282618..00e9ccf76973 100644 --- a/docs/rfc/000-Payload-v37.md +++ b/docs/rfc/000-Payload-v37.md @@ -123,7 +123,7 @@ The implementation MUST NOT fail if the algorithm is not supported. This field represents the public key of the author. -The value is in the raw format of the EC key. +The value is in the compressed format of the EC key. When it is `null`, it represents no this information is available (due to software defeat or user choice to opt-out). @@ -180,7 +180,7 @@ This field represents the iv used to encrypt the message. ###### `authorEphemeralPublicKey` field -This field is a Map of the raw format of the EC key. +This field is a Map of the compressed format of the EC key. The key indicates its format. @@ -204,9 +204,3 @@ The implementation MUST fail when the decryption result is NOT a valid TypedMess ### Why the version number is negative? The pre 1.0 version of the Mask Network extension uses `-42` as its initial payload version. The number `42` comes from the book _The Hitchhiker's Guide to the Galaxy_ and the minus sign indicates this is an early version. When a new payload format is drafted, it's a natural idea that the version number should add by 1, therefore it should be `-41`. At the time of this RFC written, the latest payload is version `-38`, therefore this RFC follows the convention to mark the version as `-37`. - -### Why not uses the `raw` format defined in the Web Crypto specification for AES key? - -According to [the Web Crypto specification][webcrypto], `raw` format is NOT standardized therefore it might have a co-operational problem. - -[webcrypto]: https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-handle diff --git a/packages/encryption/src/payload_internal/version-37.encoder.ts b/packages/encryption/src/payload_internal/version-37.encoder.ts index 33143bb99be0..f0a05180633e 100644 --- a/packages/encryption/src/payload_internal/version-37.encoder.ts +++ b/packages/encryption/src/payload_internal/version-37.encoder.ts @@ -1,5 +1,7 @@ +import { compressSecp256k1KeyRaw } from '@masknet/shared-base' import { Ok } from 'ts-results' import type { PayloadWellFormed } from '..' +import { EC_KeyCurveEnum } from '../payload/types' import { encodeMessagePack, exportCryptoKeyToRaw } from '../utils' const enum Index { @@ -24,7 +26,9 @@ export async function encode37(payload: PayloadWellFormed.Payload) { payload_arr[Index.authorPublicKeyAlgorithm] = algr const raw = await exportCryptoKeyToRaw(key) if (raw.ok) { - payload_arr[Index.authorPublicKey] = raw.val + if (algr === EC_KeyCurveEnum.secp256k1) + payload_arr[Index.authorPublicKey] = compressSecp256k1KeyRaw(raw.val) + else payload_arr[Index.authorPublicKey] = raw.val } else { payload_arr[Index.authorPublicKey] = null warn(key, raw.err) @@ -37,7 +41,10 @@ export async function encode37(payload: PayloadWellFormed.Payload) { for (const [alg, key] of ephemeralPublicKey.entries()) { const k = await exportCryptoKeyToRaw(key) if (k.err) warn(key, k.err) - else keyMaterials[alg] = k.val + else { + if (alg === EC_KeyCurveEnum.secp256k1) keyMaterials[alg] = compressSecp256k1KeyRaw(k.val) + else keyMaterials[alg] = k.val + } } payload_arr[Index.encryption] = subArr } else { diff --git a/packages/encryption/src/payload_internal/version-37.parser.ts b/packages/encryption/src/payload_internal/version-37.parser.ts index 3d4e697da0c8..a00eb26fc6d0 100644 --- a/packages/encryption/src/payload_internal/version-37.parser.ts +++ b/packages/encryption/src/payload_internal/version-37.parser.ts @@ -1,7 +1,7 @@ import type { PayloadParserResult } from '.' import type { PayloadParseResult } from '../payload' import { CryptoException, PayloadException, assertArray, assertUint8Array } from '../types' -import { andThenAsync, CheckedError, OptionalResult } from '@masknet/shared-base' +import { andThenAsync, CheckedError, decompressSecp256k1KeyRaw, OptionalResult } from '@masknet/shared-base' import { Ok, Result } from 'ts-results' import { EC_Key, EC_KeyCurveEnum } from '../payload/types' import { decodeMessagePackF, assertIVLengthEq16, importAES, importEC_Key } from '../utils' @@ -94,6 +94,9 @@ function importAsymmetryKey(algr: unknown, key: unknown, name: string) { return andThenAsync(assertUint8Array(key, name, CryptoException.InvalidCryptoKey), async (pubKey): T => { if (typeof algr === 'number') { if (algr in EC_KeyCurveEnum) { + if (algr === EC_KeyCurveEnum.secp256k1) { + pubKey = decompressSecp256k1KeyRaw(pubKey) + } const key = await importEC(pubKey, algr) if (key.err) return key return Ok({ algr, key: key.val }) diff --git a/packages/encryption/tests/__snapshots__/encryption.ts.snap b/packages/encryption/tests/__snapshots__/encryption.ts.snap index 8e9103780240..1d7513dcd76f 100644 --- a/packages/encryption/tests/__snapshots__/encryption.ts.snap +++ b/packages/encryption/tests/__snapshots__/encryption.ts.snap @@ -109,7 +109,7 @@ Object { "network": "localhost", "postIV": "Z/9AS037AaQi7QQQfq+OIw==", }, - "output": Uint8Array [ 9200c501049700a96c6f63616c686f7374a3626f6202c44104fbdd1a19eeb484e44ced760c141ff185b4bef2eb8998a052054cb7e4548716bf1032b7bbdae5dd881e40cf98e40d196bfd1f0dc2d20c3c8f71e6eb7330b5f1a19401c430e3b51fe6c57b5831460666e8ddf01b49ebb513848cc9eb014a4c322b3afbbf0af21a902912080179494adc12941bc3dbc41067ff404b4dfb01a422ed04107eaf8e2381a132c44104640c0574dbba0be00e7e6f0080fb2f4428f72245b5adb4d3bd95694d645a6b2423c6d09bab7075a1b9f63d7c6760189bc6b0cfa341ea1be9fe3d8b95fda37268c42251312d4d2137b78846f8cd793113e78726fef59ec68c2335a51d6a27d12d4c78172d ], + "output": Uint8Array [ 9200c4c49700a96c6f63616c686f7374a3626f6202c42103fbdd1a19eeb484e44ced760c141ff185b4bef2eb8998a052054cb7e4548716bf9401c430e3b51fe6c57b5831460666e8ddf01b49ebb513848cc9eb014a4c322b3afbbf0af21a902912080179494adc12941bc3dbc41067ff404b4dfb01a422ed04107eaf8e2381a132c42102640c0574dbba0be00e7e6f0080fb2f4428f72245b5adb4d3bd95694d645a6b24c42251312d4d2137b78846f8cd793113e78726fef59ec68c2335a51d6a27d12d4c78172d ], "postKey": CryptoKey { [opaque crypto key material] }, } `; @@ -152,7 +152,7 @@ Object { "network": "localhost", "postIV": "AAECAwQFBgcICQoLDA0ODw==", }, - "output": Uint8Array [ 9200c4f19700a96c6f63616c686f7374a5616c69636502c44104afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58c931d5975900006531c46a73f84b33a03755dfbe567ec504c470dd244440dd63e9300c42025186b44aca49a79b749bb8dc3a39c5c5fe38b0d202255b742258d574d6379a1c410000102030405060708090a0b0c0d0e0fc463422847d65139731573ca340118fa81883ae4cffa41cb7c91d378dd43c72ebad227c7af84e61f19fd4820fca920472d68a1076ccbe42f620eb73036bc7e13eb330d6f065c1e6ea02cb219d3e8a06a31a58d3d0b52bf8a8d03a0d001119d1b93f377ceab ], + "output": Uint8Array [ 9200c4d19700a96c6f63616c686f7374a5616c69636502c42102afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58c9300c42025186b44aca49a79b749bb8dc3a39c5c5fe38b0d202255b742258d574d6379a1c410000102030405060708090a0b0c0d0e0fc463422847d65139731573ca340118fa81883ae4cffa41cb7c91d378dd43c72ebad227c7af84e61f19fd4820fca920472d68a1076ccbe42f620eb73036bc7e13eb330d6f065c1e6ea02cb219d3e8a06a31a58d3d0b52bf8a8d03a0d001119d1b93f377ceab ], "postKey": CryptoKey { [opaque crypto key material] }, } `; diff --git a/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap b/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap index 986176571fa1..4c266abfd920 100644 --- a/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap +++ b/packages/encryption/tests/__snapshots__/v37-encode-decode.ts.snap @@ -17,7 +17,7 @@ Object { } `; -exports[`Encode v37 payload: Full payload 1`] = `Uint8Array [ 9200c4c19700a96c6f63616c686f7374a7756e6b6e6f776e02c44104afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58c931d5975900006531c46a73f84b33a03755dfbe567ec504c470dd244440dd63e9401c40605060708090ac410000102030405060708090a0b0c0d0e0f81a132c44104afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58c931d5975900006531c46a73f84b33a03755dfbe567ec504c470dd244440dd63ec4050001020304 ]`; +exports[`Encode v37 payload: Full payload 1`] = `Uint8Array [ 9200c4819700a96c6f63616c686f7374a7756e6b6e6f776e02c42102afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58c9401c40605060708090ac410000102030405060708090a0b0c0d0e0f81a132c42102afdb55600abe8749b944469377a78c4d60522bb64842ccf0820a225346a8e58cc4050001020304 ]`; exports[`Encode v37 payload: Full payload parsed 1`] = ` Object { diff --git a/packages/shared-base/src/crypto/secp256k1.ts b/packages/shared-base/src/crypto/secp256k1.ts index a9aecc240215..cb017bdac46e 100644 --- a/packages/shared-base/src/crypto/secp256k1.ts +++ b/packages/shared-base/src/crypto/secp256k1.ts @@ -49,6 +49,17 @@ export function decompressSecp256k1Point(point: Uint8Array): { x: string; y: str return { x: toBase64URL(x), y: toBase64URL(y) } } +export function compressSecp256k1KeyRaw(point: Uint8Array) { + if (!secp256k1.isPoint(point)) throw new TypeError('Not a point on secp256k1!') + if (secp256k1.isPointCompressed(point)) return point + return secp256k1.pointCompress(point, true) +} +export function decompressSecp256k1KeyRaw(point: Uint8Array) { + if (!secp256k1.isPoint(point)) throw new TypeError('Not a point on secp256k1!') + if (!secp256k1.isPointCompressed(point)) return point + return secp256k1.pointCompress(point, false) +} + export function compressSecp256k1Key(key: EC_JsonWebKey): string { const arr = compressSecp256k1Point(key.x!, key.y!) return encodeArrayBuffer(arr) From 0a11d898ed3b45c565900b68f16d51901047dc52 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Tue, 12 Apr 2022 19:53:00 +0800 Subject: [PATCH 5/5] chore: remove webcrypto-liner --- packages/encryption/package.json | 1 + packages/encryption/tests/setup.ts | 18 ++---------- packages/mask/.webpack/config.ts | 8 ------ packages/mask/.webpack/template.html | 1 - packages/mask/background/setup.ts | 2 ++ packages/mask/package.json | 1 + packages/polyfills/builder.mjs | 11 +------- packages/polyfills/elliptic.js | 4 --- packages/polyfills/package.json | 4 +-- packages/polyfills/rollup.config.js | 8 ------ pnpm-lock.yaml | 41 ++++++++++++---------------- 11 files changed, 27 insertions(+), 72 deletions(-) delete mode 100644 packages/polyfills/elliptic.js diff --git a/packages/encryption/package.json b/packages/encryption/package.json index 168085a816c6..530a6d11e5ad 100644 --- a/packages/encryption/package.json +++ b/packages/encryption/package.json @@ -10,6 +10,7 @@ } }, "dependencies": { + "@dimensiondev/secp256k1-webcrypto": "1.0.0-20220412114204-be816df", "@dimensiondev/stego-js": "0.11.1-20201027083223-8ab41be", "@masknet/shared-base": "workspace:*", "@masknet/typed-message": "workspace:*", diff --git a/packages/encryption/tests/setup.ts b/packages/encryption/tests/setup.ts index 1f0839cbce28..26c67f53e009 100644 --- a/packages/encryption/tests/setup.ts +++ b/packages/encryption/tests/setup.ts @@ -1,22 +1,10 @@ import { test } from '@jest/globals' -import { webcrypto } from 'crypto' import { atob, btoa } from 'buffer' +import { polyfill } from '@dimensiondev/secp256k1-webcrypto/node' test('Setup env', () => {}) if (!Reflect.get(globalThis, 'crypto')) { - Object.assign(globalThis, { - crypto: webcrypto, - atob, - btoa, - self: globalThis, - navigator: { - userAgent: 'Chrome/99.0.0.0', - }, - }) - - // @ts-ignore - await import('../../polyfills/dist/secp256k1.js') - Reflect.deleteProperty(globalThis, 'navigator') - Reflect.deleteProperty(globalThis, 'self') + polyfill() + Object.assign(globalThis, { atob, btoa }) } diff --git a/packages/mask/.webpack/config.ts b/packages/mask/.webpack/config.ts index ad3ef35989ef..fa17ce5cc6ad 100644 --- a/packages/mask/.webpack/config.ts +++ b/packages/mask/.webpack/config.ts @@ -267,7 +267,6 @@ export function createConfiguration(rawFlags: BuildFlags): Configuration { addHTMLEntry({ chunks: ['background'], filename: 'background.html', - secp256k1: true, gun: true, sourceMap: !!sourceMapKind, }), @@ -295,18 +294,11 @@ export function createConfiguration(rawFlags: BuildFlags): Configuration { } function addHTMLEntry( options: HTMLPlugin.Options & { - secp256k1?: boolean sourceMap: boolean gun?: boolean }, ) { let templateContent = readFileSync(join(__dirname, './template.html'), 'utf8') - if (options.secp256k1) { - templateContent = templateContent.replace( - ``, - '', - ) - } if (options.gun) { templateContent = templateContent.replace(``, '') } diff --git a/packages/mask/.webpack/template.html b/packages/mask/.webpack/template.html index 11a6e47c32df..2b2a8cc3c964 100644 --- a/packages/mask/.webpack/template.html +++ b/packages/mask/.webpack/template.html @@ -6,7 +6,6 @@ - diff --git a/packages/mask/background/setup.ts b/packages/mask/background/setup.ts index b1446fa111ac..359b798972b8 100644 --- a/packages/mask/background/setup.ts +++ b/packages/mask/background/setup.ts @@ -1,4 +1,6 @@ +import { polyfill } from '@dimensiondev/secp256k1-webcrypto' import { setupMaskKVStorageBackend } from '../shared/kv-storage' import { inMemory_KVStorageBackend, indexedDB_KVStorageBackend } from './database/kv-storage' +polyfill() setupMaskKVStorageBackend(indexedDB_KVStorageBackend, inMemory_KVStorageBackend) diff --git a/packages/mask/package.json b/packages/mask/package.json index 815712175efd..389910a67d47 100644 --- a/packages/mask/package.json +++ b/packages/mask/package.json @@ -8,6 +8,7 @@ "@dimensiondev/holoflows-kit": "^0.9.0-20210902104757-7c3d0d0", "@dimensiondev/mask-wallet-core": "0.1.0-20211013082857-eb62e5f", "@dimensiondev/metamask-extension-provider": "3.0.6-20210519045409-1835d4d", + "@dimensiondev/secp256k1-webcrypto": "1.0.0-20220412114204-be816df", "@ethersproject/abi": "^5.4.0", "@ethersproject/address": "^5.0.4", "@ethersproject/providers": "^5.0.9", diff --git a/packages/polyfills/builder.mjs b/packages/polyfills/builder.mjs index afc8ace7001e..56bff31e87bb 100644 --- a/packages/polyfills/builder.mjs +++ b/packages/polyfills/builder.mjs @@ -20,7 +20,7 @@ let polyfillVersion = '__' const lockfile = await readFile(lockfilePath) const hash = createHash('sha256') hash.update(lockfile) - polyfillVersion = 'v4' + hash.digest('hex') + polyfillVersion = 'v5' + hash.digest('hex') } const versionFilePath = fileURLToPath(new URL('./dist/version.txt', import.meta.url)) @@ -52,18 +52,9 @@ for (const optionsObj of options) { await Promise.all(optionsObj.output.map(bundle.write)) } -const elliptic = await readFile(fileURLToPath(new URL('./dist/internal_elliptic.js', import.meta.url)), 'utf-8') -const liner = await readFile(require.resolve('webcrypto-liner/build/webcrypto-liner.shim.min.mjs'), 'utf-8') -await writeFile( - fileURLToPath(new URL('./dist/secp256k1.js', import.meta.url)), - `${elliptic}; -${liner};`, -) - await normalize(new URL('./dist/dom.js', import.meta.url)) await normalize(new URL('./dist/ecmascript.js', import.meta.url)) await normalize(new URL('./dist/intl.js', import.meta.url)) -await normalize(new URL('./dist/secp256k1.js', import.meta.url)) await normalize(new URL('./dist/worker.js', import.meta.url)) await writeFile(versionFilePath, polyfillVersion) diff --git a/packages/polyfills/elliptic.js b/packages/polyfills/elliptic.js deleted file mode 100644 index 7575b1b1c3a7..000000000000 --- a/packages/polyfills/elliptic.js +++ /dev/null @@ -1,4 +0,0 @@ -import elliptic from 'elliptic' -import { Buffer } from './node_modules/buffer/index' -globalThis.elliptic = elliptic -globalThis.Buffer = Buffer diff --git a/packages/polyfills/package.json b/packages/polyfills/package.json index ef092ba0c91e..6cc611a533f8 100644 --- a/packages/polyfills/package.json +++ b/packages/polyfills/package.json @@ -18,8 +18,6 @@ "dependencies": { "buffer": "^6.0.3", "clipboard-polyfill": "^3.0.3", - "core-js": "^3.21.1", - "elliptic": "^6.5.4", - "webcrypto-liner": "1.3.1" + "core-js": "^3.21.1" } } diff --git a/packages/polyfills/rollup.config.js b/packages/polyfills/rollup.config.js index d2e87c000eab..1a894c663d6f 100644 --- a/packages/polyfills/rollup.config.js +++ b/packages/polyfills/rollup.config.js @@ -30,14 +30,6 @@ export default [ }, plugins: plugins(), }, - { - input: join(__dirname, './elliptic.js'), - output: { - file: 'internal_elliptic.js', - format: 'iife', - }, - plugins: plugins(), - }, ] function plugins() { return [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bcc05365e881..938de131dcfc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -237,11 +237,13 @@ importers: packages/encryption: specifiers: + '@dimensiondev/secp256k1-webcrypto': 1.0.0-20220412114204-be816df '@dimensiondev/stego-js': 0.11.1-20201027083223-8ab41be '@masknet/shared-base': workspace:* '@masknet/typed-message': workspace:* '@msgpack/msgpack': ^2.7.2 dependencies: + '@dimensiondev/secp256k1-webcrypto': 1.0.0-20220412114204-be816df '@dimensiondev/stego-js': 0.11.1-20201027083223-8ab41be '@masknet/shared-base': link:../shared-base '@masknet/typed-message': link:../typed-message @@ -288,6 +290,7 @@ importers: '@dimensiondev/holoflows-kit': ^0.9.0-20210902104757-7c3d0d0 '@dimensiondev/mask-wallet-core': 0.1.0-20211013082857-eb62e5f '@dimensiondev/metamask-extension-provider': 3.0.6-20210519045409-1835d4d + '@dimensiondev/secp256k1-webcrypto': 1.0.0-20220412114204-be816df '@dimensiondev/webextension-shim': 0.0.3-20210823035705-4257e12 '@ethersproject/abi': ^5.4.0 '@ethersproject/address': ^5.0.4 @@ -428,6 +431,7 @@ importers: '@dimensiondev/holoflows-kit': 0.9.0-20210902104757-7c3d0d0_webextension-polyfill@0.9.0 '@dimensiondev/mask-wallet-core': 0.1.0-20211013082857-eb62e5f_protobufjs@6.11.2 '@dimensiondev/metamask-extension-provider': 3.0.6-20210519045409-1835d4d + '@dimensiondev/secp256k1-webcrypto': 1.0.0-20220412114204-be816df '@ethersproject/abi': 5.4.0 '@ethersproject/address': 5.4.0 '@ethersproject/providers': 5.4.2 @@ -924,16 +928,12 @@ importers: clipboard-polyfill: ^3.0.3 core-js: ^3.21.1 core-js-builder: ^3.21.1 - elliptic: ^6.5.4 rollup: ^2.70.1 rollup-plugin-terser: ^7.0.2 - webcrypto-liner: 1.3.1 dependencies: buffer: 6.0.3 clipboard-polyfill: 3.0.3 core-js: 3.21.1 - elliptic: 6.5.4 - webcrypto-liner: 1.3.1 devDependencies: '@rollup/plugin-commonjs': 21.0.3_rollup@2.70.1 '@rollup/plugin-json': 4.1.0_rollup@2.70.1 @@ -4039,6 +4039,13 @@ packages: tmp: 0.0.33 dev: true + /@dimensiondev/secp256k1-webcrypto/1.0.0-20220412114204-be816df: + resolution: {integrity: sha512-gDNH39SnATJogShz7egcc4aJqBUurB7xzyNVuVy78XmkAz57xG7nWlo5KyC8sh9cZDHNwi12vYI1zJz5UPgN2A==, tarball: download/@dimensiondev/secp256k1-webcrypto/1.0.0-20220412114204-be816df/7e05b026476e62dc08df835fa6a559e9dbcfe976128f54172b8d0d0221aad6af} + dependencies: + elliptic: 6.5.4 + pvtsutils: 1.2.2 + dev: false + /@dimensiondev/stego-js/0.11.1-20201027083223-8ab41be: resolution: {integrity: sha512-lm49qcX2O40Nn+AGKN6J4qrpPHaffGnvUI3mCh+obyiZxT9H5/vZv1B+SUm2bXq8r2LeLHIeW90x1lpyg1roTQ==, tarball: download/@dimensiondev/stego-js/0.11.1-20201027083223-8ab41be/2d41418365c7ea41e10de432e82b0707c3a3a3b70a20a3733276162eeb6c4bcd} hasBin: true @@ -5904,6 +5911,7 @@ packages: pvtsutils: 1.2.1 tslib: 2.3.1 dev: false + optional: true /@peculiar/json-schema/1.1.12: resolution: {integrity: sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==} @@ -5911,6 +5919,7 @@ packages: dependencies: tslib: 2.3.1 dev: false + optional: true /@peculiar/webcrypto/1.2.3: resolution: {integrity: sha512-q7wDfZy3k/tpnsYB23/MyyDkjn6IdHh8w+xwoVMS5cu6CjVoFzngXDZEOOuSE4zus2yO6ciQhhHxd4XkLpwVnQ==} @@ -8331,6 +8340,7 @@ packages: /@types/asn1js/2.0.2: resolution: {integrity: sha512-t4YHCgtD+ERvH0FyxvNlYwJ2ezhqw7t+Ygh4urQ7dJER8i185JPv6oIM3ey5YQmGN6Zp9EMbpohkjZi9t3UxwA==} dev: false + optional: true /@types/babel__core/7.1.18: resolution: {integrity: sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==} @@ -10321,10 +10331,6 @@ packages: resolution: {integrity: sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=} dev: false - /asmcrypto.js/2.3.2: - resolution: {integrity: sha512-3FgFARf7RupsZETQ1nHnhLUUvpcttcCq1iZCaVAbJZbCZ5VNRrNyvpDyHTOb0KC3llFcsyOT/a99NZcCbeiEsA==} - dev: false - /asn1.js/5.4.1: resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} dependencies: @@ -10345,6 +10351,7 @@ packages: dependencies: pvutils: 1.1.3 dev: false + optional: true /assert-plus/1.0.0: resolution: {integrity: sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=} @@ -21778,6 +21785,7 @@ packages: dependencies: tslib: 2.3.1 dev: false + optional: true /pvtsutils/1.2.2: resolution: {integrity: sha512-OALo5ZEdqiI127i64+CXwkCOyFHUA+tCQgaUO/MvRDFXWPr53f2sx28ECNztUEzuyu5xvuuD1EB/szg9mwJoGA==} @@ -21789,6 +21797,7 @@ packages: resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==} engines: {node: '>=6.0.0'} dev: false + optional: true /q/1.5.1: resolution: {integrity: sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=} @@ -26168,21 +26177,7 @@ packages: pvtsutils: 1.2.1 tslib: 2.3.1 dev: false - - /webcrypto-liner/1.3.1: - resolution: {integrity: sha512-xCxg3DKpJ8UNsriAQq0KpOpY4xU6lvQFZbs0d/pnGdE8IRzzfAao4Z2qXsSvDRN0OraH3MlvK3j2ocUk23ymFA==} - dependencies: - '@peculiar/asn1-schema': 2.0.44 - '@peculiar/json-schema': 1.1.12 - asmcrypto.js: 2.3.2 - asn1js: 2.2.0 - core-js: 3.21.1 - des.js: 1.0.1 - elliptic: 6.5.4 - pvtsutils: 1.2.1 - tslib: 2.3.1 - webcrypto-core: 1.4.0 - dev: false + optional: true /webextension-polyfill-ts/0.22.0: resolution: {integrity: sha512-3P33ClMwZ/qiAT7UH1ROrkRC1KM78umlnPpRhdC/292UyoTTW9NcjJEqDsv83HbibcTB6qCtpVeuB2q2/oniHQ==}