From c1a8f4ae99e4612eed84a5043c0bb5d1eff88ad5 Mon Sep 17 00:00:00 2001 From: schmanu Date: Tue, 28 Nov 2023 16:05:01 +0100 Subject: [PATCH] feat: encrypt sms factor key before sending it to web3auth's service --- src/services/mpc/EncryptionUtil.ts | 32 +++++++++++++++++++++ src/services/mpc/recovery/SmsOtpRecovery.ts | 15 ++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 src/services/mpc/EncryptionUtil.ts diff --git a/src/services/mpc/EncryptionUtil.ts b/src/services/mpc/EncryptionUtil.ts new file mode 100644 index 0000000000..ac59c64250 --- /dev/null +++ b/src/services/mpc/EncryptionUtil.ts @@ -0,0 +1,32 @@ +import { getPubKeyPoint, encrypt, type EncryptedMessage, decrypt, toPrivKeyECC } from '@tkey-mpc/common-types' +import { Point } from '@web3auth/mpc-core-kit' +import type BN from 'bn.js' + +/** + * Util class to encrypt and decrypt data using i.e. the postbox key of the torus storage + */ +export default class EncryptionUtil { + private privateKey: BN + + constructor(privateKey: BN) { + this.privateKey = privateKey + } + + public async encrypt(data: T): Promise { + const oAuthKeyBN = this.privateKey + const oAuthPubKey = getPubKeyPoint(oAuthKeyBN) + const payload = JSON.stringify(data) + const encryptedMessage = await encrypt( + Point.fromTkeyPoint(oAuthPubKey).toBufferSEC1(false), + Buffer.from(payload, 'utf-8'), + ) + + return JSON.stringify(encryptedMessage) + } + + public async decrypt(data: string): Promise { + const encryptedData = JSON.parse(data) as EncryptedMessage + const decryptedDataBuffer = await decrypt(toPrivKeyECC(this.privateKey), encryptedData) + return JSON.parse(decryptedDataBuffer.toString('utf-8')) as T + } +} diff --git a/src/services/mpc/recovery/SmsOtpRecovery.ts b/src/services/mpc/recovery/SmsOtpRecovery.ts index 6ecbd51392..4b39c0dc84 100644 --- a/src/services/mpc/recovery/SmsOtpRecovery.ts +++ b/src/services/mpc/recovery/SmsOtpRecovery.ts @@ -10,6 +10,7 @@ import { BN } from 'bn.js' import { ecsign, keccak256 } from 'ethereumjs-util' import { hexZeroPad } from 'ethers/lib/utils' import { SOCIAL_WALLET_OPTIONS } from '../config' +import EncryptionUtil from '../EncryptionUtil' type SmsOtpStoreData = { number: string @@ -209,11 +210,20 @@ export class SmsOtpRecovery { code, tracking_id, } + // We need the oAuthKey to encrypt / decrypt + const oAuthKey = this.mpcCoreKit.state.oAuthKey + if (!oAuthKey) { + throw new Error('Cannot create factor without oAuthKey') + } + const encryptionUtil = new EncryptionUtil(new BN(oAuthKey, 'hex')) if (isFirstTime) { // create a new factor key to setup data in the database. const newFactorKey = generateFactorKey() - data.data = JSON.stringify({ factorKey: newFactorKey.private.toString(16, 64) }) + + // Encrypt the key with the torus postbox key + const payload = { factorKey: newFactorKey.private.toString(16, 64) } + data.data = await encryptionUtil.encrypt(payload) } const response = await fetch(`${SmsOtpRecovery.BASE_URL}/api/v1/sms/verify`, { @@ -231,7 +241,8 @@ export class SmsOtpRecovery { }) // if successfull, add this factorKey and share info in tkey instance. - const storedFactorKey = JSON.parse(response.data)?.factorKey + const decryptedData = await encryptionUtil.decrypt<{ factorKey: string }>(response.data) + const storedFactorKey = decryptedData?.factorKey if (storedFactorKey) { const newFactorKey = new BN(storedFactorKey, 'hex') if (isFirstTime) {