Skip to content

Commit d62e946

Browse files
authored
Merge pull request #8808 from BitGo/WCN-283
feat(sdk-core): add v2 decryption support for gg18
2 parents f4f6e8e + f350272 commit d62e946

2 files changed

Lines changed: 99 additions & 10 deletions

File tree

  • modules
    • bitgo/test/v2/unit/internal/tssUtils
    • sdk-core/src/bitgo/utils/tss/ecdsa

modules/bitgo/test/v2/unit/internal/tssUtils/ecdsa.ts

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,34 @@ describe('TSS Ecdsa Utils:', async function () {
426426
await Promise.all(testCasesPromises);
427427
});
428428

429+
it('createParticipantKeychain should produce a v2-encrypted encryptedPrv when encryptionVersion: 2', async function () {
430+
const passphrase = 'test-passphrase';
431+
// Stub keychains.add to capture the params sent to the API so we can inspect encryptedPrv
432+
const addStub = sinon.stub(baseCoin.keychains(), 'add').resolves({ id: '1', pub: '', type: 'tss' } as Keychain);
433+
try {
434+
await tssUtils.createParticipantKeychain(
435+
userGpgKey,
436+
userLocalBackupGpgKey,
437+
bitgoPublicKey,
438+
1,
439+
userKeyShare,
440+
backupKeyShare,
441+
nockedBitGoKeychain,
442+
passphrase,
443+
undefined,
444+
undefined,
445+
2 // encryptionVersion
446+
);
447+
sinon.assert.calledOnce(addStub);
448+
const addParams = addStub.firstCall.args[0] as { encryptedPrv?: string };
449+
assert.ok(addParams.encryptedPrv, 'encryptedPrv must be passed to keychains.add');
450+
const envelope = JSON.parse(addParams.encryptedPrv!);
451+
assert.strictEqual(envelope.v, 2, 'encryptedPrv must use v2 (Argon2id) envelope');
452+
} finally {
453+
addStub.restore();
454+
}
455+
});
456+
429457
it('should fail to generate TSS keychains when received invalid number of wallet signatures', async function () {
430458
const bitgoKeychain = await generateBitgoKeychain({
431459
coin: coinName,
@@ -983,7 +1011,28 @@ describe('TSS Ecdsa Utils:', async function () {
9831011
encryptedWShare: bitgo.encrypt({ input: JSON.stringify(wShare), password: mockPassword }),
9841012
walletPassphrase: 'password1',
9851013
})
986-
.should.be.rejectedWith("password error - ccm: tag doesn't match");
1014+
.should.be.rejectedWith('incorrect password');
1015+
});
1016+
1017+
it('createOfflineMuDeltaShare should succeed with v2-encrypted wShare', async function () {
1018+
const mockPassword = 'password';
1019+
const alphaLength = 1536;
1020+
const deltaLength = 64;
1021+
const bitgo = TestBitGo.decorate(BitGo, { env: 'mock' });
1022+
const encryptedWShare = await bitgo.encryptAsync({
1023+
input: JSON.stringify(wShare),
1024+
password: mockPassword,
1025+
encryptionVersion: 2,
1026+
});
1027+
assert.strictEqual(JSON.parse(encryptedWShare).v, 2, 'pre-condition: wShare must be v2-encrypted');
1028+
const step2SigningMaterial = await tssUtils.createOfflineMuDeltaShare({
1029+
aShareFromBitgo: aShare,
1030+
bitgoChallenge: bitgoChallenges,
1031+
encryptedWShare,
1032+
walletPassphrase: mockPassword,
1033+
});
1034+
step2SigningMaterial.muDShare.muShare.alpha.length.should.equal(alphaLength);
1035+
step2SigningMaterial.muDShare.dShare.delta.length.should.equal(deltaLength);
9871036
});
9881037

9891038
it('createOfflineSShare should succeed', async function () {
@@ -1006,6 +1055,32 @@ describe('TSS Ecdsa Utils:', async function () {
10061055
step3SigningMaterial.s.length.should.equal(privKeyLength);
10071056
});
10081057

1058+
it('createOfflineSShare should succeed with v2-encrypted oShare', async function () {
1059+
const mockPassword = 'password';
1060+
const pubKeyLength = 66;
1061+
const privKeyLength = 64;
1062+
const bitgo = TestBitGo.decorate(BitGo, { env: 'mock' });
1063+
const encryptedOShare = await bitgo.encryptAsync({
1064+
input: JSON.stringify(oShare),
1065+
password: mockPassword,
1066+
encryptionVersion: 2,
1067+
});
1068+
assert.strictEqual(JSON.parse(encryptedOShare).v, 2, 'pre-condition: oShare must be v2-encrypted');
1069+
const step3SigningMaterial = await tssUtils.createOfflineSShare({
1070+
tssParams: {
1071+
txRequest: txRequest,
1072+
reqId: reqId,
1073+
},
1074+
dShareFromBitgo: dShare,
1075+
encryptedOShare,
1076+
walletPassphrase: mockPassword,
1077+
requestType: RequestType.tx,
1078+
});
1079+
step3SigningMaterial.R.length.should.equal(pubKeyLength);
1080+
step3SigningMaterial.y.length.should.equal(pubKeyLength);
1081+
step3SigningMaterial.s.length.should.equal(privKeyLength);
1082+
});
1083+
10091084
it('createOfflineSShare should fail with txId passed', async function () {
10101085
const mockPassword = 'password';
10111086
const bitgo = TestBitGo.decorate(BitGo, { env: 'mock' });

modules/sdk-core/src/bitgo/utils/tss/ecdsa/ecdsa.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import {
4949
TxRequestChallengeResponse,
5050
} from '../../../tss/types';
5151
import { BaseEcdsaUtils } from './base';
52-
import { IRequestTracer } from '../../../../api';
52+
import { EncryptionVersion, IRequestTracer } from '../../../../api';
5353

5454
const encryptNShare = ECDSAMethods.encryptNShare;
5555

@@ -183,6 +183,7 @@ export class EcdsaUtils extends BaseEcdsaUtils {
183183
passphrase,
184184
originalPasscodeEncryptionCode,
185185
webauthnInfo,
186+
encryptionVersion,
186187
}: CreateEcdsaKeychainParams): Promise<Keychain> {
187188
if (!passphrase) {
188189
throw new Error('Please provide a wallet passphrase');
@@ -198,7 +199,8 @@ export class EcdsaUtils extends BaseEcdsaUtils {
198199
bitgoKeychain,
199200
passphrase,
200201
originalPasscodeEncryptionCode,
201-
webauthnInfo
202+
webauthnInfo,
203+
encryptionVersion
202204
);
203205
}
204206

@@ -210,6 +212,7 @@ export class EcdsaUtils extends BaseEcdsaUtils {
210212
bitgoKeychain,
211213
bitgoPublicGpgKey,
212214
passphrase,
215+
encryptionVersion,
213216
}: CreateEcdsaKeychainParams): Promise<Keychain> {
214217
assert(backupKeyShare.userHeldKeyShare);
215218
assert(passphrase);
@@ -221,7 +224,10 @@ export class EcdsaUtils extends BaseEcdsaUtils {
221224
userKeyShare,
222225
backupKeyShare.userHeldKeyShare,
223226
bitgoKeychain,
224-
passphrase
227+
passphrase,
228+
undefined,
229+
undefined,
230+
encryptionVersion
225231
);
226232
}
227233

@@ -312,7 +318,8 @@ export class EcdsaUtils extends BaseEcdsaUtils {
312318
bitgoKeychain: Keychain,
313319
passphrase: string,
314320
originalPasscodeEncryptionCode?: string,
315-
webauthnInfo?: WebauthnKeyEncryptionInfo
321+
webauthnInfo?: WebauthnKeyEncryptionInfo,
322+
encryptionVersion?: EncryptionVersion
316323
): Promise<Keychain> {
317324
const bitgoKeyShares = bitgoKeychain.keyShares;
318325
if (!bitgoKeyShares) {
@@ -402,9 +409,10 @@ export class EcdsaUtils extends BaseEcdsaUtils {
402409
keyType: 'tss' as KeyType,
403410
commonKeychain: bitgoKeychain.commonKeychain,
404411
prv: prv,
405-
encryptedPrv: this.bitgo.encrypt({
412+
encryptedPrv: await this.bitgo.encryptAsync({
406413
input: prv,
407414
password: passphrase,
415+
encryptionVersion,
408416
}),
409417
originalPasscodeEncryptionCode,
410418
webauthnDevices:
@@ -499,7 +507,10 @@ export class EcdsaUtils extends BaseEcdsaUtils {
499507
userPublicGpgKey: userPublicGpgKey,
500508
kShare: userSignShare.kShare,
501509
wShare: params.walletPassphrase
502-
? this.bitgo.encrypt({ input: JSON.stringify(userSignShare.wShare), password: params.walletPassphrase })
510+
? await this.bitgo.encryptAsync({
511+
input: JSON.stringify(userSignShare.wShare),
512+
password: params.walletPassphrase,
513+
})
503514
: userSignShare.wShare,
504515
};
505516
}
@@ -529,7 +540,7 @@ export class EcdsaUtils extends BaseEcdsaUtils {
529540
i: userGammaAndMuShares.muShare.i,
530541
},
531542
oShare: params.walletPassphrase
532-
? this.bitgo.encrypt({
543+
? await this.bitgo.encryptAsync({
533544
input: JSON.stringify(userOmicronAndDeltaShare.oShare),
534545
password: params.walletPassphrase,
535546
})
@@ -584,7 +595,10 @@ export class EcdsaUtils extends BaseEcdsaUtils {
584595
encryptedWShare: string;
585596
walletPassphrase: string;
586597
}): Promise<TssEcdsaStep2ReturnMessage> {
587-
const decryptedWShare = this.bitgo.decrypt({ input: params.encryptedWShare, password: params.walletPassphrase });
598+
const decryptedWShare = await this.bitgo.decryptAsync({
599+
input: params.encryptedWShare,
600+
password: params.walletPassphrase,
601+
});
588602
return await this.createTssEcdsaStep2SigningMaterial({
589603
aShareFromBitgo: params.aShareFromBitgo,
590604
bitgoChallenge: params.bitgoChallenge,
@@ -618,7 +632,7 @@ export class EcdsaUtils extends BaseEcdsaUtils {
618632
} catch (err) {
619633
hash = undefined;
620634
}
621-
const decryptedOShare = this.bitgo.decrypt({ input: encryptedOShare, password: walletPassphrase });
635+
const decryptedOShare = await this.bitgo.decryptAsync({ input: encryptedOShare, password: walletPassphrase });
622636
const { i, R, s, y } = await ECDSAMethods.createUserSignatureShare(
623637
JSON.parse(decryptedOShare),
624638
dShareFromBitgo,

0 commit comments

Comments
 (0)