From 26e1c25de5af47fb97f8f7bd58662ce4594879ce Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Mon, 13 Nov 2023 16:57:31 +0100 Subject: [PATCH 01/21] chore: migrate to ecies/js --- packages/utils/package.json | 1 + packages/utils/src/crypto/ec-utils.ts | 107 ++++++++++++-------- packages/utils/test/crypto/ec-utils.test.ts | 32 +++--- yarn.lock | 26 +++++ 4 files changed, 107 insertions(+), 59 deletions(-) diff --git a/packages/utils/package.json b/packages/utils/package.json index f08b2a03dd..da510336b7 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -42,6 +42,7 @@ "dependencies": { "@requestnetwork/types": "0.37.0", "@toruslabs/eccrypto": "4.0.0", + "eciesjs": "^0.4.5", "ethers": "5.5.1", "secp256k1": "4.0.2", "tslib": "2.5.0" diff --git a/packages/utils/src/crypto/ec-utils.ts b/packages/utils/src/crypto/ec-utils.ts index 03c3419260..7b1cec3fd3 100644 --- a/packages/utils/src/crypto/ec-utils.ts +++ b/packages/utils/src/crypto/ec-utils.ts @@ -1,6 +1,8 @@ import { publicKeyConvert, ecdsaRecover } from 'secp256k1'; import { ethers } from 'ethers'; -import { Ecies, decrypt, encrypt } from '@toruslabs/eccrypto'; +// import { Ecies, decrypt, encrypt } from '@toruslabs/eccrypto'; + +import { decrypt, encrypt, ECIES_CONFIG } from 'eciesjs'; /** * Function to manage Elliptic-curve cryptography @@ -14,6 +16,11 @@ export { ecSign, }; +ECIES_CONFIG.ellipticCurve = 'secp256k1'; +ECIES_CONFIG.isEphemeralKeyCompressed = false; +ECIES_CONFIG.symmetricAlgorithm = 'aes-256-gcm'; +ECIES_CONFIG.symmetricNonceLength = 16; + /** * Function to derive the address from an EC private key * @@ -132,29 +139,51 @@ function ecRecover(signature: string, data: string): string { * * @returns the encrypted data */ -async function ecEncrypt(publicKey: string, data: string): Promise { +function ecEncrypt(publicKey: string, data: string): string { try { // encrypts the data with the publicKey, returns the encrypted data with encryption parameters (such as IV..) - const compressed = compressPublicKey(publicKey); - const encrypted = await encrypt(Buffer.from(compressed), Buffer.from(data)); + // const compressed = compressPublicKey(publicKey); + // const encrypted = await encrypt(Buffer.from(compressed), Buffer.from(data)); + + return encrypt(publicKey, Buffer.from(data)).toString('hex').slice(2); // Transforms the object with the encrypted data into a smaller string-representation. - return Buffer.concat([ - encrypted.iv, - publicKeyConvert(encrypted.ephemPublicKey), - encrypted.mac, - encrypted.ciphertext, - ]).toString('hex'); + // return Buffer.concat([ + // encrypted.iv, + // publicKeyConvert(encrypted.ephemPublicKey), + // encrypted.mac, + // encrypted.ciphertext, + // ]).toString('hex'); } catch (e) { - if ( - e.message === 'public key length is invalid' || - e.message === 'Expected public key to be an Uint8Array with length [33, 65]' - ) { + if (e.message === 'second arg must be public key') { throw new Error('The public key must be a string representing 64 bytes'); } throw e; } } +// +// /** +// * Function to encrypt data with a public key +// * +// * @param publicKey the public key to encrypt with +// * @param data the data to encrypt +// * +// * @returns the encrypted data +// */ +// function ecEncrypt(publicKey: string, data: string): string { +// try { +// // encrypts the data with the publicKey, returns the encrypted data with encryption parameters (such as IV..) +// return encrypt(publicKey, Buffer.from(data)).toString('hex'); +// } catch (e) { +// if ( +// e.message === 'public key length is invalid' || +// e.message === 'Expected public key to be an Uint8Array with length [33, 65]' +// ) { +// throw new Error('The public key must be a string representing 64 bytes'); +// } +// throw e; +// } +// } /** * Function to decrypt data with a public key @@ -164,25 +193,17 @@ async function ecEncrypt(publicKey: string, data: string): Promise { * * @returns the decrypted data */ -async function ecDecrypt(privateKey: string, data: string): Promise { +function ecDecrypt(privateKey: string, data: string): string { try { - const buf = await decrypt(Buffer.from(privateKey.replace(/^0x/, ''), 'hex'), eciesSplit(data)); - return buf.toString(); + if (!data.startsWith('04')) { + data = `04${data}`; + } + return decrypt(privateKey, Buffer.from(data, 'hex')).toString(); } catch (e) { - if ( - e.message === 'Bad private key' || - e.message === 'Expected private key to be an Uint8Array with length 32' - ) { + if (e.message === 'Invalid private key') { throw new Error('The private key must be a string representing 32 bytes'); } - if ( - e.message === 'public key length is invalid' || - e.message === 'Expected public key to be an Uint8Array with length [33, 65]' || - e.message === 'Bad MAC' || - e.message === 'bad MAC after trying padded' || - e.message === 'the public key could not be parsed or is invalid' || - e.message === 'Public Key could not be parsed' - ) { + if (e.message === 'second arg must be public key') { throw new Error('The encrypted data is not well formatted'); } throw e; @@ -205,17 +226,17 @@ function compressPublicKey(publicKey: string): Uint8Array { * Split an encrypted string to ECIES params * inspired from https://github.com/pubkey/eth-crypto/blob/master/src/ecDecrypt-with-private-key.js */ -const eciesSplit = (str: string): Ecies => { - const buf = Buffer.from(str, 'hex'); - - const ephemPublicKeyStr = buf.toString('hex', 16, 49); - - return { - iv: Buffer.from(buf.toString('hex', 0, 16), 'hex'), - mac: Buffer.from(buf.toString('hex', 49, 81), 'hex'), - ciphertext: Buffer.from(buf.toString('hex', 81, buf.length), 'hex'), - ephemPublicKey: Buffer.from( - publicKeyConvert(new Uint8Array(Buffer.from(ephemPublicKeyStr, 'hex')), false), - ), - }; -}; +// const eciesSplit = (str: string): Ecies => { +// const buf = Buffer.from(str, 'hex'); +// +// const ephemPublicKeyStr = buf.toString('hex', 16, 49); +// +// return { +// iv: Buffer.from(buf.toString('hex', 0, 16), 'hex'), +// mac: Buffer.from(buf.toString('hex', 49, 81), 'hex'), +// ciphertext: Buffer.from(buf.toString('hex', 81, buf.length), 'hex'), +// ephemPublicKey: Buffer.from( +// publicKeyConvert(new Uint8Array(Buffer.from(ephemPublicKeyStr, 'hex')), false), +// ), +// }; +// }; diff --git a/packages/utils/test/crypto/ec-utils.test.ts b/packages/utils/test/crypto/ec-utils.test.ts index 668708c2ab..b803c9ed9a 100644 --- a/packages/utils/test/crypto/ec-utils.test.ts +++ b/packages/utils/test/crypto/ec-utils.test.ts @@ -97,15 +97,15 @@ describe('Utils/EcUtils', () => { describe('encrypt', () => { it('can encrypt', async () => { - const encryptedData = await ecEncrypt(rawId.publicKey, anyData); + const encryptedData = ecEncrypt(rawId.publicKey, anyData); // 'encrypt() error' expect(encryptedData.length).toBe(226); // 'decrypt() error' - expect(await ecDecrypt(rawId.privateKey, encryptedData)).toBe(anyData); + expect(ecDecrypt(rawId.privateKey, encryptedData)).toBe(anyData); }); it('can encrypt with other public key formats', async () => { - const encryptedData = await ecEncrypt( + const encryptedData = ecEncrypt( '0396212fc129c2f78771218b2e93da7a5aac63490a42bb41b97848c39c14fe65cd', anyData, ); @@ -113,7 +113,7 @@ describe('Utils/EcUtils', () => { }); it('cannot encrypt data with a wrong public key', async () => { - await expect(ecEncrypt('cf4a', anyData)).rejects.toThrowError( + expect(() => ecEncrypt('cf4a', anyData)).toThrow( 'The public key must be a string representing 64 bytes', ); }); @@ -121,7 +121,7 @@ describe('Utils/EcUtils', () => { describe('decrypt', () => { it('can decrypt', async () => { - const data = await ecDecrypt( + const data = ecDecrypt( rawId.privateKey, '307bac038efaa5bf8a0ac8db53fd4de8024a0c0baf37283a9e6671589eba18edc12b3915ff0df66e6ffad862440228a65ead99e3320e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc70a', ); @@ -130,36 +130,36 @@ describe('Utils/EcUtils', () => { }); it('cannot decrypt data with a wrong private key', async () => { - await expect( + expect(() => ecDecrypt( '0xaa', '307bac038efaa5bf8a0ac8db53fd4de8024a0c0baf37283a9e6671589eba18edc12b3915ff0df66e6ffad862440228a65ead99e3320e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc70a', ), - ).rejects.toThrowError('The private key must be a string representing 32 bytes'); + ).toThrow('The private key must be a string representing 32 bytes'); }); it('cannot decrypt data with a wrong encrypted data: public key too short', async () => { - await expect(ecDecrypt(rawId.privateKey, 'aa')).rejects.toThrowError( + expect(() => ecDecrypt(rawId.privateKey, 'aa')).toThrow( 'The encrypted data is not well formatted', ); }); it('cannot decrypt data with a wrong encrypted data: public key not parsable', async () => { - await expect( + expect(() => ecDecrypt( rawId.privateKey, 'e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc7', ), - ).rejects.toThrowError('The encrypted data is not well formatted'); + ).toThrow('The encrypted data is not well formatted'); }); it('cannot decrypt data with a wrong encrypted data: bad MAC', async () => { - await expect( + expect(() => ecDecrypt( rawId.privateKey, '307bac038efaa5bf8a0ac8db53fd4de8024a0c0baf37283a9e6671589eba18edc12b3915ff0df66e6ffad862440228a65ead99e3320e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc7', ), - ).rejects.toThrowError('The encrypted data is not well formatted'); + ).toThrow('The encrypted data is not well formatted'); }); it.each([ @@ -168,22 +168,22 @@ describe('Utils/EcUtils', () => { ])('should be compatible with legacy $type implementation of eccrypto', async ({ array }) => { for (const row of array) { const { data, key, encrypted } = row; - const decrypted = await ecDecrypt(key, encrypted); + const decrypted = ecDecrypt(key, encrypted); expect(decrypted).toBe(data); } }); }); it('can encrypt()', async () => { - const encryptedData = await ecEncrypt(rawId.publicKey, anyData); + const encryptedData = ecEncrypt(rawId.publicKey, anyData); // 'encrypt() error' expect(encryptedData.length).toBe(226); // 'decrypt() error' - expect(await ecDecrypt(rawId.privateKey, encryptedData)).toBe(anyData); + expect(ecDecrypt(rawId.privateKey, encryptedData)).toBe(anyData); }); it('can decrypt()', async () => { - const data = await ecDecrypt( + const data = ecDecrypt( rawId.privateKey, '307bac038efaa5bf8a0ac8db53fd4de8024a0c0baf37283a9e6671589eba18edc12b3915ff0df66e6ffad862440228a65ead99e3320e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc70a', ); diff --git a/yarn.lock b/yarn.lock index 3f7056f0ff..3d1d30097f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3871,11 +3871,28 @@ bn.js "5.2.1" borsh "^0.7.0" +"@noble/ciphers@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.3.0.tgz#6ba3090afdc7a7051393486f6af210e62e0f04ec" + integrity sha512-ldbrnOjmNRwFdXcTM6uXDcxpMIFrbzAWNnpBPp4oTJTFF0XByGD6vf45WrehZGXRQTRVV+Zm8YP+EgEf+e4cWA== + +"@noble/curves@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== + dependencies: + "@noble/hashes" "1.3.2" + "@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": version "1.2.0" resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz" integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== +"@noble/hashes@1.3.2", "@noble/hashes@^1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== + "@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": version "1.7.1" resolved "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz" @@ -9492,6 +9509,15 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" +eciesjs@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/eciesjs/-/eciesjs-0.4.5.tgz#35c48963e6942687da2bc93eb5b612ebf6a0bbfb" + integrity sha512-2zSRIygO48LpdS95Rwt9ryIkJNO37IdbkjRsnYyAn7gx7e4WPBNimnk6jGNdx2QQYr/VJRPnSVdwQpO5bycYZw== + dependencies: + "@noble/ciphers" "^0.3.0" + "@noble/curves" "^1.2.0" + "@noble/hashes" "^1.3.2" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" From c48a00a3d017408e73f8f5d6dfb9e82a54396dfa Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Mon, 13 Nov 2023 17:56:37 +0100 Subject: [PATCH 02/21] handle sign and recover --- packages/utils/package.json | 5 +- packages/utils/src/crypto/ec-utils.ts | 130 +++++--------------------- yarn.lock | 11 +-- 3 files changed, 29 insertions(+), 117 deletions(-) diff --git a/packages/utils/package.json b/packages/utils/package.json index da510336b7..196a3185e3 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -40,11 +40,10 @@ "test:watch": "yarn test --watch" }, "dependencies": { + "@noble/curves": "1.2.0", "@requestnetwork/types": "0.37.0", - "@toruslabs/eccrypto": "4.0.0", - "eciesjs": "^0.4.5", + "eciesjs": "0.4.5", "ethers": "5.5.1", - "secp256k1": "4.0.2", "tslib": "2.5.0" }, "devDependencies": { diff --git a/packages/utils/src/crypto/ec-utils.ts b/packages/utils/src/crypto/ec-utils.ts index 7b1cec3fd3..60a7948cdf 100644 --- a/packages/utils/src/crypto/ec-utils.ts +++ b/packages/utils/src/crypto/ec-utils.ts @@ -1,8 +1,8 @@ -import { publicKeyConvert, ecdsaRecover } from 'secp256k1'; import { ethers } from 'ethers'; -// import { Ecies, decrypt, encrypt } from '@toruslabs/eccrypto'; -import { decrypt, encrypt, ECIES_CONFIG } from 'eciesjs'; +import { decrypt, ECIES_CONFIG, encrypt, PublicKey } from 'eciesjs'; +import { secp256k1 } from '@noble/curves/secp256k1'; +import { computeAddress } from 'ethers/lib/utils'; /** * Function to manage Elliptic-curve cryptography @@ -49,13 +49,13 @@ function getAddressFromPrivateKey(privateKey: string): string { /** * Function to derive the address from an EC public key * - * @param publicKey the public key to derive + * @param publicKeyHex the public key to derive * * @returns the address */ -function getAddressFromPublicKey(publicKey: string): string { +function getAddressFromPublicKey(publicKeyHex: string): string { try { - return ethers.utils.computeAddress(compressPublicKey(publicKey)); + return ethers.utils.computeAddress(PublicKey.fromHex(publicKeyHex).toHex(true)); } catch (e) { if ( e.message === 'public key length is invalid' || @@ -69,22 +69,20 @@ function getAddressFromPublicKey(publicKey: string): string { } /** - * Function ecSigndata with ECDSA + * Function ecSign data with ECDSA * - * @param data the data to sign + * @param privateKey the private key used to sign the message + * @param dataHash the data to sign * * @returns the signature */ -function ecSign(privateKey: string, data: string): string { +function ecSign(privateKey: string, dataHash: string): string { try { - const signingKey = new ethers.utils.SigningKey(privateKey); - return ethers.utils.joinSignature(signingKey.signDigest(data)); + privateKey = privateKey.replace(/^0x/, ''); + dataHash = dataHash.replace(/^0x/, ''); + return `0x${secp256k1.sign(dataHash, privateKey).toCompactHex()}1b`; } catch (e) { - if ( - e.message === 'private key length is invalid' || - e.message === 'Expected private key to be an Uint8Array with length 32' || - e.code === 'INVALID_ARGUMENT' - ) { + if (e.message === 'private key must be 32 bytes, hex or bigint, not string') { throw new Error('The private key must be a string representing 32 bytes'); } throw e; @@ -94,37 +92,25 @@ function ecSign(privateKey: string, data: string): string { /** * Function to recover address from a signature * - * @param signature the signature - * @param data the data signed + * @param signatureHex the signature + * @param dataHash the data signed * * @returns the address */ -function ecRecover(signature: string, data: string): string { +function ecRecover(signatureHex: string, dataHash: string): string { try { - signature = signature.replace(/^0x/, ''); - data = data.replace(/^0x/, ''); - // split into v-value and sig - const sigOnly = signature.substring(0, signature.length - 2); // all but last 2 chars - const vValue = signature.slice(-2); // last 2 chars + signatureHex = signatureHex.replace(/^0x/, ''); + dataHash = dataHash.replace(/^0x/, ''); + const sigOnly = signatureHex.substring(0, signatureHex.length - 2); // all but last 2 chars + const vValue = signatureHex.slice(-2); // last 2 chars const recoveryNumber = vValue === '1c' ? 1 : 0; - return ethers.utils.computeAddress( - Buffer.from( - ecdsaRecover( - new Uint8Array(Buffer.from(sigOnly, 'hex')), - recoveryNumber, - new Uint8Array(Buffer.from(data, 'hex')), - false, - ), - ), - ); + const signature = secp256k1.Signature.fromCompact(sigOnly); + const signatureRecover = signature.addRecoveryBit(recoveryNumber); + return computeAddress(`0x${signatureRecover.recoverPublicKey(dataHash).toHex()}`); } catch (e) { - if ( - e.message === 'signature length is invalid' || - e.message === 'Expected signature to be an Uint8Array with length 64' || - e.code === 'INVALID_ARGUMENT' - ) { + if (e.message === 'compactSignature expected 64 bytes, got 0') { throw new Error('The signature must be a string representing 66 bytes'); } throw e; @@ -141,19 +127,7 @@ function ecRecover(signature: string, data: string): string { */ function ecEncrypt(publicKey: string, data: string): string { try { - // encrypts the data with the publicKey, returns the encrypted data with encryption parameters (such as IV..) - // const compressed = compressPublicKey(publicKey); - // const encrypted = await encrypt(Buffer.from(compressed), Buffer.from(data)); - return encrypt(publicKey, Buffer.from(data)).toString('hex').slice(2); - - // Transforms the object with the encrypted data into a smaller string-representation. - // return Buffer.concat([ - // encrypted.iv, - // publicKeyConvert(encrypted.ephemPublicKey), - // encrypted.mac, - // encrypted.ciphertext, - // ]).toString('hex'); } catch (e) { if (e.message === 'second arg must be public key') { throw new Error('The public key must be a string representing 64 bytes'); @@ -161,29 +135,6 @@ function ecEncrypt(publicKey: string, data: string): string { throw e; } } -// -// /** -// * Function to encrypt data with a public key -// * -// * @param publicKey the public key to encrypt with -// * @param data the data to encrypt -// * -// * @returns the encrypted data -// */ -// function ecEncrypt(publicKey: string, data: string): string { -// try { -// // encrypts the data with the publicKey, returns the encrypted data with encryption parameters (such as IV..) -// return encrypt(publicKey, Buffer.from(data)).toString('hex'); -// } catch (e) { -// if ( -// e.message === 'public key length is invalid' || -// e.message === 'Expected public key to be an Uint8Array with length [33, 65]' -// ) { -// throw new Error('The public key must be a string representing 64 bytes'); -// } -// throw e; -// } -// } /** * Function to decrypt data with a public key @@ -209,34 +160,3 @@ function ecDecrypt(privateKey: string, data: string): string { throw e; } } - -/** - * Converts a public key to its compressed form. - */ -function compressPublicKey(publicKey: string): Uint8Array { - publicKey = publicKey.replace(/^0x/, ''); - // if there are more bytes than the key itself, it means there is already a prefix - if (publicKey.length % 32 === 0) { - publicKey = `04${publicKey}`; - } - return publicKeyConvert(Buffer.from(publicKey, 'hex')); -} - -/** - * Split an encrypted string to ECIES params - * inspired from https://github.com/pubkey/eth-crypto/blob/master/src/ecDecrypt-with-private-key.js - */ -// const eciesSplit = (str: string): Ecies => { -// const buf = Buffer.from(str, 'hex'); -// -// const ephemPublicKeyStr = buf.toString('hex', 16, 49); -// -// return { -// iv: Buffer.from(buf.toString('hex', 0, 16), 'hex'), -// mac: Buffer.from(buf.toString('hex', 49, 81), 'hex'), -// ciphertext: Buffer.from(buf.toString('hex', 81, buf.length), 'hex'), -// ephemPublicKey: Buffer.from( -// publicKeyConvert(new Uint8Array(Buffer.from(ephemPublicKeyStr, 'hex')), false), -// ), -// }; -// }; diff --git a/yarn.lock b/yarn.lock index 3d1d30097f..f400e69a98 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4590,13 +4590,6 @@ resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== -"@toruslabs/eccrypto@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@toruslabs/eccrypto/-/eccrypto-4.0.0.tgz#0b27ed2d1e9483e77f42a7619a2c3c19cb802f44" - integrity sha512-Z3EINkbsgJx1t6jCDVIJjLSUEGUtNIeDjhMWmeDGOWcP/+v/yQ1hEvd1wfxEz4q5WqIHhevacmPiVxiJ4DljGQ== - dependencies: - elliptic "^6.5.4" - "@truffle/abi-utils@^0.2.11": version "0.2.11" resolved "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-0.2.11.tgz" @@ -9509,7 +9502,7 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" -eciesjs@^0.4.5: +eciesjs@0.4.5: version "0.4.5" resolved "https://registry.yarnpkg.com/eciesjs/-/eciesjs-0.4.5.tgz#35c48963e6942687da2bc93eb5b612ebf6a0bbfb" integrity sha512-2zSRIygO48LpdS95Rwt9ryIkJNO37IdbkjRsnYyAn7gx7e4WPBNimnk6jGNdx2QQYr/VJRPnSVdwQpO5bycYZw== @@ -18776,7 +18769,7 @@ scuid@^1.1.0: resolved "https://registry.npmjs.org/scuid/-/scuid-1.1.0.tgz" integrity sha512-MuCAyrGZcTLfQoH2XoBlQ8C6bzwN88XT/0slOGz0pn8+gIP85BOAfYa44ZXQUTOwRwPU0QvgU+V+OSajl/59Xg== -secp256k1@4.0.2, secp256k1@^4.0.1: +secp256k1@^4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz" integrity sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg== From 4ecc262169342d7ac78d9fc2a443a798aad1b025 Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sat, 12 Apr 2025 13:01:02 +0200 Subject: [PATCH 03/21] remove corepack property --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index e4c6ce75a8..9f1cc06fae 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,5 @@ "semver": "https://github.com/RequestNetwork/requestNetwork/security/dependabot/197", "json-schema": "https://github.com/RequestNetwork/requestNetwork/security/dependabot/51", "json5": "https://github.com/RequestNetwork/requestNetwork/security/dependabot/165" - }, - "packageManager": "yarn@1.22.21+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72" + } } From 22371d6d77f9acbea500b092613ee6e95a507942 Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sat, 12 Apr 2025 13:56:09 +0200 Subject: [PATCH 04/21] fix some tests --- packages/utils/src/crypto/ec-utils.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/utils/src/crypto/ec-utils.ts b/packages/utils/src/crypto/ec-utils.ts index 60a7948cdf..6efab1cc2e 100644 --- a/packages/utils/src/crypto/ec-utils.ts +++ b/packages/utils/src/crypto/ec-utils.ts @@ -55,13 +55,9 @@ function getAddressFromPrivateKey(privateKey: string): string { */ function getAddressFromPublicKey(publicKeyHex: string): string { try { - return ethers.utils.computeAddress(PublicKey.fromHex(publicKeyHex).toHex(true)); + return ethers.utils.computeAddress(`0x${PublicKey.fromHex(publicKeyHex).toHex(true)}`); } catch (e) { - if ( - e.message === 'public key length is invalid' || - e.message === 'Expected public key to be an Uint8Array with length [33, 65]' || - e.code === 'INVALID_ARGUMENT' - ) { + if (e.code === 'INVALID_ARGUMENT' || e.message === 'second arg must be public key') { throw new Error('The public key must be a string representing 64 bytes'); } throw e; @@ -82,7 +78,7 @@ function ecSign(privateKey: string, dataHash: string): string { dataHash = dataHash.replace(/^0x/, ''); return `0x${secp256k1.sign(dataHash, privateKey).toCompactHex()}1b`; } catch (e) { - if (e.message === 'private key must be 32 bytes, hex or bigint, not string') { + if (e.message === 'invalid private key, expected hex or 32 bytes, got string') { throw new Error('The private key must be a string representing 32 bytes'); } throw e; @@ -110,7 +106,7 @@ function ecRecover(signatureHex: string, dataHash: string): string { const signatureRecover = signature.addRecoveryBit(recoveryNumber); return computeAddress(`0x${signatureRecover.recoverPublicKey(dataHash).toHex()}`); } catch (e) { - if (e.message === 'compactSignature expected 64 bytes, got 0') { + if (e.message === 'compactSignature of length 64 expected, got 0') { throw new Error('The signature must be a string representing 66 bytes'); } throw e; From 351c3b71557ab4952cc28ffd5e844d06ecc57c94 Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sat, 12 Apr 2025 19:53:17 +0200 Subject: [PATCH 05/21] wip --- package.json | 3 +- packages/utils/package.json | 1 + packages/utils/src/crypto.ts | 6 ++- packages/utils/src/crypto/crypto-wrapper.ts | 4 +- packages/utils/src/crypto/ec-utils.ts | 59 ++++++++++++++++++++- packages/utils/src/index.ts | 1 + packages/utils/test/crypto/ec-utils.test.ts | 3 +- tsconfig.json | 2 +- yarn.lock | 2 +- 9 files changed, 71 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 9f1cc06fae..e4c6ce75a8 100644 --- a/package.json +++ b/package.json @@ -69,5 +69,6 @@ "semver": "https://github.com/RequestNetwork/requestNetwork/security/dependabot/197", "json-schema": "https://github.com/RequestNetwork/requestNetwork/security/dependabot/51", "json5": "https://github.com/RequestNetwork/requestNetwork/security/dependabot/165" - } + }, + "packageManager": "yarn@1.22.21+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72" } diff --git a/packages/utils/package.json b/packages/utils/package.json index 0c4b772905..5d052cc347 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -40,6 +40,7 @@ "test:watch": "yarn test --watch" }, "dependencies": { + "@ecies/ciphers": "0.2.3", "@noble/curves": "1.8.1", "@requestnetwork/types": "0.54.0", "eciesjs": "0.4.14", diff --git a/packages/utils/src/crypto.ts b/packages/utils/src/crypto.ts index bc99fa3769..247d9c23be 100644 --- a/packages/utils/src/crypto.ts +++ b/packages/utils/src/crypto.ts @@ -9,11 +9,12 @@ import { } from './crypto/crypto-wrapper'; import { ecDecrypt, + ecDecryptLegacy, ecEncrypt, - getAddressFromPrivateKey, - getAddressFromPublicKey, ecRecover, ecSign, + getAddressFromPrivateKey, + getAddressFromPublicKey, } from './crypto/ec-utils'; import { deepSort } from './utils'; @@ -27,6 +28,7 @@ export { encryptWithAes256gcm, random32Bytes, ecDecrypt, + ecDecryptLegacy, ecEncrypt, getAddressFromPrivateKey, getAddressFromPublicKey, diff --git a/packages/utils/src/crypto/crypto-wrapper.ts b/packages/utils/src/crypto/crypto-wrapper.ts index 50b0151868..68b31b91c7 100644 --- a/packages/utils/src/crypto/crypto-wrapper.ts +++ b/packages/utils/src/crypto/crypto-wrapper.ts @@ -1,7 +1,7 @@ import { createCipheriv, createDecipheriv, randomBytes as cryptoRandomBytes } from 'crypto'; /** - * Functions to manage native crypto functions of nodeJs + * Functions to manage native crypto functions of Node.js */ export { decryptWithAes256cbc, @@ -77,7 +77,7 @@ async function encryptWithAes256gcm(data: Buffer, key: Buffer): Promise /** * Decrypts an encrypted buffer using AES-256-cbc plus a random Initialization Vector (IV) * - * @param encrypted the data to decrypt + * @param encryptedAndIv the data to decrypt * @param key key of the encryption * * @returns Promise resolving a buffer containing the data decrypted diff --git a/packages/utils/src/crypto/ec-utils.ts b/packages/utils/src/crypto/ec-utils.ts index 6efab1cc2e..fe37ad95b6 100644 --- a/packages/utils/src/crypto/ec-utils.ts +++ b/packages/utils/src/crypto/ec-utils.ts @@ -1,14 +1,19 @@ import { ethers } from 'ethers'; -import { decrypt, ECIES_CONFIG, encrypt, PublicKey } from 'eciesjs'; +import { decrypt, ECIES_CONFIG, encrypt, PrivateKey, PublicKey } from 'eciesjs'; import { secp256k1 } from '@noble/curves/secp256k1'; import { computeAddress } from 'ethers/lib/utils'; +import { createHash } from 'node:crypto'; +import { concatBytes } from '@noble/curves/abstract/utils'; +import * as console from 'node:console'; +import { aes256cbc } from '@ecies/ciphers/aes'; /** * Function to manage Elliptic-curve cryptography */ export { ecDecrypt, + ecDecryptLegacy, ecEncrypt, getAddressFromPrivateKey, getAddressFromPublicKey, @@ -145,7 +150,7 @@ function ecDecrypt(privateKey: string, data: string): string { if (!data.startsWith('04')) { data = `04${data}`; } - return decrypt(privateKey, Buffer.from(data, 'hex')).toString(); + return decrypt(privateKey.replace(/^0x/, ''), Buffer.from(data, 'hex')).toString(); } catch (e) { if (e.message === 'Invalid private key') { throw new Error('The private key must be a string representing 32 bytes'); @@ -156,3 +161,53 @@ function ecDecrypt(privateKey: string, data: string): string { throw e; } } + +function ecDecryptLegacy(privateKey: string, data: string): string { + const { iv, mac, ciphertext, ephemPublicKey } = legacyAes256CbcMacSplit(data); + console.log(new Uint8Array(mac)); + + const receiverPrivateKey = PrivateKey.fromHex(privateKey.replace(/^0x/, '')); + + const sharedKey = ephemPublicKey.decapsulate(receiverPrivateKey); + console.log('shared', sharedKey); + return aes256cbc(sharedKey, iv).decrypt(ciphertext).toString(); +} + +class PublicKeyWithSha512Derivation extends PublicKey { + public decapsulate(sk: PrivateKey, compressed = false): Uint8Array { + const senderPoint = this.toBytes(compressed); + const sharedPoint = sk.multiply(this, compressed); + const px = concatBytes(senderPoint, sharedPoint).subarray(0, 32); + console.log('px', Buffer.from(px)); + return this.sha512(px); + } + + private sha512(content: Uint8Array): Uint8Array { + return new Uint8Array(createHash('sha512').update(content).digest()); + } +} + +/** + * Split a legacy-encrypted string to its AES-CDC-MAC params. + * See legacy way of generating an encrypted strings with the `@toruslabs/eccrypto` > `elliptic` library: + * https://github.com/RequestNetwork/requestNetwork/blob/4597d373b0284787273471cf306dd9b849c9f76a/packages/utils/src/crypto/ec-utils.ts#L141 + */ +const legacyAes256CbcMacSplit = (str: string) => { + const buf = Buffer.from(str, 'hex'); + + const ivSize = 16; + const ephemPublicKeySize = 33; + const ephemPublicKeyEnd = ivSize + ephemPublicKeySize; + const macSize = 32; + const macEnd = ephemPublicKeyEnd + macSize; + + const ephemPublicKeyStr = buf.subarray(ivSize, ephemPublicKeyEnd); + const ephemPublicKey = new PublicKeyWithSha512Derivation(ephemPublicKeyStr); + + return { + iv: Buffer.from(buf.toString('hex', 0, ivSize), 'hex'), + mac: Buffer.from(buf.toString('hex', ephemPublicKeyEnd, macEnd), 'hex'), + ciphertext: Buffer.from(buf.toString('hex', macEnd, buf.length), 'hex'), + ephemPublicKey, + }; +}; diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 009900ae71..ecb9d5d613 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -15,6 +15,7 @@ export { encryptWithAes256gcm, random32Bytes, ecDecrypt, + ecDecryptLegacy, ecEncrypt, getAddressFromPrivateKey, getAddressFromPublicKey, diff --git a/packages/utils/test/crypto/ec-utils.test.ts b/packages/utils/test/crypto/ec-utils.test.ts index 6d0906286b..2f4927230e 100644 --- a/packages/utils/test/crypto/ec-utils.test.ts +++ b/packages/utils/test/crypto/ec-utils.test.ts @@ -1,5 +1,6 @@ import { ecDecrypt, + ecDecryptLegacy, ecEncrypt, ecRecover, ecSign, @@ -111,7 +112,7 @@ describe('Utils/EcUtils', () => { describe('decrypt', () => { it('can decrypt', async () => { - const data = ecDecrypt( + const data = ecDecryptLegacy( rawId.privateKey, '307bac038efaa5bf8a0ac8db53fd4de8024a0c0baf37283a9e6671589eba18edc12b3915ff0df66e6ffad862440228a65ead99e3320e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc70a', ); diff --git a/tsconfig.json b/tsconfig.json index 84638a12a9..84b8eff768 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,7 @@ "strict": true, "baseUrl": "./packages", "skipLibCheck": true, - "moduleResolution": "node", + "moduleResolution": "nodenext", "resolveJsonModule": true, "useUnknownInCatchVariables": false, "lib": ["es2019"] diff --git a/yarn.lock b/yarn.lock index 5789ca9104..7b70a9adcd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1772,7 +1772,7 @@ is-absolute "^1.0.0" is-negated-glob "^1.0.0" -"@ecies/ciphers@^0.2.2": +"@ecies/ciphers@0.2.3", "@ecies/ciphers@^0.2.2": version "0.2.3" resolved "https://registry.yarnpkg.com/@ecies/ciphers/-/ciphers-0.2.3.tgz#963805e46d07e646550098ac29cbcc5b132218ea" integrity sha512-tapn6XhOueMwht3E2UzY0ZZjYokdaw9XtL9kEyjhQ/Fb9vL9xTFbOaI+fV0AWvTpYu4BNloC6getKW6NtSg4mA== From c3fa356a6a4efe1cea2c7677534b23ebda13f2ce Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sat, 12 Apr 2025 21:09:35 +0200 Subject: [PATCH 06/21] working algo --- packages/utils/package.json | 1 + packages/utils/src/crypto.ts | 2 +- packages/utils/src/crypto/ec-utils-legacy.ts | 48 ++++++++++++ packages/utils/src/crypto/ec-utils.ts | 57 +------------- yarn.lock | 82 +++++++++++++++----- 5 files changed, 114 insertions(+), 76 deletions(-) create mode 100644 packages/utils/src/crypto/ec-utils-legacy.ts diff --git a/packages/utils/package.json b/packages/utils/package.json index 5d052cc347..0ebba8bd80 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -42,6 +42,7 @@ "dependencies": { "@ecies/ciphers": "0.2.3", "@noble/curves": "1.8.1", + "@noble/hashes": "^1.7.1", "@requestnetwork/types": "0.54.0", "eciesjs": "0.4.14", "ethers": "5.7.2", diff --git a/packages/utils/src/crypto.ts b/packages/utils/src/crypto.ts index 247d9c23be..0c2da882b7 100644 --- a/packages/utils/src/crypto.ts +++ b/packages/utils/src/crypto.ts @@ -9,13 +9,13 @@ import { } from './crypto/crypto-wrapper'; import { ecDecrypt, - ecDecryptLegacy, ecEncrypt, ecRecover, ecSign, getAddressFromPrivateKey, getAddressFromPublicKey, } from './crypto/ec-utils'; +import { ecDecryptLegacy } from './crypto/ec-utils-legacy'; import { deepSort } from './utils'; /** diff --git a/packages/utils/src/crypto/ec-utils-legacy.ts b/packages/utils/src/crypto/ec-utils-legacy.ts new file mode 100644 index 0000000000..dad05328e3 --- /dev/null +++ b/packages/utils/src/crypto/ec-utils-legacy.ts @@ -0,0 +1,48 @@ +import { PrivateKey, PublicKey } from 'eciesjs'; +import { secp256k1 } from '@noble/curves/secp256k1'; +import { sha512 } from '@noble/hashes/sha2'; +import { aes256cbc } from '@ecies/ciphers/aes'; + +export const ecDecryptLegacy = (privateKey: string, data: string): string => { + const { iv, ciphertext, ephemPublicKey } = legacyAes256CbcMacSplit(data); + const receiverPrivateKey = PrivateKey.fromHex(privateKey.replace(/^0x/, '')); + const sharedKey = deriveSharedKeyWithSha512(receiverPrivateKey, ephemPublicKey, false); + const decrypted = aes256cbc(sharedKey.slice(0, 32), iv).decrypt(ciphertext); + return Buffer.from(decrypted).toString(); +}; + +const deriveSharedKeyWithSha512 = ( + privateKey: PrivateKey, + publicKey: PublicKey, + compressed = false, +): Uint8Array => { + const sharedPoint = secp256k1 + .getSharedSecret(privateKey.secret, publicKey.toBytes(compressed)) + .subarray(1); + return new Uint8Array(sha512.create().update(sharedPoint).digest()); +}; + +/** + * Split a legacy-encrypted string to its AES-CDC-MAC params. + * See legacy way of generating an encrypted strings with the `@toruslabs/eccrypto` > `elliptic` library: + * https://github.com/RequestNetwork/requestNetwork/blob/4597d373b0284787273471cf306dd9b849c9f76a/packages/utils/src/crypto/ec-utils.ts#L141 + */ +const legacyAes256CbcMacSplit = (str: string) => { + const buf = Buffer.from(str, 'hex'); + + const ivSize = 16; + const ephemPublicKeySize = 33; + const ephemPublicKeyEnd = ivSize + ephemPublicKeySize; + const macSize = 32; + const macEnd = ephemPublicKeyEnd + macSize; + + const ephemPublicKeyStr = buf.subarray(ivSize, ephemPublicKeyEnd); + const ephemPublicKey = new PublicKey(ephemPublicKeyStr); + + return { + iv: Buffer.from(buf.toString('hex', 0, ivSize), 'hex'), + mac: Buffer.from(buf.toString('hex', ephemPublicKeyEnd, macEnd), 'hex'), + ciphertext: Buffer.from(buf.toString('hex', macEnd, buf.length), 'hex'), + ephemPublicKey, + }; +}; diff --git a/packages/utils/src/crypto/ec-utils.ts b/packages/utils/src/crypto/ec-utils.ts index fe37ad95b6..e17f8290d7 100644 --- a/packages/utils/src/crypto/ec-utils.ts +++ b/packages/utils/src/crypto/ec-utils.ts @@ -1,19 +1,14 @@ import { ethers } from 'ethers'; -import { decrypt, ECIES_CONFIG, encrypt, PrivateKey, PublicKey } from 'eciesjs'; +import { decrypt, ECIES_CONFIG, encrypt, PublicKey } from 'eciesjs'; import { secp256k1 } from '@noble/curves/secp256k1'; import { computeAddress } from 'ethers/lib/utils'; -import { createHash } from 'node:crypto'; -import { concatBytes } from '@noble/curves/abstract/utils'; -import * as console from 'node:console'; -import { aes256cbc } from '@ecies/ciphers/aes'; /** * Function to manage Elliptic-curve cryptography */ export { ecDecrypt, - ecDecryptLegacy, ecEncrypt, getAddressFromPrivateKey, getAddressFromPublicKey, @@ -161,53 +156,3 @@ function ecDecrypt(privateKey: string, data: string): string { throw e; } } - -function ecDecryptLegacy(privateKey: string, data: string): string { - const { iv, mac, ciphertext, ephemPublicKey } = legacyAes256CbcMacSplit(data); - console.log(new Uint8Array(mac)); - - const receiverPrivateKey = PrivateKey.fromHex(privateKey.replace(/^0x/, '')); - - const sharedKey = ephemPublicKey.decapsulate(receiverPrivateKey); - console.log('shared', sharedKey); - return aes256cbc(sharedKey, iv).decrypt(ciphertext).toString(); -} - -class PublicKeyWithSha512Derivation extends PublicKey { - public decapsulate(sk: PrivateKey, compressed = false): Uint8Array { - const senderPoint = this.toBytes(compressed); - const sharedPoint = sk.multiply(this, compressed); - const px = concatBytes(senderPoint, sharedPoint).subarray(0, 32); - console.log('px', Buffer.from(px)); - return this.sha512(px); - } - - private sha512(content: Uint8Array): Uint8Array { - return new Uint8Array(createHash('sha512').update(content).digest()); - } -} - -/** - * Split a legacy-encrypted string to its AES-CDC-MAC params. - * See legacy way of generating an encrypted strings with the `@toruslabs/eccrypto` > `elliptic` library: - * https://github.com/RequestNetwork/requestNetwork/blob/4597d373b0284787273471cf306dd9b849c9f76a/packages/utils/src/crypto/ec-utils.ts#L141 - */ -const legacyAes256CbcMacSplit = (str: string) => { - const buf = Buffer.from(str, 'hex'); - - const ivSize = 16; - const ephemPublicKeySize = 33; - const ephemPublicKeyEnd = ivSize + ephemPublicKeySize; - const macSize = 32; - const macEnd = ephemPublicKeyEnd + macSize; - - const ephemPublicKeyStr = buf.subarray(ivSize, ephemPublicKeyEnd); - const ephemPublicKey = new PublicKeyWithSha512Derivation(ephemPublicKeyStr); - - return { - iv: Buffer.from(buf.toString('hex', 0, ivSize), 'hex'), - mac: Buffer.from(buf.toString('hex', ephemPublicKeyEnd, macEnd), 'hex'), - ciphertext: Buffer.from(buf.toString('hex', macEnd, buf.length), 'hex'), - ephemPublicKey, - }; -}; diff --git a/yarn.lock b/yarn.lock index 7b70a9adcd..04fb102fde 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5020,7 +5020,7 @@ resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== -"@noble/hashes@1.7.1", "@noble/hashes@^1.5.0": +"@noble/hashes@1.7.1", "@noble/hashes@^1.5.0", "@noble/hashes@^1.7.1": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.1.tgz#5738f6d765710921e7a751e00c20ae091ed8db0f" integrity sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ== @@ -11276,10 +11276,10 @@ crypto-browserify@3.12.0, crypto-browserify@^3.0.0: randombytes "^2.0.0" randomfill "^1.0.3" -crypto-js@^3.1.9-1, crypto-js@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" - integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== +crypto-js@^3.1.9-1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.3.0.tgz#846dd1cce2f68aacfa156c8578f926a609b7976b" + integrity sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q== crypto-random-string@^2.0.0: version "2.0.0" @@ -17585,10 +17585,10 @@ json-schema-traverse@^1.0.0: resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json-schema@0.2.3, json-schema@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" - integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha512-a3xHnILGMtk+hDOqNwHzF6e2fNbiMrXZvxKQiEv2MlgQP+pjIOzqAmKYD2mDpXYE/44M7g+n9p2bKkYWDUcXCQ== json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" @@ -17625,7 +17625,19 @@ json-to-pretty-yaml@^1.2.2: remedial "^1.0.7" remove-trailing-spaces "^1.0.6" -json5@^0.5.1, json5@^1.0.1, json5@^1.0.2, json5@^2.1.0, json5@^2.1.2, json5@^2.2.1, json5@^2.2.2, json5@^2.2.3: +json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + integrity sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw== + +json5@^1.0.1, json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +json5@^2.1.0, json5@^2.1.2, json5@^2.2.2, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== @@ -19098,10 +19110,15 @@ minimist-options@4.1.0, minimist-options@^4.0.2: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@0.0.8, minimist@^0.2.4, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@~1.2.8: - version "0.2.4" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.2.4.tgz#0085d5501e29033748a2f2a4da0180142697a475" - integrity sha512-Pkrrm8NjyQ8yVt8Am9M+yUt74zE3iokhzbG1bFVNjLB92vwM71hf40RkEsryg98BujhVOncKm/C1xROxZ030LQ== +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q== + +minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@~1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== minipass-collect@^1.0.2: version "1.0.2" @@ -22671,13 +22688,35 @@ semver-compare@^1.0.0: resolved "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz" integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= -"semver@2 || 3 || 4 || 5", semver@7.3.8, semver@7.5.4, semver@7.x, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^6.0.0, semver@^6.1.0, semver@^6.3.0, semver@^6.3.1, semver@^7.0.0, semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.1, semver@^7.5.3, semver@^7.5.4, semver@~5.4.1: +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@7.3.8: + version "7.3.8" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" + integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== + dependencies: + lru-cache "^6.0.0" + +semver@7.5.4, semver@7.x, semver@^7.0.0, semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.1, semver@^7.5.3, semver@^7.5.4: version "7.5.4" resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" +semver@^6.0.0, semver@^6.1.0, semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@~5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + integrity sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg== + send@0.19.0: version "0.19.0" resolved "https://registry.npmjs.org/send/-/send-0.19.0.tgz" @@ -25201,10 +25240,15 @@ undeclared-identifiers@^1.1.2: simple-concat "^1.0.0" xtend "^4.0.1" -underscore@1.12.1, underscore@1.9.1, underscore@^1.12.1: - version "1.13.7" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.7.tgz#970e33963af9a7dda228f17ebe8399e5fbe63a10" - integrity sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g== +underscore@1.12.1: + version "1.12.1" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e" + integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw== + +underscore@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" + integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== undici@^5.14.0: version "5.28.5" From 431071a28f695dd5ce8aa6923432ea8b061a4aaf Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sat, 12 Apr 2025 21:57:07 +0200 Subject: [PATCH 07/21] test padded --- packages/utils/package.json | 2 +- packages/utils/src/crypto/ec-utils-legacy.ts | 31 +++++--- packages/utils/src/crypto/ec-utils.ts | 10 ++- packages/utils/test/crypto/ec-utils.test.ts | 3 +- yarn.lock | 82 +++++--------------- 5 files changed, 47 insertions(+), 81 deletions(-) diff --git a/packages/utils/package.json b/packages/utils/package.json index 0ebba8bd80..fe8f7830a1 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -42,7 +42,7 @@ "dependencies": { "@ecies/ciphers": "0.2.3", "@noble/curves": "1.8.1", - "@noble/hashes": "^1.7.1", + "@noble/hashes": "1.7.1", "@requestnetwork/types": "0.54.0", "eciesjs": "0.4.14", "ethers": "5.7.2", diff --git a/packages/utils/src/crypto/ec-utils-legacy.ts b/packages/utils/src/crypto/ec-utils-legacy.ts index dad05328e3..1635ccf7fe 100644 --- a/packages/utils/src/crypto/ec-utils-legacy.ts +++ b/packages/utils/src/crypto/ec-utils-legacy.ts @@ -3,23 +3,32 @@ import { secp256k1 } from '@noble/curves/secp256k1'; import { sha512 } from '@noble/hashes/sha2'; import { aes256cbc } from '@ecies/ciphers/aes'; -export const ecDecryptLegacy = (privateKey: string, data: string): string => { - const { iv, ciphertext, ephemPublicKey } = legacyAes256CbcMacSplit(data); - const receiverPrivateKey = PrivateKey.fromHex(privateKey.replace(/^0x/, '')); - const sharedKey = deriveSharedKeyWithSha512(receiverPrivateKey, ephemPublicKey, false); - const decrypted = aes256cbc(sharedKey.slice(0, 32), iv).decrypt(ciphertext); - return Buffer.from(decrypted).toString(); +export const ecDecryptLegacy = (privateKey: string, data: string, padded = false): string => { + try { + const { iv, ciphertext, ephemPublicKey } = legacyAes256CbcMacSplit(data); + const receiverPrivateKey = PrivateKey.fromHex(privateKey.replace(/^0x/, '')); + const sharedKey = deriveSharedKeyWithSha512(receiverPrivateKey, ephemPublicKey, padded); + const decrypted = aes256cbc(sharedKey.slice(0, 32), iv).decrypt(ciphertext); + return Buffer.from(decrypted).toString(); + } catch (e) { + if (e.message === 'error:1C80006B:Provider routines::wrong final block length') { + throw new Error('The encrypted data is not well formatted'); + } + if (e.message === 'error:1C800064:Provider routines::bad decrypt' && !padded) { + return ecDecryptLegacy(privateKey, data, true); + } + throw e; + } }; const deriveSharedKeyWithSha512 = ( privateKey: PrivateKey, publicKey: PublicKey, - compressed = false, + padded = false, ): Uint8Array => { - const sharedPoint = secp256k1 - .getSharedSecret(privateKey.secret, publicKey.toBytes(compressed)) - .subarray(1); - return new Uint8Array(sha512.create().update(sharedPoint).digest()); + const sharedPoint = secp256k1.getSharedSecret(privateKey.secret, publicKey.toBytes()).subarray(1); + const paddedBytes = padded ? sharedPoint.subarray(16, 64) : sharedPoint; + return new Uint8Array(sha512.create().update(paddedBytes).digest()); }; /** diff --git a/packages/utils/src/crypto/ec-utils.ts b/packages/utils/src/crypto/ec-utils.ts index e17f8290d7..9fb3e5f1ac 100644 --- a/packages/utils/src/crypto/ec-utils.ts +++ b/packages/utils/src/crypto/ec-utils.ts @@ -3,6 +3,7 @@ import { ethers } from 'ethers'; import { decrypt, ECIES_CONFIG, encrypt, PublicKey } from 'eciesjs'; import { secp256k1 } from '@noble/curves/secp256k1'; import { computeAddress } from 'ethers/lib/utils'; +import { ecDecryptLegacy } from './ec-utils-legacy'; /** * Function to manage Elliptic-curve cryptography @@ -142,11 +143,12 @@ function ecEncrypt(publicKey: string, data: string): string { */ function ecDecrypt(privateKey: string, data: string): string { try { - if (!data.startsWith('04')) { - data = `04${data}`; - } - return decrypt(privateKey.replace(/^0x/, ''), Buffer.from(data, 'hex')).toString(); + const paddedData = data.startsWith('04') ? data : `04${data}`; + return decrypt(privateKey.replace(/^0x/, ''), Buffer.from(paddedData, 'hex')).toString(); } catch (e) { + if (e.message === 'bad point: equation left != right') { + return ecDecryptLegacy(privateKey, data); + } if (e.message === 'Invalid private key') { throw new Error('The private key must be a string representing 32 bytes'); } diff --git a/packages/utils/test/crypto/ec-utils.test.ts b/packages/utils/test/crypto/ec-utils.test.ts index 2f4927230e..6d0906286b 100644 --- a/packages/utils/test/crypto/ec-utils.test.ts +++ b/packages/utils/test/crypto/ec-utils.test.ts @@ -1,6 +1,5 @@ import { ecDecrypt, - ecDecryptLegacy, ecEncrypt, ecRecover, ecSign, @@ -112,7 +111,7 @@ describe('Utils/EcUtils', () => { describe('decrypt', () => { it('can decrypt', async () => { - const data = ecDecryptLegacy( + const data = ecDecrypt( rawId.privateKey, '307bac038efaa5bf8a0ac8db53fd4de8024a0c0baf37283a9e6671589eba18edc12b3915ff0df66e6ffad862440228a65ead99e3320e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc70a', ); diff --git a/yarn.lock b/yarn.lock index 04fb102fde..7b70a9adcd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5020,7 +5020,7 @@ resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== -"@noble/hashes@1.7.1", "@noble/hashes@^1.5.0", "@noble/hashes@^1.7.1": +"@noble/hashes@1.7.1", "@noble/hashes@^1.5.0": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.1.tgz#5738f6d765710921e7a751e00c20ae091ed8db0f" integrity sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ== @@ -11276,10 +11276,10 @@ crypto-browserify@3.12.0, crypto-browserify@^3.0.0: randombytes "^2.0.0" randomfill "^1.0.3" -crypto-js@^3.1.9-1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.3.0.tgz#846dd1cce2f68aacfa156c8578f926a609b7976b" - integrity sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q== +crypto-js@^3.1.9-1, crypto-js@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" + integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== crypto-random-string@^2.0.0: version "2.0.0" @@ -17585,10 +17585,10 @@ json-schema-traverse@^1.0.0: resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha512-a3xHnILGMtk+hDOqNwHzF6e2fNbiMrXZvxKQiEv2MlgQP+pjIOzqAmKYD2mDpXYE/44M7g+n9p2bKkYWDUcXCQ== +json-schema@0.2.3, json-schema@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" @@ -17625,19 +17625,7 @@ json-to-pretty-yaml@^1.2.2: remedial "^1.0.7" remove-trailing-spaces "^1.0.6" -json5@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw== - -json5@^1.0.1, json5@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" - integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== - dependencies: - minimist "^1.2.0" - -json5@^2.1.0, json5@^2.1.2, json5@^2.2.2, json5@^2.2.3: +json5@^0.5.1, json5@^1.0.1, json5@^1.0.2, json5@^2.1.0, json5@^2.1.2, json5@^2.2.1, json5@^2.2.2, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== @@ -19110,15 +19098,10 @@ minimist-options@4.1.0, minimist-options@^4.0.2: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q== - -minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@~1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +minimist@0.0.8, minimist@^0.2.4, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@~1.2.8: + version "0.2.4" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.2.4.tgz#0085d5501e29033748a2f2a4da0180142697a475" + integrity sha512-Pkrrm8NjyQ8yVt8Am9M+yUt74zE3iokhzbG1bFVNjLB92vwM71hf40RkEsryg98BujhVOncKm/C1xROxZ030LQ== minipass-collect@^1.0.2: version "1.0.2" @@ -22688,35 +22671,13 @@ semver-compare@^1.0.0: resolved "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz" integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: - version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - -semver@7.3.8: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== - dependencies: - lru-cache "^6.0.0" - -semver@7.5.4, semver@7.x, semver@^7.0.0, semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.1, semver@^7.5.3, semver@^7.5.4: +"semver@2 || 3 || 4 || 5", semver@7.3.8, semver@7.5.4, semver@7.x, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^6.0.0, semver@^6.1.0, semver@^6.3.0, semver@^6.3.1, semver@^7.0.0, semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.1, semver@^7.5.3, semver@^7.5.4, semver@~5.4.1: version "7.5.4" resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.1.0, semver@^6.3.0, semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@~5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" - integrity sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg== - send@0.19.0: version "0.19.0" resolved "https://registry.npmjs.org/send/-/send-0.19.0.tgz" @@ -25240,15 +25201,10 @@ undeclared-identifiers@^1.1.2: simple-concat "^1.0.0" xtend "^4.0.1" -underscore@1.12.1: - version "1.12.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e" - integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw== - -underscore@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" - integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== +underscore@1.12.1, underscore@1.9.1, underscore@^1.12.1: + version "1.13.7" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.7.tgz#970e33963af9a7dda228f17ebe8399e5fbe63a10" + integrity sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g== undici@^5.14.0: version "5.28.5" From e7f8dff8625b398ba30c4b8aa3cfb4dfa09151d9 Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sun, 13 Apr 2025 00:11:55 +0200 Subject: [PATCH 08/21] wip --- packages/utils/src/crypto/ec-utils-legacy.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/utils/src/crypto/ec-utils-legacy.ts b/packages/utils/src/crypto/ec-utils-legacy.ts index 1635ccf7fe..f399e48502 100644 --- a/packages/utils/src/crypto/ec-utils-legacy.ts +++ b/packages/utils/src/crypto/ec-utils-legacy.ts @@ -26,8 +26,8 @@ const deriveSharedKeyWithSha512 = ( publicKey: PublicKey, padded = false, ): Uint8Array => { - const sharedPoint = secp256k1.getSharedSecret(privateKey.secret, publicKey.toBytes()).subarray(1); - const paddedBytes = padded ? sharedPoint.subarray(16, 64) : sharedPoint; + const sharedPoint = secp256k1.getSharedSecret(privateKey.secret, publicKey.toBytes()); + const paddedBytes = padded ? sharedPoint.slice(1) : sharedPoint.slice(16, 64); return new Uint8Array(sha512.create().update(paddedBytes).digest()); }; From c5c0f532a2e032dc6a06170c2af1ba9c797db8ef Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sun, 13 Apr 2025 00:34:35 +0200 Subject: [PATCH 09/21] tests green --- packages/utils/src/crypto/ec-utils-legacy.ts | 10 ++++++++-- packages/utils/test/crypto/ec-utils.test.ts | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/utils/src/crypto/ec-utils-legacy.ts b/packages/utils/src/crypto/ec-utils-legacy.ts index f399e48502..b5df54b4d4 100644 --- a/packages/utils/src/crypto/ec-utils-legacy.ts +++ b/packages/utils/src/crypto/ec-utils-legacy.ts @@ -3,6 +3,11 @@ import { secp256k1 } from '@noble/curves/secp256k1'; import { sha512 } from '@noble/hashes/sha2'; import { aes256cbc } from '@ecies/ciphers/aes'; +/** + * Decrypt the `eccrypto` way: using ECIES with AES-CDC-MAC and SHA-512 derivation. + * Migrated from https://github.com/torusresearch/eccrypto/blob/923ebc03e5be016a7ee27a04d8c3b496ee949bfa/src/index.ts#L264 + * but using `@noble/curves` instead of `elliptics` + */ export const ecDecryptLegacy = (privateKey: string, data: string, padded = false): string => { try { const { iv, ciphertext, ephemPublicKey } = legacyAes256CbcMacSplit(data); @@ -27,8 +32,9 @@ const deriveSharedKeyWithSha512 = ( padded = false, ): Uint8Array => { const sharedPoint = secp256k1.getSharedSecret(privateKey.secret, publicKey.toBytes()); - const paddedBytes = padded ? sharedPoint.slice(1) : sharedPoint.slice(16, 64); - return new Uint8Array(sha512.create().update(paddedBytes).digest()); + const paddedBytes = padded ? sharedPoint.slice(1) : sharedPoint.slice(2); + const hash = sha512.create().update(paddedBytes).digest(); + return new Uint8Array(hash); }; /** diff --git a/packages/utils/test/crypto/ec-utils.test.ts b/packages/utils/test/crypto/ec-utils.test.ts index 6d0906286b..95e49ffd80 100644 --- a/packages/utils/test/crypto/ec-utils.test.ts +++ b/packages/utils/test/crypto/ec-utils.test.ts @@ -6,8 +6,8 @@ import { getAddressFromPrivateKey, getAddressFromPublicKey, } from '../../src'; -import { eccryptoNativeData } from './data/crypto-native'; import { eccryptoBrowserData } from './data/crypto-browser'; +import { eccryptoNativeData } from './data/crypto-native'; const rawId = { address: '0x818B6337657A23F58581715Fc610577292e521D0', From ad422b8ab5d78a56aef386645adc6531be4a6404 Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sun, 13 Apr 2025 00:44:49 +0200 Subject: [PATCH 10/21] add test --- packages/utils/src/crypto/ec-utils-legacy.ts | 4 +- packages/utils/src/crypto/ec-utils.ts | 8 +- packages/utils/test/crypto/ec-utils.test.ts | 87 +++++++++++--------- 3 files changed, 54 insertions(+), 45 deletions(-) diff --git a/packages/utils/src/crypto/ec-utils-legacy.ts b/packages/utils/src/crypto/ec-utils-legacy.ts index b5df54b4d4..cf269e3c14 100644 --- a/packages/utils/src/crypto/ec-utils-legacy.ts +++ b/packages/utils/src/crypto/ec-utils-legacy.ts @@ -4,7 +4,7 @@ import { sha512 } from '@noble/hashes/sha2'; import { aes256cbc } from '@ecies/ciphers/aes'; /** - * Decrypt the `eccrypto` way: using ECIES with AES-CDC-MAC and SHA-512 derivation. + * Decrypt the `eccrypto` way: using ECIES with AES-CBC-MAC and SHA-512 derivation. * Migrated from https://github.com/torusresearch/eccrypto/blob/923ebc03e5be016a7ee27a04d8c3b496ee949bfa/src/index.ts#L264 * but using `@noble/curves` instead of `elliptics` */ @@ -38,7 +38,7 @@ const deriveSharedKeyWithSha512 = ( }; /** - * Split a legacy-encrypted string to its AES-CDC-MAC params. + * Split a legacy-encrypted string to its AES-CBC-MAC params. * See legacy way of generating an encrypted strings with the `@toruslabs/eccrypto` > `elliptic` library: * https://github.com/RequestNetwork/requestNetwork/blob/4597d373b0284787273471cf306dd9b849c9f76a/packages/utils/src/crypto/ec-utils.ts#L141 */ diff --git a/packages/utils/src/crypto/ec-utils.ts b/packages/utils/src/crypto/ec-utils.ts index 9fb3e5f1ac..f6cd7471bc 100644 --- a/packages/utils/src/crypto/ec-utils.ts +++ b/packages/utils/src/crypto/ec-utils.ts @@ -1,8 +1,6 @@ -import { ethers } from 'ethers'; - import { decrypt, ECIES_CONFIG, encrypt, PublicKey } from 'eciesjs'; import { secp256k1 } from '@noble/curves/secp256k1'; -import { computeAddress } from 'ethers/lib/utils'; +import { computeAddress, hexlify } from 'ethers/lib/utils'; import { ecDecryptLegacy } from './ec-utils-legacy'; /** @@ -34,7 +32,7 @@ function getAddressFromPrivateKey(privateKey: string): string { if (!privateKey.match(/^0x/)) { privateKey = `0x` + privateKey; } - return ethers.utils.computeAddress(ethers.utils.hexlify(privateKey)); + return computeAddress(hexlify(privateKey)); } catch (e) { if ( e.message === 'private key length is invalid' || @@ -56,7 +54,7 @@ function getAddressFromPrivateKey(privateKey: string): string { */ function getAddressFromPublicKey(publicKeyHex: string): string { try { - return ethers.utils.computeAddress(`0x${PublicKey.fromHex(publicKeyHex).toHex(true)}`); + return computeAddress(`0x${PublicKey.fromHex(publicKeyHex).toHex(true)}`); } catch (e) { if (e.code === 'INVALID_ARGUMENT' || e.message === 'second arg must be public key') { throw new Error('The public key must be a string representing 64 bytes'); diff --git a/packages/utils/test/crypto/ec-utils.test.ts b/packages/utils/test/crypto/ec-utils.test.ts index 95e49ffd80..dafed2183d 100644 --- a/packages/utils/test/crypto/ec-utils.test.ts +++ b/packages/utils/test/crypto/ec-utils.test.ts @@ -113,53 +113,64 @@ describe('Utils/EcUtils', () => { it('can decrypt', async () => { const data = ecDecrypt( rawId.privateKey, - '307bac038efaa5bf8a0ac8db53fd4de8024a0c0baf37283a9e6671589eba18edc12b3915ff0df66e6ffad862440228a65ead99e3320e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc70a', + '2ed3fe634d39892603c2d121d538ce0fdc7e80e4991858fbc816b49849041a726617c34226a7c61a9a217a077e8233812623e18dfbda0209e524751665aefe409b26117853d35ba6d00085dd368dadf44fcbf38c749b276184aa669d8db77d535b62e6cc874eec6bc004bce4f05c9f67c3', ); expect(data).toBe(anyData); }); - it('cannot decrypt data with a wrong private key', async () => { - expect(() => - ecDecrypt( - '0xaa', + describe('legacy dataset (AES-CBC-MAC)', () => { + it('can decrypt legacy format', async () => { + const data = ecDecrypt( + rawId.privateKey, '307bac038efaa5bf8a0ac8db53fd4de8024a0c0baf37283a9e6671589eba18edc12b3915ff0df66e6ffad862440228a65ead99e3320e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc70a', - ), - ).toThrow('The private key must be a string representing 32 bytes'); - }); + ); + expect(data).toBe(anyData); + }); - it('cannot decrypt data with a wrong encrypted data: public key too short', async () => { - expect(() => ecDecrypt(rawId.privateKey, 'aa')).toThrow( - 'The encrypted data is not well formatted', - ); - }); + it('cannot decrypt data with a wrong private key', async () => { + expect(() => + ecDecrypt( + '0xaa', + '307bac038efaa5bf8a0ac8db53fd4de8024a0c0baf37283a9e6671589eba18edc12b3915ff0df66e6ffad862440228a65ead99e3320e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc70a', + ), + ).toThrow('The private key must be a string representing 32 bytes'); + }); - it('cannot decrypt data with a wrong encrypted data: public key not parsable', async () => { - expect(() => - ecDecrypt( - rawId.privateKey, - 'e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc7', - ), - ).toThrow('The encrypted data is not well formatted'); - }); + it('cannot decrypt data with a wrong encrypted data: public key too short', async () => { + expect(() => ecDecrypt(rawId.privateKey, 'aa')).toThrow( + 'The encrypted data is not well formatted', + ); + }); - it('cannot decrypt data with a wrong encrypted data: bad MAC', async () => { - expect(() => - ecDecrypt( - rawId.privateKey, - '307bac038efaa5bf8a0ac8db53fd4de8024a0c0baf37283a9e6671589eba18edc12b3915ff0df66e6ffad862440228a65ead99e3320e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc7', - ), - ).toThrow('The encrypted data is not well formatted'); - }); + it('cannot decrypt data with a wrong encrypted data: public key not parsable', async () => { + expect(() => + ecDecrypt( + rawId.privateKey, + 'e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc7', + ), + ).toThrow('The encrypted data is not well formatted'); + }); + + it('cannot decrypt data with a wrong encrypted data: bad MAC', async () => { + expect(() => + ecDecrypt( + rawId.privateKey, + '307bac038efaa5bf8a0ac8db53fd4de8024a0c0baf37283a9e6671589eba18edc12b3915ff0df66e6ffad862440228a65ead99e3320e50aa90008961e3d68acc35b314e98020e3280bf4ce4258419dbb775185e60b43e7b88038a776a9322ff7cb3e886b2d92060cff2951ef3beedcc7', + ), + ).toThrow('The encrypted data is not well formatted'); + }); - it.each([ - { type: 'native', array: eccryptoNativeData }, - { type: 'browser', array: eccryptoBrowserData }, - ])('should be compatible with legacy $type implementation of eccrypto', async ({ array }) => { - for (const row of array) { - const { data, key, encrypted } = row; - const decrypted = ecDecrypt(key, encrypted); - expect(decrypted).toBe(data); - } + // test for https://github.com/RequestNetwork/requestNetwork/pull/1229 + it.each([ + { type: 'native', array: eccryptoNativeData }, + { type: 'browser', array: eccryptoBrowserData }, + ])('should be compatible with legacy $type implementation of eccrypto', async ({ array }) => { + for (const row of array) { + const { data, key, encrypted } = row; + const decrypted = ecDecrypt(key, encrypted); + expect(decrypted).toBe(data); + } + }); }); }); }); From 619c6e2864d4c54166aa2837c00e25a61bb4241d Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sun, 13 Apr 2025 00:45:49 +0200 Subject: [PATCH 11/21] remove corepack field --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index e4c6ce75a8..9f1cc06fae 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,5 @@ "semver": "https://github.com/RequestNetwork/requestNetwork/security/dependabot/197", "json-schema": "https://github.com/RequestNetwork/requestNetwork/security/dependabot/51", "json5": "https://github.com/RequestNetwork/requestNetwork/security/dependabot/165" - }, - "packageManager": "yarn@1.22.21+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72" + } } From eac9c9a1492085aa7a8aa5591e2ed09119d852d4 Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sun, 13 Apr 2025 00:49:43 +0200 Subject: [PATCH 12/21] sinplify --- packages/utils/src/crypto/ec-utils-legacy.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/utils/src/crypto/ec-utils-legacy.ts b/packages/utils/src/crypto/ec-utils-legacy.ts index cf269e3c14..c620e7c10a 100644 --- a/packages/utils/src/crypto/ec-utils-legacy.ts +++ b/packages/utils/src/crypto/ec-utils-legacy.ts @@ -43,7 +43,7 @@ const deriveSharedKeyWithSha512 = ( * https://github.com/RequestNetwork/requestNetwork/blob/4597d373b0284787273471cf306dd9b849c9f76a/packages/utils/src/crypto/ec-utils.ts#L141 */ const legacyAes256CbcMacSplit = (str: string) => { - const buf = Buffer.from(str, 'hex'); + const buffer = Buffer.from(str, 'hex'); const ivSize = 16; const ephemPublicKeySize = 33; @@ -51,13 +51,13 @@ const legacyAes256CbcMacSplit = (str: string) => { const macSize = 32; const macEnd = ephemPublicKeyEnd + macSize; - const ephemPublicKeyStr = buf.subarray(ivSize, ephemPublicKeyEnd); + const ephemPublicKeyStr = buffer.subarray(ivSize, ephemPublicKeyEnd); const ephemPublicKey = new PublicKey(ephemPublicKeyStr); return { - iv: Buffer.from(buf.toString('hex', 0, ivSize), 'hex'), - mac: Buffer.from(buf.toString('hex', ephemPublicKeyEnd, macEnd), 'hex'), - ciphertext: Buffer.from(buf.toString('hex', macEnd, buf.length), 'hex'), + iv: buffer.slice(0, ivSize), + mac: buffer.slice(ephemPublicKeyEnd, macEnd), + ciphertext: buffer.slice(macEnd), ephemPublicKey, }; }; From 49f8b06641a3aa1f7f76fd86375acb74cdbc8f94 Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sun, 13 Apr 2025 00:53:48 +0200 Subject: [PATCH 13/21] remove slice --- packages/utils/src/crypto/ec-utils-legacy.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/utils/src/crypto/ec-utils-legacy.ts b/packages/utils/src/crypto/ec-utils-legacy.ts index c620e7c10a..6cda395f43 100644 --- a/packages/utils/src/crypto/ec-utils-legacy.ts +++ b/packages/utils/src/crypto/ec-utils-legacy.ts @@ -13,7 +13,7 @@ export const ecDecryptLegacy = (privateKey: string, data: string, padded = false const { iv, ciphertext, ephemPublicKey } = legacyAes256CbcMacSplit(data); const receiverPrivateKey = PrivateKey.fromHex(privateKey.replace(/^0x/, '')); const sharedKey = deriveSharedKeyWithSha512(receiverPrivateKey, ephemPublicKey, padded); - const decrypted = aes256cbc(sharedKey.slice(0, 32), iv).decrypt(ciphertext); + const decrypted = aes256cbc(sharedKey.subarray(0, 32), iv).decrypt(ciphertext); return Buffer.from(decrypted).toString(); } catch (e) { if (e.message === 'error:1C80006B:Provider routines::wrong final block length') { @@ -32,7 +32,7 @@ const deriveSharedKeyWithSha512 = ( padded = false, ): Uint8Array => { const sharedPoint = secp256k1.getSharedSecret(privateKey.secret, publicKey.toBytes()); - const paddedBytes = padded ? sharedPoint.slice(1) : sharedPoint.slice(2); + const paddedBytes = padded ? sharedPoint.subarray(1) : sharedPoint.subarray(2); const hash = sha512.create().update(paddedBytes).digest(); return new Uint8Array(hash); }; @@ -55,9 +55,9 @@ const legacyAes256CbcMacSplit = (str: string) => { const ephemPublicKey = new PublicKey(ephemPublicKeyStr); return { - iv: buffer.slice(0, ivSize), - mac: buffer.slice(ephemPublicKeyEnd, macEnd), - ciphertext: buffer.slice(macEnd), + iv: buffer.subarray(0, ivSize), + mac: buffer.subarray(ephemPublicKeyEnd, macEnd), + ciphertext: buffer.subarray(macEnd), ephemPublicKey, }; }; From ffbdcc8c7cae9d6a38ddd9a4da25a23a3f71d376 Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sun, 13 Apr 2025 02:16:59 +0200 Subject: [PATCH 14/21] tests green --- packages/utils/src/crypto/ec-utils-legacy.ts | 52 +++++++++++++------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/packages/utils/src/crypto/ec-utils-legacy.ts b/packages/utils/src/crypto/ec-utils-legacy.ts index 6cda395f43..10b0730f8a 100644 --- a/packages/utils/src/crypto/ec-utils-legacy.ts +++ b/packages/utils/src/crypto/ec-utils-legacy.ts @@ -1,38 +1,56 @@ import { PrivateKey, PublicKey } from 'eciesjs'; import { secp256k1 } from '@noble/curves/secp256k1'; -import { sha512 } from '@noble/hashes/sha2'; +import { sha256, sha512 } from '@noble/hashes/sha2'; import { aes256cbc } from '@ecies/ciphers/aes'; +import { hmac } from '@noble/hashes/hmac'; /** * Decrypt the `eccrypto` way: using ECIES with AES-CBC-MAC and SHA-512 derivation. * Migrated from https://github.com/torusresearch/eccrypto/blob/923ebc03e5be016a7ee27a04d8c3b496ee949bfa/src/index.ts#L264 * but using `@noble/curves` instead of `elliptics` */ -export const ecDecryptLegacy = (privateKey: string, data: string, padded = false): string => { - try { - const { iv, ciphertext, ephemPublicKey } = legacyAes256CbcMacSplit(data); - const receiverPrivateKey = PrivateKey.fromHex(privateKey.replace(/^0x/, '')); - const sharedKey = deriveSharedKeyWithSha512(receiverPrivateKey, ephemPublicKey, padded); - const decrypted = aes256cbc(sharedKey.subarray(0, 32), iv).decrypt(ciphertext); - return Buffer.from(decrypted).toString(); - } catch (e) { - if (e.message === 'error:1C80006B:Provider routines::wrong final block length') { - throw new Error('The encrypted data is not well formatted'); - } - if (e.message === 'error:1C800064:Provider routines::bad decrypt' && !padded) { +export const ecDecryptLegacy = (privateKey: string, data: string, padding = false): string => { + const { iv, ephemPublicKey, mac, ciphertext } = legacyAes256CbcMacSplit(data); + const receiverPrivateKey = PrivateKey.fromHex(privateKey.replace(/^0x/, '')); + const sharedKey = deriveSharedKeyWithSha512(receiverPrivateKey, ephemPublicKey, padding); + const encryptionKey = sharedKey.subarray(0, 32); + const macKey = sharedKey.subarray(32); + const dataToMac = Buffer.concat([iv, ephemPublicKey.toBytes(false), ciphertext]); + const macGood = hmacSha256Verify(macKey, dataToMac, mac); + if (!macGood) { + if (!padding) { return ecDecryptLegacy(privateKey, data, true); } - throw e; + throw new Error('The encrypted data is not well formatted'); } + const decrypted = aes256cbc(encryptionKey, iv).decrypt(ciphertext); + return Buffer.from(decrypted).toString(); +}; + +const hmacSha256Verify = (key: Uint8Array, msg: Uint8Array, sig: Uint8Array): boolean => { + const expectedSig = hmac(sha256, key, msg); + return equalConstTime(expectedSig, sig); +}; + +// Compare two buffers in constant time to prevent timing attacks. +const equalConstTime = (b1: Uint8Array, b2: Uint8Array): boolean => { + if (b1.length !== b2.length) { + return false; + } + let res = 0; + for (let i = 0; i < b1.length; i++) { + res |= b1[i] ^ b2[i]; + } + return res === 0; }; const deriveSharedKeyWithSha512 = ( privateKey: PrivateKey, publicKey: PublicKey, - padded = false, + padding = false, ): Uint8Array => { const sharedPoint = secp256k1.getSharedSecret(privateKey.secret, publicKey.toBytes()); - const paddedBytes = padded ? sharedPoint.subarray(1) : sharedPoint.subarray(2); + const paddedBytes = padding ? sharedPoint.subarray(1) : sharedPoint.subarray(2); const hash = sha512.create().update(paddedBytes).digest(); return new Uint8Array(hash); }; @@ -56,8 +74,8 @@ const legacyAes256CbcMacSplit = (str: string) => { return { iv: buffer.subarray(0, ivSize), + ephemPublicKey, mac: buffer.subarray(ephemPublicKeyEnd, macEnd), ciphertext: buffer.subarray(macEnd), - ephemPublicKey, }; }; From 89d47985f0aa7f8979157dc17500edd5b3980276 Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sun, 13 Apr 2025 03:15:36 +0200 Subject: [PATCH 15/21] fix parity --- packages/utils/src/crypto/ec-utils.ts | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/utils/src/crypto/ec-utils.ts b/packages/utils/src/crypto/ec-utils.ts index f6cd7471bc..e0836d7fac 100644 --- a/packages/utils/src/crypto/ec-utils.ts +++ b/packages/utils/src/crypto/ec-utils.ts @@ -67,15 +67,16 @@ function getAddressFromPublicKey(publicKeyHex: string): string { * Function ecSign data with ECDSA * * @param privateKey the private key used to sign the message - * @param dataHash the data to sign + * @param data the data to sign * * @returns the signature */ -function ecSign(privateKey: string, dataHash: string): string { +function ecSign(privateKey: string, data: string): string { try { - privateKey = privateKey.replace(/^0x/, ''); - dataHash = dataHash.replace(/^0x/, ''); - return `0x${secp256k1.sign(dataHash, privateKey).toCompactHex()}1b`; + const privateKeyHex = privateKey.replace(/^0x/, ''); + const dataHex = data.replace(/^0x/, ''); + const signature = secp256k1.sign(dataHex, privateKeyHex); + return `0x${signature.toCompactHex()}${signature.recovery ? '1c' : '1b'}`; } catch (e) { if (e.message === 'invalid private key, expected hex or 32 bytes, got string') { throw new Error('The private key must be a string representing 32 bytes'); @@ -87,23 +88,23 @@ function ecSign(privateKey: string, dataHash: string): string { /** * Function to recover address from a signature * - * @param signatureHex the signature - * @param dataHash the data signed + * @param signature the signature + * @param data the data signed * * @returns the address */ -function ecRecover(signatureHex: string, dataHash: string): string { +function ecRecover(signature: string, data: string): string { try { - signatureHex = signatureHex.replace(/^0x/, ''); - dataHash = dataHash.replace(/^0x/, ''); + const signatureHex = signature.replace(/^0x/, ''); + data = data.replace(/^0x/, ''); const sigOnly = signatureHex.substring(0, signatureHex.length - 2); // all but last 2 chars const vValue = signatureHex.slice(-2); // last 2 chars const recoveryNumber = vValue === '1c' ? 1 : 0; - const signature = secp256k1.Signature.fromCompact(sigOnly); - const signatureRecover = signature.addRecoveryBit(recoveryNumber); - return computeAddress(`0x${signatureRecover.recoverPublicKey(dataHash).toHex()}`); + const signatureObj = secp256k1.Signature.fromCompact(sigOnly); + const signatureRecover = signatureObj.addRecoveryBit(recoveryNumber); + return computeAddress(`0x${signatureRecover.recoverPublicKey(data).toHex()}`); } catch (e) { if (e.message === 'compactSignature of length 64 expected, got 0') { throw new Error('The signature must be a string representing 66 bytes'); From 9f5d95eef8c654dea3ea68a09ccad86ffd9b120f Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sun, 13 Apr 2025 03:22:37 +0200 Subject: [PATCH 16/21] simplify sign and recover --- packages/utils/src/crypto/ec-utils.ts | 30 +++++++++++---------------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/packages/utils/src/crypto/ec-utils.ts b/packages/utils/src/crypto/ec-utils.ts index e0836d7fac..0fb27b4f46 100644 --- a/packages/utils/src/crypto/ec-utils.ts +++ b/packages/utils/src/crypto/ec-utils.ts @@ -1,6 +1,11 @@ import { decrypt, ECIES_CONFIG, encrypt, PublicKey } from 'eciesjs'; -import { secp256k1 } from '@noble/curves/secp256k1'; -import { computeAddress, hexlify } from 'ethers/lib/utils'; +import { + computeAddress, + hexlify, + joinSignature, + recoverPublicKey, + SigningKey, +} from 'ethers/lib/utils'; import { ecDecryptLegacy } from './ec-utils-legacy'; /** @@ -73,12 +78,10 @@ function getAddressFromPublicKey(publicKeyHex: string): string { */ function ecSign(privateKey: string, data: string): string { try { - const privateKeyHex = privateKey.replace(/^0x/, ''); - const dataHex = data.replace(/^0x/, ''); - const signature = secp256k1.sign(dataHex, privateKeyHex); - return `0x${signature.toCompactHex()}${signature.recovery ? '1c' : '1b'}`; + const signingKey = new SigningKey(privateKey); + return joinSignature(signingKey.signDigest(data)); } catch (e) { - if (e.message === 'invalid private key, expected hex or 32 bytes, got string') { + if (e.code === 'INVALID_ARGUMENT') { throw new Error('The private key must be a string representing 32 bytes'); } throw e; @@ -95,18 +98,9 @@ function ecSign(privateKey: string, data: string): string { */ function ecRecover(signature: string, data: string): string { try { - const signatureHex = signature.replace(/^0x/, ''); - data = data.replace(/^0x/, ''); - - const sigOnly = signatureHex.substring(0, signatureHex.length - 2); // all but last 2 chars - const vValue = signatureHex.slice(-2); // last 2 chars - const recoveryNumber = vValue === '1c' ? 1 : 0; - - const signatureObj = secp256k1.Signature.fromCompact(sigOnly); - const signatureRecover = signatureObj.addRecoveryBit(recoveryNumber); - return computeAddress(`0x${signatureRecover.recoverPublicKey(data).toHex()}`); + return computeAddress(recoverPublicKey(data, signature)); } catch (e) { - if (e.message === 'compactSignature of length 64 expected, got 0') { + if (e.code === 'INVALID_ARGUMENT') { throw new Error('The signature must be a string representing 66 bytes'); } throw e; From b9023ba34e16c3eca301aa4a6153fae384172f9b Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sun, 13 Apr 2025 03:23:58 +0200 Subject: [PATCH 17/21] undo arg name change --- packages/utils/src/crypto/ec-utils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/utils/src/crypto/ec-utils.ts b/packages/utils/src/crypto/ec-utils.ts index 0fb27b4f46..94266feb64 100644 --- a/packages/utils/src/crypto/ec-utils.ts +++ b/packages/utils/src/crypto/ec-utils.ts @@ -53,13 +53,13 @@ function getAddressFromPrivateKey(privateKey: string): string { /** * Function to derive the address from an EC public key * - * @param publicKeyHex the public key to derive + * @param publicKey the public key to derive * * @returns the address */ -function getAddressFromPublicKey(publicKeyHex: string): string { +function getAddressFromPublicKey(publicKey: string): string { try { - return computeAddress(`0x${PublicKey.fromHex(publicKeyHex).toHex(true)}`); + return computeAddress(`0x${PublicKey.fromHex(publicKey).toHex(true)}`); } catch (e) { if (e.code === 'INVALID_ARGUMENT' || e.message === 'second arg must be public key') { throw new Error('The public key must be a string representing 64 bytes'); From 298dbd5bc311b6c3f5cd5f066f6df63c0aa76c76 Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sun, 13 Apr 2025 04:04:18 +0200 Subject: [PATCH 18/21] rename args --- packages/utils/src/crypto.ts | 2 -- packages/utils/src/crypto/ec-utils-legacy.ts | 12 ++++++------ packages/utils/src/crypto/ec-utils.ts | 18 +++++++++--------- packages/utils/src/index.ts | 1 - packages/utils/test/crypto/ec-utils.test.ts | 18 +++++++++++++++--- 5 files changed, 30 insertions(+), 21 deletions(-) diff --git a/packages/utils/src/crypto.ts b/packages/utils/src/crypto.ts index 0c2da882b7..e230eb0b60 100644 --- a/packages/utils/src/crypto.ts +++ b/packages/utils/src/crypto.ts @@ -15,7 +15,6 @@ import { getAddressFromPrivateKey, getAddressFromPublicKey, } from './crypto/ec-utils'; -import { ecDecryptLegacy } from './crypto/ec-utils-legacy'; import { deepSort } from './utils'; /** @@ -28,7 +27,6 @@ export { encryptWithAes256gcm, random32Bytes, ecDecrypt, - ecDecryptLegacy, ecEncrypt, getAddressFromPrivateKey, getAddressFromPublicKey, diff --git a/packages/utils/src/crypto/ec-utils-legacy.ts b/packages/utils/src/crypto/ec-utils-legacy.ts index 10b0730f8a..2bcec8e0c9 100644 --- a/packages/utils/src/crypto/ec-utils-legacy.ts +++ b/packages/utils/src/crypto/ec-utils-legacy.ts @@ -9,8 +9,8 @@ import { hmac } from '@noble/hashes/hmac'; * Migrated from https://github.com/torusresearch/eccrypto/blob/923ebc03e5be016a7ee27a04d8c3b496ee949bfa/src/index.ts#L264 * but using `@noble/curves` instead of `elliptics` */ -export const ecDecryptLegacy = (privateKey: string, data: string, padding = false): string => { - const { iv, ephemPublicKey, mac, ciphertext } = legacyAes256CbcMacSplit(data); +export const ecDecryptLegacy = (privateKey: string, dataHex: string, padding = false): string => { + const { iv, ephemPublicKey, mac, ciphertext } = legacyAes256CbcMacSplit(dataHex); const receiverPrivateKey = PrivateKey.fromHex(privateKey.replace(/^0x/, '')); const sharedKey = deriveSharedKeyWithSha512(receiverPrivateKey, ephemPublicKey, padding); const encryptionKey = sharedKey.subarray(0, 32); @@ -19,7 +19,7 @@ export const ecDecryptLegacy = (privateKey: string, data: string, padding = fals const macGood = hmacSha256Verify(macKey, dataToMac, mac); if (!macGood) { if (!padding) { - return ecDecryptLegacy(privateKey, data, true); + return ecDecryptLegacy(privateKey, dataHex, true); } throw new Error('The encrypted data is not well formatted'); } @@ -56,12 +56,12 @@ const deriveSharedKeyWithSha512 = ( }; /** - * Split a legacy-encrypted string to its AES-CBC-MAC params. + * Split a legacy-encrypted hex string to its AES-CBC-MAC params. * See legacy way of generating an encrypted strings with the `@toruslabs/eccrypto` > `elliptic` library: * https://github.com/RequestNetwork/requestNetwork/blob/4597d373b0284787273471cf306dd9b849c9f76a/packages/utils/src/crypto/ec-utils.ts#L141 */ -const legacyAes256CbcMacSplit = (str: string) => { - const buffer = Buffer.from(str, 'hex'); +const legacyAes256CbcMacSplit = (dataHex: string) => { + const buffer = Buffer.from(dataHex, 'hex'); const ivSize = 16; const ephemPublicKeySize = 33; diff --git a/packages/utils/src/crypto/ec-utils.ts b/packages/utils/src/crypto/ec-utils.ts index 94266feb64..a4a2d620f7 100644 --- a/packages/utils/src/crypto/ec-utils.ts +++ b/packages/utils/src/crypto/ec-utils.ts @@ -59,7 +59,8 @@ function getAddressFromPrivateKey(privateKey: string): string { */ function getAddressFromPublicKey(publicKey: string): string { try { - return computeAddress(`0x${PublicKey.fromHex(publicKey).toHex(true)}`); + const compressedKey = PublicKey.fromHex(publicKey).toHex(true); + return computeAddress(`0x${compressedKey}`); } catch (e) { if (e.code === 'INVALID_ARGUMENT' || e.message === 'second arg must be public key') { throw new Error('The public key must be a string representing 64 bytes'); @@ -113,11 +114,11 @@ function ecRecover(signature: string, data: string): string { * @param publicKey the public key to encrypt with * @param data the data to encrypt * - * @returns the encrypted data + * @returns the encrypted data as a hex string */ function ecEncrypt(publicKey: string, data: string): string { try { - return encrypt(publicKey, Buffer.from(data)).toString('hex').slice(2); + return encrypt(publicKey, Buffer.from(data)).toString('hex'); } catch (e) { if (e.message === 'second arg must be public key') { throw new Error('The public key must be a string representing 64 bytes'); @@ -130,17 +131,16 @@ function ecEncrypt(publicKey: string, data: string): string { * Function to decrypt data with a public key * * @param privateKey the private key to decrypt with - * @param data the data to decrypt + * @param dataHex the hex data to decrypt * * @returns the decrypted data */ -function ecDecrypt(privateKey: string, data: string): string { +function ecDecrypt(privateKey: string, dataHex: string): string { try { - const paddedData = data.startsWith('04') ? data : `04${data}`; - return decrypt(privateKey.replace(/^0x/, ''), Buffer.from(paddedData, 'hex')).toString(); + return decrypt(privateKey.replace(/^0x/, ''), Buffer.from(dataHex, 'hex')).toString(); } catch (e) { - if (e.message === 'bad point: equation left != right') { - return ecDecryptLegacy(privateKey, data); + if (e.message.startsWith('invalid Point')) { + return ecDecryptLegacy(privateKey, dataHex); } if (e.message === 'Invalid private key') { throw new Error('The private key must be a string representing 32 bytes'); diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index ecb9d5d613..009900ae71 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -15,7 +15,6 @@ export { encryptWithAes256gcm, random32Bytes, ecDecrypt, - ecDecryptLegacy, ecEncrypt, getAddressFromPrivateKey, getAddressFromPublicKey, diff --git a/packages/utils/test/crypto/ec-utils.test.ts b/packages/utils/test/crypto/ec-utils.test.ts index dafed2183d..958105b410 100644 --- a/packages/utils/test/crypto/ec-utils.test.ts +++ b/packages/utils/test/crypto/ec-utils.test.ts @@ -1,3 +1,4 @@ +import { randomBytes } from '@noble/hashes/utils'; import { ecDecrypt, ecEncrypt, @@ -8,6 +9,7 @@ import { } from '../../src'; import { eccryptoBrowserData } from './data/crypto-browser'; import { eccryptoNativeData } from './data/crypto-native'; +import { PrivateKey } from 'eciesjs'; const rawId = { address: '0x818B6337657A23F58581715Fc610577292e521D0', @@ -90,7 +92,7 @@ describe('Utils/EcUtils', () => { describe('encrypt', () => { it('can encrypt', async () => { const encryptedData = ecEncrypt(rawId.publicKey, anyData); - expect(encryptedData.length).toBe(226); + expect(encryptedData.length).toBe(228); expect(ecDecrypt(rawId.privateKey, encryptedData)).toBe(anyData); }); @@ -99,7 +101,7 @@ describe('Utils/EcUtils', () => { '0396212fc129c2f78771218b2e93da7a5aac63490a42bb41b97848c39c14fe65cd', anyData, ); - expect(encryptedData.length).toBe(226); + expect(encryptedData.length).toBe(228); }); it('cannot encrypt data with a wrong public key', async () => { @@ -113,11 +115,21 @@ describe('Utils/EcUtils', () => { it('can decrypt', async () => { const data = ecDecrypt( rawId.privateKey, - '2ed3fe634d39892603c2d121d538ce0fdc7e80e4991858fbc816b49849041a726617c34226a7c61a9a217a077e8233812623e18dfbda0209e524751665aefe409b26117853d35ba6d00085dd368dadf44fcbf38c749b276184aa669d8db77d535b62e6cc874eec6bc004bce4f05c9f67c3', + '04f5ef23cfd828b7910d7c909eef047729b0cb986ebf4ba12ce877ec455863c6b9350e06f3f51479fa6b0a3feeb4c9f6fa808d4e6393d570627636642df35b1f85d59bb5bd78fdbaacaaa557c7d472ff7c5bbf8d8df59c0bd5d856831f1c0bcb77ad55bd82149a3bcb729f534fcdb62efa64', ); expect(data).toBe(anyData); }); + it('can decrypt random data', async () => { + for (let i = 0; i < 10; i++) { + const privateKey = new PrivateKey(); + const data = Buffer.from(randomBytes(32)).toString('hex'); + const encrypted = ecEncrypt(privateKey.publicKey.toHex(Math.random() >= 0.5), data); + const decrypted = ecDecrypt(privateKey.secret.toString('hex'), encrypted); + expect(decrypted).toBe(data); + } + }); + describe('legacy dataset (AES-CBC-MAC)', () => { it('can decrypt legacy format', async () => { const data = ecDecrypt( From c07908d481322894fd0f890b5fa1349cf139d12e Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sun, 13 Apr 2025 05:27:25 +0200 Subject: [PATCH 19/21] update dotenv --- packages/request-node/package.json | 2 +- packages/smart-contracts/package.json | 2 +- yarn.lock | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/request-node/package.json b/packages/request-node/package.json index 214f63dbad..5126fe9c12 100644 --- a/packages/request-node/package.json +++ b/packages/request-node/package.json @@ -56,7 +56,7 @@ "@requestnetwork/utils": "0.54.0", "chalk": "4.1.0", "cors": "2.8.5", - "dotenv": "8.2.0", + "dotenv": "16.5.0", "ethers": "5.7.2", "express": "4.21.0", "graphql": "16.8.1", diff --git a/packages/smart-contracts/package.json b/packages/smart-contracts/package.json index fb90e4d163..72d33bf0b0 100644 --- a/packages/smart-contracts/package.json +++ b/packages/smart-contracts/package.json @@ -78,7 +78,7 @@ "@types/mocha": "8.2.3", "@types/node": "18.11.9", "chai": "4.3.4", - "dotenv": "10.0.0", + "dotenv": "16.5.0", "ethereum-waffle": "3.4.4", "ethers": "5.7.2", "ganache-cli": "6.12.0", diff --git a/yarn.lock b/yarn.lock index 7b70a9adcd..d4169f665f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12006,15 +12006,10 @@ dot@^1.1.3: resolved "https://registry.npmjs.org/dot/-/dot-1.1.3.tgz" integrity sha512-/nt74Rm+PcfnirXGEdhZleTwGC2LMnuKTeeTIlI82xb5loBBoXNYzr2ezCroPSMtilK8EZIfcNZwOcHN+ib1Lg== -dotenv@10.0.0, dotenv@~10.0.0: - version "10.0.0" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz" - integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== - -dotenv@8.2.0: - version "8.2.0" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz" - integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== +dotenv@16.5.0: + version "16.5.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.5.0.tgz#092b49f25f808f020050051d1ff258e404c78692" + integrity sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg== dotenv@^16.0.0: version "16.3.1" @@ -12026,6 +12021,11 @@ dotenv@^16.4.5: resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz" integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== +dotenv@~10.0.0: + version "10.0.0" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== + dotignore@~0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz" From b56af8cc5947092e22b4b1a2ddd00738719f3863 Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sun, 13 Apr 2025 05:46:40 +0200 Subject: [PATCH 20/21] fix build issues --- packages/payment-detection/src/thegraph/client.ts | 5 +++-- packages/payment-detection/src/thegraph/superfluid.ts | 2 +- packages/thegraph-data-access/package.json | 2 +- packages/thegraph-data-access/src/subgraph-client.ts | 6 +++--- packages/thegraph-data-access/src/types.ts | 4 +++- yarn.lock | 7 ------- 6 files changed, 11 insertions(+), 15 deletions(-) diff --git a/packages/payment-detection/src/thegraph/client.ts b/packages/payment-detection/src/thegraph/client.ts index 7b9d9b1968..3654c40ccd 100644 --- a/packages/payment-detection/src/thegraph/client.ts +++ b/packages/payment-detection/src/thegraph/client.ts @@ -2,9 +2,8 @@ import { CurrencyTypes } from '@requestnetwork/types'; import { NearChains } from '@requestnetwork/currency'; import { GraphQLClient } from 'graphql-request'; -import { Block_Height, Maybe, getSdk } from './generated/graphql'; +import { Block_Height, getSdk, Maybe } from './generated/graphql'; import { getSdk as getNearSdk } from './generated/graphql-near'; -import { RequestConfig } from 'graphql-request/src/types'; const THE_GRAPH_STUDIO_URL = 'https://api.studio.thegraph.com/query/67444/request-payments-$NETWORK/version/latest'; @@ -41,6 +40,8 @@ export type TheGraphQueryOptions = { blockFilter?: Maybe; }; +type RequestConfig = (typeof GraphQLClient.prototype)['requestConfig']; + export type TheGraphClientOptions = RequestConfig & { /** constraint to select indexers that have at least parsed this block */ minIndexedBlock?: number | undefined; diff --git a/packages/payment-detection/src/thegraph/superfluid.ts b/packages/payment-detection/src/thegraph/superfluid.ts index 941d2bc2b8..fae40e9b0c 100644 --- a/packages/payment-detection/src/thegraph/superfluid.ts +++ b/packages/payment-detection/src/thegraph/superfluid.ts @@ -1,6 +1,5 @@ import { GraphQLClient } from 'graphql-request'; import { getSdk } from './generated/graphql-superfluid'; -import { RequestConfig } from 'graphql-request/src/types'; const BASE_URL = `https://subgraph-endpoints.superfluid.dev`; const NETWORK_TO_URL: Record = { @@ -22,6 +21,7 @@ const NETWORK_TO_URL: Record = { /** * A GraphQL client to query Superfluid's subgraph. */ +type RequestConfig = (typeof GraphQLClient.prototype)['requestConfig']; export type TheGraphSuperfluidClient = ReturnType; export type TheGraphClientOptions = RequestConfig & { baseUrl?: string; diff --git a/packages/thegraph-data-access/package.json b/packages/thegraph-data-access/package.json index 79a5c2c415..8d740665fe 100644 --- a/packages/thegraph-data-access/package.json +++ b/packages/thegraph-data-access/package.json @@ -45,7 +45,7 @@ "@requestnetwork/types": "0.54.0", "@requestnetwork/utils": "0.54.0", "ethers": "5.7.2", - "graphql-request": "7.1.2", + "graphql-request": "6.1.0", "tslib": "2.5.0" }, "devDependencies": { diff --git a/packages/thegraph-data-access/src/subgraph-client.ts b/packages/thegraph-data-access/src/subgraph-client.ts index 322542153b..937fe16dbf 100644 --- a/packages/thegraph-data-access/src/subgraph-client.ts +++ b/packages/thegraph-data-access/src/subgraph-client.ts @@ -1,5 +1,5 @@ import { DataAccessTypes, StorageTypes } from '@requestnetwork/types'; -import { GraphQLClient } from 'graphql-request'; +import { GraphQLClient, Variables } from 'graphql-request'; import { GetBlockQuery, GetTransactionByDataHashQuery, @@ -10,12 +10,12 @@ import { Transaction, TransactionsBody, } from './queries'; -import { Variables } from 'graphql-request/build/cjs/types'; -import { RequestConfig } from 'graphql-request/build/legacy/helpers/types'; // Max Int value (as supported by grapqhl types) const MAX_INT_VALUE = 0x7fffffff; +type RequestConfig = (typeof GraphQLClient.prototype)['requestConfig']; + type ClientConfig = Omit & { headers?: Record }; export class SubgraphClient implements StorageTypes.IIndexer { diff --git a/packages/thegraph-data-access/src/types.ts b/packages/thegraph-data-access/src/types.ts index ffe0828a62..8bf0c32845 100644 --- a/packages/thegraph-data-access/src/types.ts +++ b/packages/thegraph-data-access/src/types.ts @@ -1,6 +1,8 @@ import { StorageTypes } from '@requestnetwork/types'; import { DataAccessBaseOptions } from '@requestnetwork/data-access'; -import { RequestConfig } from 'graphql-request/build/legacy/helpers/types'; +import { GraphQLClient } from 'graphql-request'; + +type RequestConfig = (typeof GraphQLClient.prototype)['requestConfig']; export type TheGraphDataAccessOptions = DataAccessBaseOptions & { graphql: { url: string } & Omit & { headers?: Record }; diff --git a/yarn.lock b/yarn.lock index d4169f665f..c09358e473 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15181,13 +15181,6 @@ graphql-request@6.1.0, graphql-request@^6.0.0: "@graphql-typed-document-node/core" "^3.2.0" cross-fetch "^3.1.5" -graphql-request@7.1.2: - version "7.1.2" - resolved "https://registry.npmjs.org/graphql-request/-/graphql-request-7.1.2.tgz" - integrity sha512-+XE3iuC55C2di5ZUrB4pjgwe+nIQBuXVIK9J98wrVwojzDW3GMdSBZfxUk8l4j9TieIpjpggclxhNEU9ebGF8w== - dependencies: - "@graphql-typed-document-node/core" "^3.2.0" - graphql-request@^4.3.0: version "4.3.0" resolved "https://registry.npmjs.org/graphql-request/-/graphql-request-4.3.0.tgz" From 84aab77bf4ca53914fad627bb18bdaac4e678e27 Mon Sep 17 00:00:00 2001 From: Alexandre ABRIOUX Date: Sun, 13 Apr 2025 14:13:23 +0200 Subject: [PATCH 21/21] update @graphql-codegen/typescript-graphql-request --- package.json | 3 ++- packages/payment-detection/package.json | 2 +- yarn.lock | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 9f1cc06fae..e4c6ce75a8 100644 --- a/package.json +++ b/package.json @@ -69,5 +69,6 @@ "semver": "https://github.com/RequestNetwork/requestNetwork/security/dependabot/197", "json-schema": "https://github.com/RequestNetwork/requestNetwork/security/dependabot/51", "json5": "https://github.com/RequestNetwork/requestNetwork/security/dependabot/165" - } + }, + "packageManager": "yarn@1.22.21+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72" } diff --git a/packages/payment-detection/package.json b/packages/payment-detection/package.json index d26cdb9215..1a2e7526ea 100644 --- a/packages/payment-detection/package.json +++ b/packages/payment-detection/package.json @@ -57,7 +57,7 @@ "@graphql-codegen/cli": "4.0.1", "@graphql-codegen/typescript": "4.0.1", "@graphql-codegen/typescript-document-nodes": "4.0.1", - "@graphql-codegen/typescript-graphql-request": "6.0.1", + "@graphql-codegen/typescript-graphql-request": "6.2.0", "@graphql-codegen/typescript-operations": "4.0.1", "@graphql-codegen/typescript-resolvers": "4.0.1", "@jridgewell/gen-mapping": "0.3.2", diff --git a/yarn.lock b/yarn.lock index c09358e473..fd0c149136 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3416,10 +3416,10 @@ auto-bind "~4.0.0" tslib "~2.5.0" -"@graphql-codegen/typescript-graphql-request@6.0.1": - version "6.0.1" - resolved "https://registry.npmjs.org/@graphql-codegen/typescript-graphql-request/-/typescript-graphql-request-6.0.1.tgz" - integrity sha512-aScw7ICyscW7bYLh2HyjQU3geCAjvFy6sRIlzgdkeFvcKBdjCil69upkyZAyntnSno2C4ZoUv7sHOpyQ9hQmFQ== +"@graphql-codegen/typescript-graphql-request@6.2.0": + version "6.2.0" + resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-graphql-request/-/typescript-graphql-request-6.2.0.tgz#db3bd90cd9070d446b8039384476cc1029929617" + integrity sha512-nkp5tr4PrC/+2QkQqi+IB+bc7AavUnUvXPW8MC93HZRvwfMGy6m2Oo7b9JCPZ3vhNpqT2VDWOn/zIZXKz6zJAw== dependencies: "@graphql-codegen/plugin-helpers" "^3.0.0" "@graphql-codegen/visitor-plugin-common" "2.13.1" @@ -3428,7 +3428,7 @@ "@graphql-codegen/typescript-operations@4.0.1": version "4.0.1" - resolved "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-4.0.1.tgz" + resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-operations/-/typescript-operations-4.0.1.tgz#930af3e2d2ae8ff06de696291be28fe7046a2fef" integrity sha512-GpUWWdBVUec/Zqo23aFLBMrXYxN2irypHqDcKjN78JclDPdreasAEPcIpMfqf4MClvpmvDLy4ql+djVAwmkjbw== dependencies: "@graphql-codegen/plugin-helpers" "^5.0.0"