fix tipping planchet derivation

This commit is contained in:
Florian Dold 2021-01-06 17:06:19 +01:00
parent c032931f22
commit 458777c5a2
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
3 changed files with 19 additions and 18 deletions

View File

@ -340,10 +340,6 @@ export function createEcdheKeyPair(): EcdheKeyPair {
return { ecdhePriv, ecdhePub }; return { ecdhePriv, ecdhePub };
} }
export function createBlindingKeySecret(): Uint8Array {
return nacl.randomBytes(32);
}
export function hash(d: Uint8Array): Uint8Array { export function hash(d: Uint8Array): Uint8Array {
return nacl.hash(d); return nacl.hash(d);
} }

View File

@ -48,7 +48,6 @@ import {
encodeCrock, encodeCrock,
decodeCrock, decodeCrock,
createEddsaKeyPair, createEddsaKeyPair,
createBlindingKeySecret,
hash, hash,
rsaBlind, rsaBlind,
eddsaVerify, eddsaVerify,
@ -199,12 +198,11 @@ export class CryptoImplementation {
createTipPlanchet(req: DeriveTipRequest): DerivedTipPlanchet { createTipPlanchet(req: DeriveTipRequest): DerivedTipPlanchet {
const fc = setupTipPlanchet(decodeCrock(req.secretSeed), req.planchetIndex); const fc = setupTipPlanchet(decodeCrock(req.secretSeed), req.planchetIndex);
const denomPub = decodeCrock(req.denomPub); const denomPub = decodeCrock(req.denomPub);
const blindingFactor = createBlindingKeySecret();
const coinPubHash = hash(fc.coinPub); const coinPubHash = hash(fc.coinPub);
const ev = rsaBlind(coinPubHash, blindingFactor, denomPub); const ev = rsaBlind(coinPubHash, fc.bks, denomPub);
const tipPlanchet: DerivedTipPlanchet = { const tipPlanchet: DerivedTipPlanchet = {
blindingKey: encodeCrock(blindingFactor), blindingKey: encodeCrock(fc.bks),
coinEv: encodeCrock(ev), coinEv: encodeCrock(ev),
coinEvHash: encodeCrock(hash(ev)), coinEvHash: encodeCrock(hash(ev)),
coinPriv: encodeCrock(fc.coinPriv), coinPriv: encodeCrock(fc.coinPriv),

View File

@ -52,7 +52,7 @@ import { checkDbInvariant, checkLogicInvariant } from "../util/invariants";
import { TalerErrorCode } from "../TalerErrorCode"; import { TalerErrorCode } from "../TalerErrorCode";
import { initRetryInfo, updateRetryInfoTimeout } from "../util/retries"; import { initRetryInfo, updateRetryInfoTimeout } from "../util/retries";
import { j2s } from "../util/helpers"; import { j2s } from "../util/helpers";
import { DerivedTipPlanchet } from '../types/cryptoTypes'; import { DerivedTipPlanchet } from "../types/cryptoTypes";
const logger = new Logger("operations/tip.ts"); const logger = new Logger("operations/tip.ts");
@ -95,11 +95,11 @@ export async function prepareTip(
const walletTipId = encodeCrock(getRandomBytes(32)); const walletTipId = encodeCrock(getRandomBytes(32));
await updateWithdrawalDenoms(ws, tipPickupStatus.exchange_url); await updateWithdrawalDenoms(ws, tipPickupStatus.exchange_url);
const denoms = await getPossibleWithdrawalDenoms(ws, tipPickupStatus.exchange_url); const denoms = await getPossibleWithdrawalDenoms(
const selectedDenoms = await selectWithdrawalDenominations( ws,
amount, tipPickupStatus.exchange_url,
denoms
); );
const selectedDenoms = selectWithdrawalDenominations(amount, denoms);
const secretSeed = encodeCrock(getRandomBytes(64)); const secretSeed = encodeCrock(getRandomBytes(64));
@ -213,7 +213,7 @@ async function processTipImpl(
const planchets: DerivedTipPlanchet[] = []; const planchets: DerivedTipPlanchet[] = [];
// Planchets in the form that the merchant expects // Planchets in the form that the merchant expects
const planchetsDetail: TipPlanchetDetail[] = []; const planchetsDetail: TipPlanchetDetail[] = [];
const denomForPlanchet: { [index: number]: DenominationRecord} = []; const denomForPlanchet: { [index: number]: DenominationRecord } = [];
for (const dh of denomsForWithdraw.selectedDenoms) { for (const dh of denomsForWithdraw.selectedDenoms) {
const denom = await ws.db.get(Stores.denominations, [ const denom = await ws.db.get(Stores.denominations, [
@ -222,11 +222,14 @@ async function processTipImpl(
]); ]);
checkDbInvariant(!!denom, "denomination should be in database"); checkDbInvariant(!!denom, "denomination should be in database");
for (let i = 0; i < dh.count; i++) { for (let i = 0; i < dh.count; i++) {
const p = await ws.cryptoApi.createTipPlanchet({ const deriveReq = {
denomPub: denom.denomPub, denomPub: denom.denomPub,
planchetIndex: planchets.length, planchetIndex: planchets.length,
secretSeed: tipRecord.secretSeed, secretSeed: tipRecord.secretSeed,
}); };
logger.trace(`deriving tip planchet: ${j2s(deriveReq)}`)
const p = await ws.cryptoApi.createTipPlanchet(deriveReq);
logger.trace(`derive result: ${j2s(p)}`);
denomForPlanchet[planchets.length] = denom; denomForPlanchet[planchets.length] = denom;
planchets.push(p); planchets.push(p);
planchetsDetail.push({ planchetsDetail.push({
@ -242,14 +245,18 @@ async function processTipImpl(
); );
const req = { planchets: planchetsDetail }; const req = { planchets: planchetsDetail };
logger.trace(`sending tip request: ${j2s(req)}`);
const merchantResp = await ws.http.postJson(tipStatusUrl.href, req); const merchantResp = await ws.http.postJson(tipStatusUrl.href, req);
logger.trace(`got tip response, status ${merchantResp.status}`);
// Hide transient errors. // Hide transient errors.
if ( if (
tipRecord.retryInfo.retryCounter < 5 && tipRecord.retryInfo.retryCounter < 5 &&
merchantResp.status >= 500 && ((merchantResp.status >= 500 && merchantResp.status <= 599) ||
merchantResp.status <= 599 merchantResp.status === 424)
) { ) {
logger.trace(`got transient tip error`);
const err = makeErrorDetails( const err = makeErrorDetails(
TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR, TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR,
"tip pickup failed (transient)", "tip pickup failed (transient)",