Skip to content

Commit

Permalink
fix(did-comm): remove isomorphic-webcrypto dependency (#1401)
Browse files Browse the repository at this point in the history
fixes #1381
fixes #1387

Signed-off-by: Mircea Nistor <[email protected]>
  • Loading branch information
mirceanis authored Jul 11, 2024
1 parent 018e189 commit 85cc1ce
Show file tree
Hide file tree
Showing 14 changed files with 1,284 additions and 1,351 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"@microsoft/api-extractor": "7.40.6",
"@microsoft/api-extractor-model": "7.28.13",
"@microsoft/tsdoc": "0.14.2",
"@noble/hashes": "1.3.3",
"@noble/hashes": "1.4.0",
"@stablelib/ed25519": "1.0.3",
"@transmute/credentials-context": "0.7.0-unstable.82",
"@types/express": "4.17.21",
Expand All @@ -49,7 +49,7 @@
"did-resolver": "4.1.0",
"ethers": "6.11.1",
"ethr-did-resolver": "10.1.9",
"express": "4.18.2",
"express": "4.19.2",
"ganache": "7.9.2",
"jest": "29.7.0",
"jest-config": "29.7.0",
Expand Down
7 changes: 2 additions & 5 deletions packages/did-comm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@
}
},
"dependencies": {
"@noble/curves": "^1.1.0",
"@stablelib/aes": "^2.0.0",
"@noble/curves": "^1.4.2",
"@noble/ciphers": "^0.5.3",
"@stablelib/aes-kw": "^1.0.1",
"@stablelib/gcm": "^1.0.2",
"@stablelib/xchacha20poly1305": "^1.0.1",
"@veramo/core-types": "workspace:^",
"@veramo/kv-store": "workspace:^",
"@veramo/mediation-manager": "workspace:^",
Expand All @@ -31,7 +29,6 @@
"debug": "^4.3.3",
"did-jwt": "^8.0.0",
"did-resolver": "^4.1.0",
"isomorphic-webcrypto": "^2.3.8",
"uuid": "^9.0.0"
},
"devDependencies": {
Expand Down
2,157 changes: 1,089 additions & 1,068 deletions packages/did-comm/src/__tests__/encryption.test.ts

Large diffs are not rendered by default.

57 changes: 13 additions & 44 deletions packages/did-comm/src/encryption/a256cbc-hs512-dir.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import crypto from 'isomorphic-webcrypto'
import { randomBytes } from '@noble/hashes/utils'
import { hmac } from '@noble/hashes/hmac'
import { sha512 } from '@noble/hashes/sha512'
import { cbc } from '@noble/ciphers/aes'
import { base64ToBytes, bytesToBase64url, concat, encodeBase64url } from '@veramo/utils'
import { Decrypter, Encrypter, EncryptionResult, ProtectedHeader } from 'did-jwt'
import { fromString } from 'uint8arrays/from-string'
Expand Down Expand Up @@ -39,38 +41,18 @@ async function cbcEncrypt(
) {
// A256CBC-HS512 CEK size should be 512 bits; first 256 bits are used for HMAC with SHA-512 and the rest for AES-CBC
const keySize = parseInt(enc.slice(1, 4), 10)
const encKey = await crypto.subtle.importKey('raw', cek.subarray(keySize >> 3), 'AES-CBC', false, [
'encrypt',
])
const macKey = await crypto.subtle.importKey(
'raw',
cek.subarray(0, keySize >> 3),
{
hash: `SHA-${keySize << 1}`,
name: 'HMAC',
},
false,
['sign'],
)
const encKey = cek.subarray(keySize >> 3)
const macKey = cek.subarray(0, keySize >> 3)

if (providedIV && providedIV.length !== keySize >> 4) {
throw new Error(`illegal_argument: Invalid IV size, expected ${keySize >> 4}, got ${providedIV.length}`)
}
const iv = providedIV ?? randomBytes(keySize >> 4)

const ciphertext = new Uint8Array(
await crypto.subtle.encrypt(
{
iv,
name: 'AES-CBC',
},
encKey,
plaintext,
),
)
const ciphertext = cbc(encKey, iv).encrypt(plaintext)

const macData = concat([aad, iv, ciphertext, uint64be(aad.length << 3)])
const tag = new Uint8Array((await crypto.subtle.sign('HMAC', macKey, macData)).slice(0, keySize >> 3))
const tag = hmac(sha512, macKey, macData).slice(0, keySize >> 3)

return { enc: 'dir', ciphertext, tag, iv }
}
Expand All @@ -96,30 +78,17 @@ async function cbcDecrypt(
aad: Uint8Array,
) {
const keySize = parseInt(enc.slice(1, 4), 10)
const encKey = await crypto.subtle.importKey('raw', cek.subarray(keySize >> 3), 'AES-CBC', false, [
'decrypt',
])
const macKey = await crypto.subtle.importKey(
'raw',
cek.subarray(0, keySize >> 3),
{
hash: `SHA-${keySize << 1}`,
name: 'HMAC',
},
false,
['sign'],
)
const encKey = cek.subarray(keySize >> 3)
const macKey = cek.subarray(0, keySize >> 3)

const macData = concat([aad, iv, ciphertext, uint64be(aad.length << 3)])
const expectedTag = new Uint8Array(
(await crypto.subtle.sign('HMAC', macKey, macData)).slice(0, keySize >> 3),
)
const expectedTag = hmac(sha512, macKey, macData).slice(0, keySize >> 3)

let macCheckPassed!: boolean
let macCheckPassed: boolean = false
try {
macCheckPassed = timingSafeEqual(tag, expectedTag)
} catch {
//
// nop
}
if (!macCheckPassed) {
// current JWE decryption pipeline tries to decrypt multiple times with different keys, so return null instead of
Expand All @@ -130,7 +99,7 @@ async function cbcDecrypt(

let plaintext: Uint8Array | null = null
try {
plaintext = new Uint8Array(await crypto.subtle.decrypt({ iv, name: 'AES-CBC' }, encKey, ciphertext))
plaintext = cbc(encKey, iv).decrypt(ciphertext)
} catch (e: any) {
// current JWE decryption pipeline tries to decrypt multiple times with different keys, so return null instead of
// throwing an error
Expand Down
16 changes: 6 additions & 10 deletions packages/did-comm/src/encryption/a256gcm-dir.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
import type { Decrypter, Encrypter, EncryptionResult, ProtectedHeader } from 'did-jwt'
import { AES } from '@stablelib/aes'
import { GCM } from '@stablelib/gcm'
import { gcm } from '@noble/ciphers/aes'
import { randomBytes } from '@noble/hashes/utils'
import { bytesToBase64url, encodeBase64url } from '@veramo/utils'
import { fromString } from 'uint8arrays/from-string'

function createA256GCMEncrypter(
key: Uint8Array,
): (cleartext: Uint8Array, aad?: Uint8Array) => EncryptionResult {
const blockcipher = new AES(key)
const cipher = new GCM(blockcipher)
return (cleartext: Uint8Array, aad?: Uint8Array) => {
const iv = randomBytes(cipher.nonceLength)
const sealed = cipher.seal(iv, cleartext, aad)
const iv = randomBytes(gcm.nonceLength)
const sealed = gcm(key, iv, aad).encrypt(cleartext)
return {
ciphertext: sealed.subarray(0, sealed.length - cipher.tagLength),
tag: sealed.subarray(sealed.length - cipher.tagLength),
ciphertext: sealed.subarray(0, sealed.length - gcm.tagLength),
tag: sealed.subarray(sealed.length - gcm.tagLength),
iv,
}
}
Expand All @@ -42,10 +39,9 @@ export function a256gcmDirEncrypter(key: Uint8Array): Encrypter {
}

export function a256gcmDirDecrypter(key: Uint8Array): Decrypter {
const cipher = new GCM(new AES(key))

async function decrypt(sealed: Uint8Array, iv: Uint8Array, aad?: Uint8Array): Promise<Uint8Array | null> {
return cipher.open(iv, sealed, aad)
return gcm(key, iv, aad).decrypt(sealed)
}

return { alg: 'dir', enc: 'A256GCM', decrypt }
Expand Down
16 changes: 8 additions & 8 deletions packages/did-comm/src/encryption/xc20pkw.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import type { Decrypter, KeyWrapper, WrappingResult } from 'did-jwt'
import { randomBytes } from '@noble/hashes/utils'
import { concat } from '@veramo/utils'
import { XChaCha20Poly1305 } from '@stablelib/xchacha20poly1305'
import { xchacha20poly1305 } from '@noble/ciphers/chacha'

export const xc20pKeyWrapper: KeyWrapper = {
from: (wrappingKey: Uint8Array) => {
const cipher = new XChaCha20Poly1305(wrappingKey)
const wrap = async (cek: Uint8Array): Promise<WrappingResult> => {
const iv = randomBytes(cipher.nonceLength)
const sealed = cipher.seal(iv, cek)
const iv = randomBytes(xchacha20poly1305.nonceLength)
const cipher = xchacha20poly1305(wrappingKey, iv)
const sealed = cipher.encrypt(cek)
return {
ciphertext: sealed.subarray(0, sealed.length - cipher.tagLength),
tag: sealed.subarray(sealed.length - cipher.tagLength),
ciphertext: sealed.subarray(0, sealed.length - xchacha20poly1305.tagLength),
tag: sealed.subarray(sealed.length - xchacha20poly1305.tagLength),
iv,
}
}
Expand All @@ -22,10 +22,10 @@ export const xc20pKeyWrapper: KeyWrapper = {
}

export function xc20pDecrypter(key: Uint8Array): Decrypter {
const cipher = new XChaCha20Poly1305(key)

async function decrypt(sealed: Uint8Array, iv: Uint8Array, aad?: Uint8Array): Promise<Uint8Array | null> {
return cipher.open(iv, sealed, aad)
const cipher = xchacha20poly1305(key, iv, aad)
return cipher.decrypt(sealed)
}

return { alg: 'dir', enc: 'XC20P', decrypt }
Expand Down
4 changes: 2 additions & 2 deletions packages/did-provider-ion/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
},
"dependencies": {
"@decentralized-identity/ion-sdk": "^1.0.1",
"@noble/curves": "^1.1.0",
"@noble/hashes": "^1.3.1",
"@noble/curves": "^1.4.2",
"@noble/hashes": "^1.4.0",
"@sphereon/ion-pow": "^0.2.0",
"@sphereon/isomorphic-argon2": "^1.0.1",
"@trust/keyto": "^1.0.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/did-provider-jwk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"extract-api": "node ../cli/bin/veramo.js dev extract-api"
},
"dependencies": {
"@noble/curves": "^1.1.0",
"@noble/curves": "^1.4.2",
"@veramo/core-types": "workspace:^",
"@veramo/did-manager": "workspace:^",
"@veramo/utils": "workspace:^",
Expand Down
2 changes: 1 addition & 1 deletion packages/key-manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"extract-api": "node ../cli/bin/veramo.js dev extract-api"
},
"dependencies": {
"@noble/curves": "^1.1.0",
"@noble/curves": "^1.4.2",
"@veramo/core-types": "workspace:^",
"@veramo/utils": "workspace:^",
"debug": "^4.3.4",
Expand Down
3 changes: 1 addition & 2 deletions packages/kms-local/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
"extract-api": "node ../cli/bin/veramo.js dev extract-api"
},
"dependencies": {
"@noble/curves": "^1.1.0",
"@noble/curves": "^1.4.2",
"@stablelib/nacl": "^1.0.4",
"@stablelib/random": "^1.0.2",
"@veramo/core-types": "workspace:^",
"@veramo/key-manager": "workspace:^",
"@veramo/utils": "workspace:^",
Expand Down
2 changes: 1 addition & 1 deletion packages/kms-local/src/__tests__/kms-local.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
hexToBytes,
stringToUtf8Bytes,
} from '../../../utils/src'
import { randomBytes } from '@stablelib/random'
import { randomBytes } from 'ethers'
import {
convertPublicKeyToX25519,
convertSecretKeyToX25519,
Expand Down
3 changes: 1 addition & 2 deletions packages/kms-local/src/secret-box.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { AbstractSecretBox } from '@veramo/key-manager'
import { secretBox, openSecretBox, generateKeyPair } from '@stablelib/nacl'
import { randomBytes } from '@stablelib/random'
import { getBytes, concat, hexlify, toUtf8Bytes, toUtf8String } from 'ethers'
import { getBytes, concat, hexlify, toUtf8Bytes, toUtf8String, randomBytes } from 'ethers'

const NONCE_BYTES = 24

Expand Down
2 changes: 1 addition & 1 deletion packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
},
"dependencies": {
"@ipld/dag-pb": "^4.0.5",
"@noble/curves": "^1.1.0",
"@noble/curves": "^1.4.2",
"@veramo/core-types": "workspace:^",
"credential-status": "^3.0.0",
"cross-fetch": "^4.0.0",
Expand Down
Loading

0 comments on commit 85cc1ce

Please sign in to comment.