From b40aad4c016dc5a10908cea71597cbbf19110c15 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Thu, 10 Aug 2023 18:58:46 -0400 Subject: [PATCH 1/4] add option to use DEK in loadtest --- .../phone-number-privacy/monitor/src/query.ts | 29 ++++++--- .../monitor/src/resources.ts | 63 +++++++++++++++++++ .../monitor/src/scripts/run-load-test.ts | 17 +++-- .../phone-number-privacy/monitor/src/test.ts | 24 +++++-- 4 files changed, 115 insertions(+), 18 deletions(-) create mode 100644 packages/phone-number-privacy/monitor/src/resources.ts diff --git a/packages/phone-number-privacy/monitor/src/query.ts b/packages/phone-number-privacy/monitor/src/query.ts index 6879b12d0c1..33a0c23e4bf 100644 --- a/packages/phone-number-privacy/monitor/src/query.ts +++ b/packages/phone-number-privacy/monitor/src/query.ts @@ -18,6 +18,7 @@ import { genSessionID } from '@celo/phone-number-privacy-common/lib/utils/logger import { normalizeAddressWith0x, privateKeyToAddress } from '@celo/utils/lib/address' import { defined } from '@celo/utils/lib/sign-typed-data-utils' import { LocalWallet } from '@celo/wallet-local' +import { ACCOUNT_ADDRESS, dekAuthSigner, PRIVATE_KEY } from './resources' const phoneNumber = fetchEnv('PHONE_NUMBER') @@ -30,21 +31,33 @@ export const queryOdisForSalt = async ( blockchainProvider: string, contextName: OdisContextName, timeoutMs: number = 10000, - bypassQuota: boolean = false + bypassQuota: boolean = false, + useDEK: boolean = false ) => { + let authSigner: AuthSigner + let accountAddress: string console.log(`contextName: ${contextName}`) // tslint:disable-line:no-console console.log(`blockchain provider: ${blockchainProvider}`) // tslint:disable-line:no-console + console.log(`using DEK: ${useDEK}`) // tslint:disable-line:no-console const serviceContext = getServiceContext(contextName, OdisAPI.PNP) const contractKit = newKit(blockchainProvider, new LocalWallet()) - const privateKey = await newPrivateKey() - const accountAddress = normalizeAddressWith0x(privateKeyToAddress(privateKey)) - contractKit.connection.addAccount(privateKey) - contractKit.defaultAccount = accountAddress - const authSigner: AuthSigner = { - authenticationMethod: OdisUtils.Query.AuthenticationMethod.WALLET_KEY, - contractKit, + + if (useDEK) { + accountAddress = ACCOUNT_ADDRESS + contractKit.connection.addAccount(PRIVATE_KEY) + contractKit.defaultAccount = accountAddress + authSigner = dekAuthSigner(0) + } else { + const privateKey = await newPrivateKey() + accountAddress = normalizeAddressWith0x(privateKeyToAddress(privateKey)) + contractKit.connection.addAccount(privateKey) + contractKit.defaultAccount = accountAddress + authSigner = { + authenticationMethod: OdisUtils.Query.AuthenticationMethod.WALLET_KEY, + contractKit, + } } const abortController = new AbortController() diff --git a/packages/phone-number-privacy/monitor/src/resources.ts b/packages/phone-number-privacy/monitor/src/resources.ts new file mode 100644 index 00000000000..a3a776f365f --- /dev/null +++ b/packages/phone-number-privacy/monitor/src/resources.ts @@ -0,0 +1,63 @@ +import { EncryptionKeySigner } from '@celo/identity/lib/odis/query' +import { AuthenticationMethod } from '@celo/phone-number-privacy-common' +import { PhoneNumberUtils } from '@celo/phone-utils' +import { + ensureLeading0x, + normalizeAddressWith0x, + privateKeyToAddress, +} from '@celo/utils/lib/address' +import 'isomorphic-fetch' + +export const PRIVATE_KEY = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef' +export const ACCOUNT_ADDRESS = normalizeAddressWith0x(privateKeyToAddress(PRIVATE_KEY)) // 0x1be31a94361a391bbafb2a4ccd704f57dc04d4bb + +export const PRIVATE_KEY_NO_QUOTA = + '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890000000' +export const ACCOUNT_ADDRESS_NO_QUOTA = privateKeyToAddress(PRIVATE_KEY_NO_QUOTA) + +export const PHONE_NUMBER = '+17777777777' +export const BLINDING_FACTOR = Buffer.from('0IsBvRfkBrkKCIW6HV0/T1zrzjQSe8wRyU3PKojCnww=', 'base64') +// BLINDED_PHONE_NUMBER value is dependent on PHONE_NUMBER AND BLINDING_FACTOR +// hardcoding to avoid importing blind_threshols_bls library +export const BLINDED_PHONE_NUMBER = + 'hZXDhpC5onzBSFa1agZ9vfHzqwJ/QeJg77NGvWiQG/sFWsvHETzZvdWr2GpF3QkB' + +export const PHONE_HASH_IDENTIFIER = PhoneNumberUtils.getPhoneHash(PHONE_NUMBER) + +export const CONTACT_PHONE_NUMBER = '+14155559999' +export const CONTACT_PHONE_NUMBERS = [CONTACT_PHONE_NUMBER] + +interface DEK { + privateKey: string + publicKey: string + address: string +} + +export const deks: DEK[] = [ + { + privateKey: 'bf8a2b73baf8402f8fe906ad3f42b560bf14b39f7df7797ece9e293d6f162188', + publicKey: '034846bc781cacdafc66f3a77aa9fc3c56a9dadcd683c72be3c446fee8da041070', + address: '0x7b33dF2607b85e3211738a49A6Ad6E8Ed4d13F6E', + }, + { + privateKey: '0975b0c565abc75b6638a749ea3008cb52676af3eabe4b80e19c516d82330364', + publicKey: '03b1ac8c445f0796978018c087b97e8213b32c39e6a8642ae63dce71da33a19f65', + address: '0x34332049B07Fab9a2e843A7C8991469d93cF6Ae6', + }, +] +// The following code can be used to generate more test DEKs +// const generateDEKs = (n: number): Promise => Promise.all([...Array(n).keys()].map( +// async () => await deriveDek(await generateMnemonic()) +// )) + +export const dekAuthSigner = (index: number): EncryptionKeySigner => { + return { + authenticationMethod: AuthenticationMethod.ENCRYPTION_KEY, + rawKey: ensureLeading0x(deks[index].privateKey), + } +} + +// export const walletAuthSigner: WalletKeySigner = { +// authenticationMethod: AuthenticationMethod.WALLET_KEY, +// contractKit, +// } diff --git a/packages/phone-number-privacy/monitor/src/scripts/run-load-test.ts b/packages/phone-number-privacy/monitor/src/scripts/run-load-test.ts index 2f6b0afaa8c..c6aa374094d 100644 --- a/packages/phone-number-privacy/monitor/src/scripts/run-load-test.ts +++ b/packages/phone-number-privacy/monitor/src/scripts/run-load-test.ts @@ -11,7 +11,8 @@ const runLoadTest = ( isSerial: boolean, pnpQuotaEndpoint: boolean, timeoutMs: number, - bypassQuota: boolean + bypassQuota: boolean, + useDEK: boolean ) => { let blockchainProvider: string switch (contextName) { @@ -39,7 +40,8 @@ const runLoadTest = ( contextName as OdisContextName, pnpQuotaEndpoint ? CombinerEndpointPNP.PNP_QUOTA : CombinerEndpointPNP.PNP_SIGN, timeoutMs, - bypassQuota + bypassQuota, + useDEK ) } else { concurrentLoadTest( @@ -48,7 +50,8 @@ const runLoadTest = ( contextName as OdisContextName, pnpQuotaEndpoint ? CombinerEndpointPNP.PNP_QUOTA : CombinerEndpointPNP.PNP_SIGN, timeoutMs, - bypassQuota + bypassQuota, + useDEK ) } } @@ -87,6 +90,11 @@ yargs description: 'Bypass Signer quota check.', default: false, }) + .option('useDEK', { + type: 'boolean', + description: 'Use Data Encryption Key (DEK) to authenticate.', + default: false, + }) .option('pnpQuotaEndpoint', { type: 'boolean', description: @@ -100,6 +108,7 @@ yargs args.isSerial, args.pnpQuotaEndpoint, args.timeoutMs, - args.bypassQuota + args.bypassQuota, + args.useDEK ) ).argv diff --git a/packages/phone-number-privacy/monitor/src/test.ts b/packages/phone-number-privacy/monitor/src/test.ts index 7c0a3aca51c..af9fa42cebc 100644 --- a/packages/phone-number-privacy/monitor/src/test.ts +++ b/packages/phone-number-privacy/monitor/src/test.ts @@ -14,7 +14,8 @@ export async function testPNPSignQuery( contextName: OdisContextName, endpoint: CombinerEndpointPNP.PNP_SIGN, timeoutMs?: number, - bypassQuota?: boolean + bypassQuota?: boolean, + useDEK?: boolean ) { logger.info(`Performing test PNP query for ${endpoint}`) try { @@ -22,7 +23,8 @@ export async function testPNPSignQuery( blockchainProvider, contextName, timeoutMs, - bypassQuota + bypassQuota, + useDEK ) logger.info({ odisResponse }, 'ODIS salt request successful. System is healthy.') } catch (err) { @@ -85,13 +87,21 @@ export async function serialLoadTest( | CombinerEndpointPNP.PNP_QUOTA | CombinerEndpointPNP.PNP_SIGN = CombinerEndpointPNP.PNP_SIGN, timeoutMs?: number, - bypassQuota?: boolean + bypassQuota?: boolean, + useDEK?: boolean ) { for (let i = 0; i < n; i++) { try { switch (endpoint) { case CombinerEndpointPNP.PNP_SIGN: - await testPNPSignQuery(blockchainProvider, contextName, endpoint, timeoutMs, bypassQuota) + await testPNPSignQuery( + blockchainProvider, + contextName, + endpoint, + timeoutMs, + bypassQuota, + useDEK + ) break case CombinerEndpointPNP.PNP_QUOTA: await testPNPQuotaQuery(blockchainProvider, contextName, timeoutMs) @@ -108,7 +118,8 @@ export async function concurrentLoadTest( | CombinerEndpointPNP.PNP_QUOTA | CombinerEndpointPNP.PNP_SIGN = CombinerEndpointPNP.PNP_SIGN, timeoutMs?: number, - bypassQuota?: boolean + bypassQuota?: boolean, + useDEK?: boolean ) { while (true) { const reqs = [] @@ -126,7 +137,8 @@ export async function concurrentLoadTest( contextName, endpoint, timeoutMs, - bypassQuota + bypassQuota, + useDEK ) break case CombinerEndpointPNP.PNP_QUOTA: From dfa7c3fbb99a6912397823edc241e3868ef84d15 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Thu, 10 Aug 2023 19:22:11 -0400 Subject: [PATCH 2/4] Added monitoring counter for AuthenticationMethod --- .../signer/src/pnp/endpoints/sign/io.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/phone-number-privacy/signer/src/pnp/endpoints/sign/io.ts b/packages/phone-number-privacy/signer/src/pnp/endpoints/sign/io.ts index dfc4dfd3345..b5a10fb4252 100644 --- a/packages/phone-number-privacy/signer/src/pnp/endpoints/sign/io.ts +++ b/packages/phone-number-privacy/signer/src/pnp/endpoints/sign/io.ts @@ -1,6 +1,7 @@ import { ContractKit } from '@celo/contractkit' import { authenticateUser, + AuthenticationMethod, ErrorType, hasValidAccountParam, hasValidBlindedPhoneNumberParam, @@ -75,6 +76,12 @@ export class PnpSignIO extends IO { warnings: ErrorType[], logger: Logger ): Promise { + const authMethod = request.body.authenticationMethod + + if (authMethod && authMethod === AuthenticationMethod.WALLET_KEY) { + Counters.requestsWithWalletAddress.inc() + } + return authenticateUser( request, this.kit, From c81a42b3ee7661a6286dfecfdba38688c52adb7d Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Fri, 11 Aug 2023 11:06:54 -0400 Subject: [PATCH 3/4] randomized phonenumber to avoid replay attempts --- .../phone-number-privacy/monitor/src/query.ts | 5 ++-- .../monitor/src/resources.ts | 28 +++++-------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/packages/phone-number-privacy/monitor/src/query.ts b/packages/phone-number-privacy/monitor/src/query.ts index 33a0c23e4bf..823deb391b0 100644 --- a/packages/phone-number-privacy/monitor/src/query.ts +++ b/packages/phone-number-privacy/monitor/src/query.ts @@ -18,9 +18,9 @@ import { genSessionID } from '@celo/phone-number-privacy-common/lib/utils/logger import { normalizeAddressWith0x, privateKeyToAddress } from '@celo/utils/lib/address' import { defined } from '@celo/utils/lib/sign-typed-data-utils' import { LocalWallet } from '@celo/wallet-local' -import { ACCOUNT_ADDRESS, dekAuthSigner, PRIVATE_KEY } from './resources' +import { ACCOUNT_ADDRESS, dekAuthSigner, generateRandomPhoneNumber, PRIVATE_KEY } from './resources' -const phoneNumber = fetchEnv('PHONE_NUMBER') +let phoneNumber = fetchEnv('PHONE_NUMBER') const newPrivateKey = async () => { const mnemonic = await generateMnemonic(MnemonicStrength.s256_24words) @@ -49,6 +49,7 @@ export const queryOdisForSalt = async ( contractKit.connection.addAccount(PRIVATE_KEY) contractKit.defaultAccount = accountAddress authSigner = dekAuthSigner(0) + phoneNumber = generateRandomPhoneNumber() } else { const privateKey = await newPrivateKey() accountAddress = normalizeAddressWith0x(privateKeyToAddress(privateKey)) diff --git a/packages/phone-number-privacy/monitor/src/resources.ts b/packages/phone-number-privacy/monitor/src/resources.ts index a3a776f365f..97243eb3c68 100644 --- a/packages/phone-number-privacy/monitor/src/resources.ts +++ b/packages/phone-number-privacy/monitor/src/resources.ts @@ -1,6 +1,5 @@ import { EncryptionKeySigner } from '@celo/identity/lib/odis/query' import { AuthenticationMethod } from '@celo/phone-number-privacy-common' -import { PhoneNumberUtils } from '@celo/phone-utils' import { ensureLeading0x, normalizeAddressWith0x, @@ -11,22 +10,6 @@ import 'isomorphic-fetch' export const PRIVATE_KEY = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef' export const ACCOUNT_ADDRESS = normalizeAddressWith0x(privateKeyToAddress(PRIVATE_KEY)) // 0x1be31a94361a391bbafb2a4ccd704f57dc04d4bb -export const PRIVATE_KEY_NO_QUOTA = - '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890000000' -export const ACCOUNT_ADDRESS_NO_QUOTA = privateKeyToAddress(PRIVATE_KEY_NO_QUOTA) - -export const PHONE_NUMBER = '+17777777777' -export const BLINDING_FACTOR = Buffer.from('0IsBvRfkBrkKCIW6HV0/T1zrzjQSe8wRyU3PKojCnww=', 'base64') -// BLINDED_PHONE_NUMBER value is dependent on PHONE_NUMBER AND BLINDING_FACTOR -// hardcoding to avoid importing blind_threshols_bls library -export const BLINDED_PHONE_NUMBER = - 'hZXDhpC5onzBSFa1agZ9vfHzqwJ/QeJg77NGvWiQG/sFWsvHETzZvdWr2GpF3QkB' - -export const PHONE_HASH_IDENTIFIER = PhoneNumberUtils.getPhoneHash(PHONE_NUMBER) - -export const CONTACT_PHONE_NUMBER = '+14155559999' -export const CONTACT_PHONE_NUMBERS = [CONTACT_PHONE_NUMBER] - interface DEK { privateKey: string publicKey: string @@ -45,6 +28,7 @@ export const deks: DEK[] = [ address: '0x34332049B07Fab9a2e843A7C8991469d93cF6Ae6', }, ] + // The following code can be used to generate more test DEKs // const generateDEKs = (n: number): Promise => Promise.all([...Array(n).keys()].map( // async () => await deriveDek(await generateMnemonic()) @@ -57,7 +41,9 @@ export const dekAuthSigner = (index: number): EncryptionKeySigner => { } } -// export const walletAuthSigner: WalletKeySigner = { -// authenticationMethod: AuthenticationMethod.WALLET_KEY, -// contractKit, -// } +export function generateRandomPhoneNumber() { + const min = 1000000000 // Smallest 10-digit number + const max = 9999999999 // Largest 10-digit number + const randomNumber = Math.floor(Math.random() * (max - min + 1)) + min + return '+1' + randomNumber.toString() +} From b70ec2d7fb6f5af4fb5980f369f19e67d6c1eca1 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Fri, 11 Aug 2023 12:12:48 -0400 Subject: [PATCH 4/4] removed isomorphic-fetch --- packages/phone-number-privacy/monitor/src/resources.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/phone-number-privacy/monitor/src/resources.ts b/packages/phone-number-privacy/monitor/src/resources.ts index 97243eb3c68..b7ca1ef06db 100644 --- a/packages/phone-number-privacy/monitor/src/resources.ts +++ b/packages/phone-number-privacy/monitor/src/resources.ts @@ -5,7 +5,6 @@ import { normalizeAddressWith0x, privateKeyToAddress, } from '@celo/utils/lib/address' -import 'isomorphic-fetch' export const PRIVATE_KEY = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef' export const ACCOUNT_ADDRESS = normalizeAddressWith0x(privateKeyToAddress(PRIVATE_KEY)) // 0x1be31a94361a391bbafb2a4ccd704f57dc04d4bb