diff options
Diffstat (limited to 'packages/taler-wallet-core/src/crypto')
-rw-r--r-- | packages/taler-wallet-core/src/crypto/cryptoImplementation.ts | 159 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/crypto/workers/synchronousWorker.ts | 23 |
2 files changed, 155 insertions, 27 deletions
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, + }; + }; } } |