Skip to content

Commit

Permalink
Merge pull request #180 from rahulbarmann/rahulbarmann/feat#169
Browse files Browse the repository at this point in the history
Feat: add server action for decryption of shares and reconstruct it back to the private key
  • Loading branch information
cb7chaitanya authored Sep 18, 2024
2 parents d498a1a + 06bf5d3 commit b0c33b3
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 30 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
"@solana/wallet-adapter-react-ui": "^0.9.35",
"@solana/wallet-adapter-wallets": "^0.19.32",
"@solana/web3.js": "^1.95.2",
"@types/bs58": "^4.0.4",
"axios": "^1.7.7",
"bs58": "^4.0.1",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"framer-motion": "^11.3.21",
Expand Down
47 changes: 46 additions & 1 deletion src/actions/pvtKeyDecryptMgmt.ts
Original file line number Diff line number Diff line change
@@ -1 +1,46 @@
//Here you create decryption + retrieval logic in a top level server action like the other file
'use server'

import prisma from '@/db'
import { authOptions } from '@/lib/auth'
import { aesDecrypt } from '@/services/aes-module'
import { awsDecrypt } from '@/services/aws-kms-module'
import { gcpDecrypt } from '@/services/gcp-kms-module'
import { combineSecret } from '@/services/keyShardingService'
import { getServerSession } from 'next-auth'
import bs58 from 'bs58'

export async function pvtKeyDecryptionManager() {
try {
const session = await getServerSession(authOptions)
const userId = session.user.id

const { aesShare, awsShare, gcpShare }: any = await prisma.user.findFirst({
where: { id: userId },
select: { aesShare: true, awsShare: true, gcpShare: true },
})

const decryptedAesShare = aesDecrypt(aesShare)
const decryptedAwsShare = await awsDecrypt(awsShare, {
purpose: 'tiplink',
country: 'India',
})
const decryptedGcpShare = await gcpDecrypt(gcpShare)

const aesShareArray = new Uint8Array(Buffer.from(decryptedAesShare, 'hex'))
const awsShareArray = new Uint8Array(Buffer.from(decryptedAwsShare, 'hex'))
const gcpShareArray = new Uint8Array(Buffer.from(decryptedGcpShare, 'hex'))

const res = await combineSecret([
aesShareArray,
awsShareArray,
gcpShareArray,
])

const privateKey = bs58.encode(res)

return privateKey
} catch (error) {
console.error('Error in pvtKeyDecryptionManager:', error)
throw error
}
}
13 changes: 3 additions & 10 deletions src/actions/pvtKeyEncryptMgmt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,18 @@ export async function pvtKeyEncryptionManager(privateKey: string) {
const session = await getServerSession(authOptions)
const userId = session?.user?.id

const { aesShareString, awsShareString, gcpShareString }: any =
await splitSecret(new Uint8Array(Buffer.from(privateKey, 'hex')))
const { aesShareString, awsShareString, gcpShareString } =
await splitSecret(privateKey)

//AES Share 1 -> share encryption AES module
const aesEncryptedShare = aesEncrypt(aesShareString)
//AWS Share 2 -> share encryption AWS module
const awsEncryptedShare = await awsEncrypt(awsShareString, {
purpose: 'tiplink',
country: 'India',
})

//GCP Share 3 -> share encryption GCP module
const gcpEncryptedShare = await gcpEncrypt(gcpShareString)
// DB write

await prisma.user.update({
where: {
id: userId,
},
where: { id: userId },
data: {
aesShare: aesEncryptedShare,
awsShare: awsEncryptedShare,
Expand Down
2 changes: 0 additions & 2 deletions src/services/aws-kms-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ export async function awsDecrypt(
try {
const encryptedBuffer = Buffer.from(encryptedData, 'base64')
const { plaintext, messageHeader } = await decrypt(keyring, encryptedBuffer)
console.log('===== Message Header =======')
console.log(JSON.stringify(messageHeader.encryptionContext))

Object.entries(context).forEach(([key, value]) => {
if (messageHeader.encryptionContext[key] !== value) {
Expand Down
52 changes: 36 additions & 16 deletions src/services/keyShardingService.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
import { split as shamirSplit, combine as shamirCombine } from 'shamir-secret-sharing';
const CryptoJS = require('crypto-js');
import {
split as shamirSplit,
combine as shamirCombine,
} from 'shamir-secret-sharing'

export async function splitSecret(secretKey: Uint8Array) {
if (!secretKey) {
throw new Error('Secret is undefined');
}
try {
const shares = await shamirSplit(secretKey, 3, 3);
import * as bs58 from 'bs58'

const [aesShare, awsShare, gcpShare] = shares;
const aesShareString = Buffer.from(aesShare).toString('hex');
const awsShareString = Buffer.from(awsShare).toString('hex');
const gcpShareString = Buffer.from(gcpShare).toString('hex');
export async function splitSecret(privateKey: string) {
if (!privateKey) {
throw new Error('Private key is undefined')
}
try {
const secretKeyUint8Array = new Uint8Array(bs58.decode(privateKey))

const shares = await shamirSplit(secretKeyUint8Array, 3, 3)

return { aesShareString, awsShareString, gcpShareString };
} catch (error) {
console.error('Error splitting and encrypting secret:', error);
}
const [aesShare, awsShare, gcpShare] = shares
const aesShareString = Buffer.from(aesShare).toString('hex')
const awsShareString = Buffer.from(awsShare).toString('hex')
const gcpShareString = Buffer.from(gcpShare).toString('hex')

return { aesShareString, awsShareString, gcpShareString }
} catch (error) {
console.error('Error splitting secret:', error)
throw error
}
}

export async function combineSecret(shares: Uint8Array[]) {
if (!shares || shares.length === 0) {
throw new Error('Shares are undefined or empty')
}

try {
const secretKey = await shamirCombine(shares)
return new Uint8Array(secretKey)
} catch (e) {
console.error('Error while combining shares: ', e)
throw e
}
}
3 changes: 2 additions & 1 deletion src/services/walletService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import prisma from '@/db'
import { User } from '@prisma/client'
import axios from 'axios'
import { pvtKeyEncryptionManager } from '@/actions/pvtKeyEncryptMgmt'
import base58 from 'bs58'

const customRpcUrl = process.env.NEXT_PUBLIC_SOLANA_RPC || ''

Expand All @@ -20,7 +21,7 @@ export async function createWallet(user: User) {
try {
const keypair = Keypair.generate()
const publicKey = keypair.publicKey.toString()
const privateKey = keypair.secretKey.toString()
const privateKey = base58.encode(keypair.secretKey)
await pvtKeyEncryptionManager(privateKey)
await prisma.user.update({
where: {
Expand Down

0 comments on commit b0c33b3

Please sign in to comment.