Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 76 additions & 1 deletion modules/bitgo/test/v2/unit/internal/tssUtils/ecdsa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,34 @@ describe('TSS Ecdsa Utils:', async function () {
await Promise.all(testCasesPromises);
});

it('createParticipantKeychain should produce a v2-encrypted encryptedPrv when encryptionVersion: 2', async function () {
const passphrase = 'test-passphrase';
// Stub keychains.add to capture the params sent to the API so we can inspect encryptedPrv
const addStub = sinon.stub(baseCoin.keychains(), 'add').resolves({ id: '1', pub: '', type: 'tss' } as Keychain);
try {
await tssUtils.createParticipantKeychain(
userGpgKey,
userLocalBackupGpgKey,
bitgoPublicKey,
1,
userKeyShare,
backupKeyShare,
nockedBitGoKeychain,
passphrase,
undefined,
undefined,
2 // encryptionVersion
);
sinon.assert.calledOnce(addStub);
const addParams = addStub.firstCall.args[0] as { encryptedPrv?: string };
assert.ok(addParams.encryptedPrv, 'encryptedPrv must be passed to keychains.add');
const envelope = JSON.parse(addParams.encryptedPrv!);
assert.strictEqual(envelope.v, 2, 'encryptedPrv must use v2 (Argon2id) envelope');
} finally {
addStub.restore();
}
});

it('should fail to generate TSS keychains when received invalid number of wallet signatures', async function () {
const bitgoKeychain = await generateBitgoKeychain({
coin: coinName,
Expand Down Expand Up @@ -983,7 +1011,28 @@ describe('TSS Ecdsa Utils:', async function () {
encryptedWShare: bitgo.encrypt({ input: JSON.stringify(wShare), password: mockPassword }),
walletPassphrase: 'password1',
})
.should.be.rejectedWith("password error - ccm: tag doesn't match");
.should.be.rejectedWith('incorrect password');
});

it('createOfflineMuDeltaShare should succeed with v2-encrypted wShare', async function () {
const mockPassword = 'password';
const alphaLength = 1536;
const deltaLength = 64;
const bitgo = TestBitGo.decorate(BitGo, { env: 'mock' });
const encryptedWShare = await bitgo.encryptAsync({
input: JSON.stringify(wShare),
password: mockPassword,
encryptionVersion: 2,
});
assert.strictEqual(JSON.parse(encryptedWShare).v, 2, 'pre-condition: wShare must be v2-encrypted');
const step2SigningMaterial = await tssUtils.createOfflineMuDeltaShare({
aShareFromBitgo: aShare,
bitgoChallenge: bitgoChallenges,
encryptedWShare,
walletPassphrase: mockPassword,
});
step2SigningMaterial.muDShare.muShare.alpha.length.should.equal(alphaLength);
step2SigningMaterial.muDShare.dShare.delta.length.should.equal(deltaLength);
});

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

it('createOfflineSShare should succeed with v2-encrypted oShare', async function () {
const mockPassword = 'password';
const pubKeyLength = 66;
const privKeyLength = 64;
const bitgo = TestBitGo.decorate(BitGo, { env: 'mock' });
const encryptedOShare = await bitgo.encryptAsync({
input: JSON.stringify(oShare),
password: mockPassword,
encryptionVersion: 2,
});
assert.strictEqual(JSON.parse(encryptedOShare).v, 2, 'pre-condition: oShare must be v2-encrypted');
const step3SigningMaterial = await tssUtils.createOfflineSShare({
tssParams: {
txRequest: txRequest,
reqId: reqId,
},
dShareFromBitgo: dShare,
encryptedOShare,
walletPassphrase: mockPassword,
requestType: RequestType.tx,
});
step3SigningMaterial.R.length.should.equal(pubKeyLength);
step3SigningMaterial.y.length.should.equal(pubKeyLength);
step3SigningMaterial.s.length.should.equal(privKeyLength);
});

it('createOfflineSShare should fail with txId passed', async function () {
const mockPassword = 'password';
const bitgo = TestBitGo.decorate(BitGo, { env: 'mock' });
Expand Down
32 changes: 23 additions & 9 deletions modules/sdk-core/src/bitgo/utils/tss/ecdsa/ecdsa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import {
TxRequestChallengeResponse,
} from '../../../tss/types';
import { BaseEcdsaUtils } from './base';
import { IRequestTracer } from '../../../../api';
import { EncryptionVersion, IRequestTracer } from '../../../../api';

const encryptNShare = ECDSAMethods.encryptNShare;

Expand Down Expand Up @@ -183,6 +183,7 @@ export class EcdsaUtils extends BaseEcdsaUtils {
passphrase,
originalPasscodeEncryptionCode,
webauthnInfo,
encryptionVersion,
}: CreateEcdsaKeychainParams): Promise<Keychain> {
if (!passphrase) {
throw new Error('Please provide a wallet passphrase');
Expand All @@ -198,7 +199,8 @@ export class EcdsaUtils extends BaseEcdsaUtils {
bitgoKeychain,
passphrase,
originalPasscodeEncryptionCode,
webauthnInfo
webauthnInfo,
encryptionVersion
);
}

Expand All @@ -210,6 +212,7 @@ export class EcdsaUtils extends BaseEcdsaUtils {
bitgoKeychain,
bitgoPublicGpgKey,
passphrase,
encryptionVersion,
}: CreateEcdsaKeychainParams): Promise<Keychain> {
assert(backupKeyShare.userHeldKeyShare);
assert(passphrase);
Expand All @@ -221,7 +224,10 @@ export class EcdsaUtils extends BaseEcdsaUtils {
userKeyShare,
backupKeyShare.userHeldKeyShare,
bitgoKeychain,
passphrase
passphrase,
undefined,
undefined,
encryptionVersion
);
}

Expand Down Expand Up @@ -312,7 +318,8 @@ export class EcdsaUtils extends BaseEcdsaUtils {
bitgoKeychain: Keychain,
passphrase: string,
originalPasscodeEncryptionCode?: string,
webauthnInfo?: WebauthnKeyEncryptionInfo
webauthnInfo?: WebauthnKeyEncryptionInfo,
encryptionVersion?: EncryptionVersion
): Promise<Keychain> {
const bitgoKeyShares = bitgoKeychain.keyShares;
if (!bitgoKeyShares) {
Expand Down Expand Up @@ -402,9 +409,10 @@ export class EcdsaUtils extends BaseEcdsaUtils {
keyType: 'tss' as KeyType,
commonKeychain: bitgoKeychain.commonKeychain,
prv: prv,
encryptedPrv: this.bitgo.encrypt({
encryptedPrv: await this.bitgo.encryptAsync({
input: prv,
password: passphrase,
encryptionVersion,
}),
originalPasscodeEncryptionCode,
webauthnDevices:
Expand Down Expand Up @@ -499,7 +507,10 @@ export class EcdsaUtils extends BaseEcdsaUtils {
userPublicGpgKey: userPublicGpgKey,
kShare: userSignShare.kShare,
wShare: params.walletPassphrase
? this.bitgo.encrypt({ input: JSON.stringify(userSignShare.wShare), password: params.walletPassphrase })
? await this.bitgo.encryptAsync({
input: JSON.stringify(userSignShare.wShare),
password: params.walletPassphrase,
})
: userSignShare.wShare,
};
}
Expand Down Expand Up @@ -529,7 +540,7 @@ export class EcdsaUtils extends BaseEcdsaUtils {
i: userGammaAndMuShares.muShare.i,
},
oShare: params.walletPassphrase
? this.bitgo.encrypt({
? await this.bitgo.encryptAsync({
input: JSON.stringify(userOmicronAndDeltaShare.oShare),
password: params.walletPassphrase,
})
Expand Down Expand Up @@ -584,7 +595,10 @@ export class EcdsaUtils extends BaseEcdsaUtils {
encryptedWShare: string;
walletPassphrase: string;
}): Promise<TssEcdsaStep2ReturnMessage> {
const decryptedWShare = this.bitgo.decrypt({ input: params.encryptedWShare, password: params.walletPassphrase });
const decryptedWShare = await this.bitgo.decryptAsync({
input: params.encryptedWShare,
password: params.walletPassphrase,
});
return await this.createTssEcdsaStep2SigningMaterial({
aShareFromBitgo: params.aShareFromBitgo,
bitgoChallenge: params.bitgoChallenge,
Expand Down Expand Up @@ -618,7 +632,7 @@ export class EcdsaUtils extends BaseEcdsaUtils {
} catch (err) {
hash = undefined;
}
const decryptedOShare = this.bitgo.decrypt({ input: encryptedOShare, password: walletPassphrase });
const decryptedOShare = await this.bitgo.decryptAsync({ input: encryptedOShare, password: walletPassphrase });
const { i, R, s, y } = await ECDSAMethods.createUserSignatureShare(
JSON.parse(decryptedOShare),
dShareFromBitgo,
Expand Down
Loading