diff --git a/api/helpers.go b/api/helpers.go index 6dae6884c..8ad02d722 100644 --- a/api/helpers.go +++ b/api/helpers.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/iancoleman/strcase" + "go.vocdoni.io/dvote/crypto/nacl" "go.vocdoni.io/dvote/types" "go.vocdoni.io/dvote/vochain/indexer/indexertypes" "go.vocdoni.io/proto/build/go/models" @@ -143,3 +144,21 @@ func encodeEVMResultsArgs(electionId common.Hash, organizationId common.Address, } return fmt.Sprintf("0x%s", hex.EncodeToString(abiEncodedResultsBytes)), nil } + +// decryptVotePackage decrypts a vote package using the given private keys and indexes. +func decryptVotePackage(vp []byte, privKeys []string, indexes []uint32) ([]byte, error) { + for i := len(indexes) - 1; i >= 0; i-- { + if indexes[i] >= uint32(len(privKeys)) { + return nil, fmt.Errorf("invalid key index %d", indexes[i]) + } + priv, err := nacl.DecodePrivate(privKeys[indexes[i]]) + if err != nil { + return nil, fmt.Errorf("cannot decode encryption key with index %d: (%s)", indexes[i], err) + } + vp, err = priv.Decrypt(vp) + if err != nil { + return nil, fmt.Errorf("cannot decrypt votePackage: (%s)", err) + } + } + return vp, nil +} diff --git a/api/vote.go b/api/vote.go index 96041bfce..9cd774a04 100644 --- a/api/vote.go +++ b/api/vote.go @@ -7,6 +7,7 @@ import ( "go.vocdoni.io/dvote/httprouter" "go.vocdoni.io/dvote/httprouter/apirest" + "go.vocdoni.io/dvote/log" "go.vocdoni.io/dvote/types" "go.vocdoni.io/dvote/util" "go.vocdoni.io/dvote/vochain/indexer" @@ -120,13 +121,29 @@ func (a *API) getVoteHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) er Date: &voteData.Date, } - // If VotePackage is valid JSON, it's not encrypted, so we can include it. + // If VotePackage is valid JSON, it's not encrypted, so we can include it direcectly. if json.Valid(voteData.VotePackage) { vote.VotePackage = voteData.VotePackage } else { - evp, err := json.Marshal(map[string][]byte{"encrypted": voteData.VotePackage}) + // Otherwise, we need to decrypt it or include the encrypted version. + process, err := a.vocapp.State.Process(voteData.Meta.ProcessId, true) if err != nil { - return err + return ErrCantFetchElection.WithErr(err) + } + // Try to decrypt the vote package + var evp []byte + if len(process.EncryptionPrivateKeys) >= len(voteData.EncryptionKeyIndexes) { + evp, err = decryptVotePackage(voteData.VotePackage, process.EncryptionPrivateKeys, voteData.EncryptionKeyIndexes) + if err != nil { + log.Warnw("failed to decrypt vote package, skipping", "err", err) + } + } + // If decryption failed, include the encrypted version + if evp == nil { + evp, err = json.Marshal(map[string][]byte{"encrypted": voteData.VotePackage}) + if err != nil { + return ErrMarshalingJSONFailed + } } vote.VotePackage = evp }