diff options
author | Florian Dold <florian@dold.me> | 2022-03-24 01:59:08 +0100 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2022-03-24 01:59:08 +0100 |
commit | 303c6e99b34ed4e8b0272fe89f300b0838bbe5e4 (patch) | |
tree | 35f1260ea714eb4a6ac0cc7b9c7b19bf824d4fda | |
parent | 454b55aa56034f0599f88e92e0475f5928486ce7 (diff) |
wallet: allow using RPC crypto in more places
7 files changed, 173 insertions, 83 deletions
diff --git a/packages/taler-util/src/talerCrypto.ts b/packages/taler-util/src/talerCrypto.ts index 0385658ca..6bcb592e3 100644 --- a/packages/taler-util/src/talerCrypto.ts +++ b/packages/taler-util/src/talerCrypto.ts @@ -700,25 +700,6 @@ export function bufferForUint32(n: number): Uint8Array { return buf; } -export function setupWithdrawPlanchet( - secretSeed: Uint8Array, - coinNumber: number, -): FreshCoin { - const info = stringToBytes("taler-withdrawal-coin-derivation"); - const saltArrBuf = new ArrayBuffer(4); - const salt = new Uint8Array(saltArrBuf); - const saltDataView = new DataView(saltArrBuf); - saltDataView.setUint32(0, coinNumber); - const out = kdf(64, secretSeed, salt, info); - const coinPriv = out.slice(0, 32); - const bks = out.slice(32, 64); - return { - bks, - coinPriv, - coinPub: eddsaGetPublic(coinPriv), - }; -} - export function setupTipPlanchet( secretSeed: Uint8Array, coinNumber: number, @@ -737,23 +718,6 @@ export function setupTipPlanchet( coinPub: eddsaGetPublic(coinPriv), }; } - -export function setupRefreshTransferPub( - secretSeed: Uint8Array, - transferPubIndex: number, -): EcdheKeyPair { - const info = stringToBytes("taler-transfer-pub-derivation"); - const saltArrBuf = new ArrayBuffer(4); - const salt = new Uint8Array(saltArrBuf); - const saltDataView = new DataView(saltArrBuf); - saltDataView.setUint32(0, transferPubIndex); - const out = kdf(32, secretSeed, salt, info); - return { - ecdhePriv: out, - ecdhePub: ecdheGetPublic(out), - }; -} - /** * * @param paytoUri diff --git a/packages/taler-wallet-cli/src/bench2.ts b/packages/taler-wallet-cli/src/bench2.ts index c1fa674c4..2ee53329a 100644 --- a/packages/taler-wallet-cli/src/bench2.ts +++ b/packages/taler-wallet-cli/src/bench2.ts @@ -31,7 +31,6 @@ import { depositCoin, downloadExchangeInfo, findDenomOrThrow, - generateReserveKeypair, NodeHttpLib, refreshCoin, SynchronousCryptoWorkerFactory, @@ -64,7 +63,7 @@ export async function runBench2(configJson: any): Promise<void> { for (let i = 0; i < numIter; i++) { const exchangeInfo = await downloadExchangeInfo(benchConf.exchange, http); - const reserveKeyPair = generateReserveKeypair(); + const reserveKeyPair = await cryptoApi.createEddsaKeypair({}); console.log("creating fakebank reserve"); @@ -73,12 +72,12 @@ export async function runBench2(configJson: any): Promise<void> { exchangeInfo, fakebankBaseUrl: benchConf.bank, http, - reservePub: reserveKeyPair.reservePub, + reservePub: reserveKeyPair.pub, }); console.log("waiting for reserve"); - await checkReserve(http, benchConf.exchange, reserveKeyPair.reservePub); + await checkReserve(http, benchConf.exchange, reserveKeyPair.pub); console.log("reserve found"); @@ -89,7 +88,10 @@ export async function runBench2(configJson: any): Promise<void> { const coin = await withdrawCoin({ http, cryptoApi, - reserveKeyPair, + reserveKeyPair: { + reservePriv: reserveKeyPair.priv, + reservePub: reserveKeyPair.pub, + }, denom: d1, exchangeBaseUrl: benchConf.exchange, }); diff --git a/packages/taler-wallet-cli/src/integrationtests/test-wallet-dbless.ts b/packages/taler-wallet-cli/src/integrationtests/test-wallet-dbless.ts index d8abae136..3837e567a 100644 --- a/packages/taler-wallet-cli/src/integrationtests/test-wallet-dbless.ts +++ b/packages/taler-wallet-cli/src/integrationtests/test-wallet-dbless.ts @@ -24,7 +24,6 @@ import { depositCoin, downloadExchangeInfo, findDenomOrThrow, - generateReserveKeypair, NodeHttpLib, refreshCoin, SynchronousCryptoWorkerFactory, @@ -52,11 +51,11 @@ export async function runWalletDblessTest(t: GlobalTestState) { const exchangeInfo = await downloadExchangeInfo(exchange.baseUrl, http); - const reserveKeyPair = generateReserveKeypair(); + const reserveKeyPair = await cryptoApi.createEddsaKeypair({}); await topupReserveWithDemobank( http, - reserveKeyPair.reservePub, + reserveKeyPair.pub, bank.baseUrl, exchangeInfo, "TESTKUDOS:10", @@ -64,14 +63,17 @@ export async function runWalletDblessTest(t: GlobalTestState) { await exchange.runWirewatchOnce(); - await checkReserve(http, exchange.baseUrl, reserveKeyPair.reservePub); + await checkReserve(http, exchange.baseUrl, reserveKeyPair.pub); const d1 = findDenomOrThrow(exchangeInfo, "TESTKUDOS:8"); const coin = await withdrawCoin({ http, cryptoApi, - reserveKeyPair, + reserveKeyPair: { + reservePriv: reserveKeyPair.priv, + reservePub: reserveKeyPair.pub, + }, denom: d1, exchangeBaseUrl: exchange.baseUrl, }); diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts index a6093e365..fa754e354 100644 --- a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts +++ b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts @@ -28,7 +28,6 @@ import { AmountJson, Amounts, - BenchmarkResult, buildSigPS, CoinDepositPermission, CoinEnvelope, @@ -58,9 +57,7 @@ import { rsaBlind, rsaUnblind, rsaVerify, - setupRefreshTransferPub, setupTipPlanchet, - setupWithdrawPlanchet, stringToBytes, TalerSignaturePurpose, BlindedDenominationSignature, @@ -69,9 +66,12 @@ import { TalerProtocolTimestamp, kdfKw, bufferForUint32, + kdf, + ecdheGetPublic, + getRandomBytes, } from "@gnu-taler/taler-util"; import bigint from "big-integer"; -import { DenominationRecord, WireFee } from "../db.js"; +import { DenominationRecord, TipCoinSource, WireFee } from "../db.js"; import { CreateRecoupRefreshReqRequest, CreateRecoupReqRequest, @@ -130,7 +130,7 @@ export interface TalerCryptoInterface { createEddsaKeypair(req: {}): Promise<EddsaKeypair>; - eddsaGetPublic(req: EddsaGetPublicRequest): Promise<EddsaKeypair>; + eddsaGetPublic(req: EddsaGetPublicRequest): Promise<EddsaGetPublicResponse>; unblindDenominationSignature( req: UnblindDenominationSignatureRequest, @@ -160,9 +160,19 @@ export interface TalerCryptoInterface { req: SetupRefreshPlanchetRequest, ): Promise<FreshCoinEncoded>; + setupWithdrawalPlanchet( + req: SetupWithdrawalPlanchetRequest, + ): Promise<FreshCoinEncoded>; + keyExchangeEcdheEddsa( req: KeyExchangeEcdheEddsaRequest, ): Promise<KeyExchangeResult>; + + ecdheGetPublic(req: EddsaGetPublicRequest): Promise<EddsaGetPublicResponse>; + + setupRefreshTransferPub( + req: SetupRefreshTransferPubRequest, + ): Promise<TransferPubResponse>; } /** @@ -279,6 +289,21 @@ export const nullCrypto: TalerCryptoInterface = { ): Promise<KeyExchangeResult> { throw new Error("Function not implemented."); }, + setupWithdrawalPlanchet: function ( + req: SetupWithdrawalPlanchetRequest, + ): Promise<FreshCoinEncoded> { + throw new Error("Function not implemented."); + }, + ecdheGetPublic: function ( + req: EddsaGetPublicRequest, + ): Promise<EddsaGetPublicResponse> { + throw new Error("Function not implemented."); + }, + setupRefreshTransferPub: function ( + req: SetupRefreshTransferPubRequest, + ): Promise<TransferPubResponse> { + throw new Error("Function not implemented."); + }, }; export type WithArg<X> = X extends (req: infer T) => infer R @@ -302,6 +327,11 @@ export interface SetupRefreshPlanchetRequest { coinNumber: number; } +export interface SetupWithdrawalPlanchetRequest { + secretSeed: string; + coinNumber: number; +} + export interface RsaVerificationRequest { hm: string; sig: string; @@ -369,6 +399,18 @@ export interface EddsaGetPublicRequest { priv: string; } +export interface EddsaGetPublicResponse { + pub: string; +} + +export interface EcdheGetPublicRequest { + priv: string; +} + +export interface EcdheGetPublicResponse { + pub: string; +} + export interface UnblindDenominationSignatureRequest { planchet: PlanchetUnblindInfo; evSig: BlindedDenominationSignature; @@ -403,6 +445,16 @@ export interface KeyExchangeResult { h: string; } +export interface SetupRefreshTransferPubRequest { + secretSeed: string; + transferPubIndex: number; +} + +export interface TransferPubResponse { + transferPub: string; + transferPriv: string; +} + export const nativeCryptoR: TalerCryptoInterfaceR = { async eddsaSign( tci: TalerCryptoInterfaceR, @@ -453,10 +505,38 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { salt: stringToBytes("bks"), }); + const coinPrivEnc = encodeCrock(coinPriv); + const coinPubRes = await tci.eddsaGetPublic(tci, { + priv: coinPrivEnc, + }); + + return { + bks: encodeCrock(bks), + coinPriv: coinPrivEnc, + coinPub: coinPubRes.pub, + }; + }, + + async setupWithdrawalPlanchet( + tci: TalerCryptoInterfaceR, + req: SetupWithdrawalPlanchetRequest, + ): Promise<FreshCoinEncoded> { + const info = stringToBytes("taler-withdrawal-coin-derivation"); + const saltArrBuf = new ArrayBuffer(4); + const salt = new Uint8Array(saltArrBuf); + const saltDataView = new DataView(saltArrBuf); + saltDataView.setUint32(0, req.coinNumber); + const out = kdf(64, decodeCrock(req.secretSeed), salt, info); + const coinPriv = out.slice(0, 32); + const bks = out.slice(32, 64); + const coinPrivEnc = encodeCrock(coinPriv); + const coinPubRes = await tci.eddsaGetPublic(tci, { + priv: coinPrivEnc, + }); return { bks: encodeCrock(bks), - coinPriv: encodeCrock(coinPriv), - coinPub: encodeCrock(eddsaGetPublic(coinPriv)), + coinPriv: coinPrivEnc, + coinPub: coinPubRes.pub, }; }, @@ -468,13 +548,13 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { if (denomPub.cipher === DenomKeyType.Rsa) { const reservePub = decodeCrock(req.reservePub); const denomPubRsa = decodeCrock(denomPub.rsa_public_key); - const derivedPlanchet = setupWithdrawPlanchet( - decodeCrock(req.secretSeed), - req.coinIndex, - ); - const coinPubHash = hash(derivedPlanchet.coinPub); + const derivedPlanchet = await tci.setupWithdrawalPlanchet(tci, { + coinNumber: req.coinIndex, + secretSeed: req.secretSeed, + }); + const coinPubHash = hash(decodeCrock(derivedPlanchet.coinPub)); const blindResp = await tci.rsaBlind(tci, { - bks: encodeCrock(derivedPlanchet.bks), + bks: derivedPlanchet.bks, hm: encodeCrock(coinPubHash), pub: denomPub.rsa_public_key, }); @@ -499,10 +579,10 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { }); const planchet: WithdrawalPlanchet = { - blindingKey: encodeCrock(derivedPlanchet.bks), + blindingKey: derivedPlanchet.bks, coinEv, - coinPriv: encodeCrock(derivedPlanchet.coinPriv), - coinPub: encodeCrock(derivedPlanchet.coinPub), + coinPriv: derivedPlanchet.coinPriv, + coinPub: derivedPlanchet.coinPub, coinValue: req.value, denomPub, denomPubHash: encodeCrock(denomPubHash), @@ -715,10 +795,13 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { * Create a new EdDSA key pair. */ async createEddsaKeypair(tci: TalerCryptoInterfaceR): Promise<EddsaKeypair> { - const pair = createEddsaKeyPair(); + const eddsaPriv = encodeCrock(getRandomBytes(32)); + const eddsaPubRes = await tci.eddsaGetPublic(tci, { + priv: eddsaPriv, + }); return { - priv: encodeCrock(pair.eddsaPriv), - pub: encodeCrock(pair.eddsaPub), + priv: eddsaPriv, + pub: eddsaPubRes.pub, }; }, @@ -876,13 +959,13 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { const planchetsForGammas: RefreshPlanchetInfo[][] = []; for (let i = 0; i < kappa; i++) { - const transferKeyPair = setupRefreshTransferPub( - decodeCrock(refreshSessionSecretSeed), - i, - ); - sessionHc.update(transferKeyPair.ecdhePub); - transferPrivs.push(encodeCrock(transferKeyPair.ecdhePriv)); - transferPubs.push(encodeCrock(transferKeyPair.ecdhePub)); + const transferKeyPair = await tci.setupRefreshTransferPub(tci, { + secretSeed: refreshSessionSecretSeed, + transferPubIndex: i, + }); + sessionHc.update(decodeCrock(transferKeyPair.transferPub)); + transferPrivs.push(transferKeyPair.transferPriv); + transferPubs.push(transferKeyPair.transferPub); } for (const denomSel of newCoinDenoms) { @@ -1041,6 +1124,30 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { ), }; }, + async ecdheGetPublic( + tci: TalerCryptoInterfaceR, + req: EcdheGetPublicRequest, + ): Promise<EcdheGetPublicResponse> { + return { + pub: encodeCrock(ecdheGetPublic(decodeCrock(req.priv))), + }; + }, + async setupRefreshTransferPub( + tci: TalerCryptoInterfaceR, + req: SetupRefreshTransferPubRequest, + ): Promise<TransferPubResponse> { + const info = stringToBytes("taler-transfer-pub-derivation"); + const saltArrBuf = new ArrayBuffer(4); + const salt = new Uint8Array(saltArrBuf); + const saltDataView = new DataView(saltArrBuf); + saltDataView.setUint32(0, req.transferPubIndex); + const out = kdf(32, decodeCrock(req.secretSeed), salt, info); + const transferPriv = encodeCrock(out); + return { + transferPriv, + transferPub: (await tci.ecdheGetPublic(tci, { priv: transferPriv })).pub, + }; + }, }; function amountToBuffer(amount: AmountJson): Uint8Array { diff --git a/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts b/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts index 902222673..4dda9cd11 100644 --- a/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts +++ b/packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts @@ -86,7 +86,6 @@ export class SynchronousCryptoWorker { blinded: res.blinded, }; }; - this.cryptoImplR.keyExchangeEcdheEddsa = async (_, req) => { const res = await rpc.queueRequest({ op: "kx_ecdhe_eddsa", @@ -99,6 +98,28 @@ export class SynchronousCryptoWorker { h: res.h, }; }; + this.cryptoImplR.eddsaGetPublic = async (_, req) => { + const res = await rpc.queueRequest({ + op: "eddsa_get_public", + args: { + eddsa_priv: req.priv, + }, + }); + return { + pub: res.eddsa_pub, + }; + }; + this.cryptoImplR.ecdheGetPublic = async (_, req) => { + const res = await rpc.queueRequest({ + op: "ecdhe_get_public", + args: { + ecdhe_priv: req.priv, + }, + }); + return { + pub: res.ecdhe_pub, + }; + }; } } diff --git a/packages/taler-wallet-core/src/dbless.ts b/packages/taler-wallet-core/src/dbless.ts index ea5a42323..e0fe3d1ce 100644 --- a/packages/taler-wallet-core/src/dbless.ts +++ b/packages/taler-wallet-core/src/dbless.ts @@ -80,15 +80,6 @@ export interface CoinInfo { feeRefresh: string; } -export function generateReserveKeypair(): ReserveKeypair { - const priv = getRandomBytes(32); - const pub = eddsaGetPublic(priv); - return { - reservePriv: encodeCrock(priv), - reservePub: encodeCrock(pub), - }; -} - /** * Check the status of a reserve, use long-polling to wait * until the reserve actually has been created. diff --git a/packages/taler-wallet-core/src/operations/pay.ts b/packages/taler-wallet-core/src/operations/pay.ts index 97f38bae6..193ce54e2 100644 --- a/packages/taler-wallet-core/src/operations/pay.ts +++ b/packages/taler-wallet-core/src/operations/pay.ts @@ -927,7 +927,10 @@ async function startDownloadProposal( let noncePair: EddsaKeypair; if (noncePriv) { - noncePair = await ws.cryptoApi.eddsaGetPublic({ priv: noncePriv }); + noncePair = { + priv: noncePriv, + pub: (await ws.cryptoApi.eddsaGetPublic({ priv: noncePriv })).pub, + }; } else { noncePair = await ws.cryptoApi.createEddsaKeypair({}); } |