- Add checks for the context and manifest matching manifesthash values (#306)

- Add C++ and C# unit tests
This commit is contained in:
Steve Maier 2022-06-15 10:11:47 -04:00 коммит произвёл GitHub
Родитель 6ba0bcab88
Коммит 62d1d030d3
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 138 добавлений и 62 удалений

Просмотреть файл

@ -154,5 +154,48 @@ namespace ElectionGuard.Encrypt.Tests
Assert.That(constants.Contains(Constants.G.ToHex()));
}
[Test]
public void Test_EncryptMediator_Hashes_Match()
{
var keypair = ElGamalKeyPair.FromSecret(Constants.TWO_MOD_Q);
var manifest = ManifestGenerator.GetManifestFromFile();
var internalManifest = new InternalManifest(manifest);
var context = new CiphertextElectionContext(
1UL, 1UL, keypair.PublicKey, Constants.TWO_MOD_Q, internalManifest.ManifestHash); // make a context with the correct manifesthash
var device = new EncryptionDevice(12345UL, 23456UL, 34567UL, "Location");
try
{
var mediator = new EncryptionMediator(internalManifest, context, device);
Assert.IsNotNull(mediator); // should not be null if it gets created
}
catch (Exception ex)
{
// if there is an exception then the manifest hash would not be equal
Assert.AreNotEqual(context.ManifestHash.ToHex(), internalManifest.ManifestHash.ToHex());
}
}
[Test]
public void Test_EncryptMediator_Hashes_Dont_Match()
{
var keypair = ElGamalKeyPair.FromSecret(Constants.TWO_MOD_Q);
var manifest = ManifestGenerator.GetManifestFromFile();
var internalManifest = new InternalManifest(manifest);
var context = new CiphertextElectionContext(
1UL, 1UL, keypair.PublicKey, Constants.TWO_MOD_Q, Constants.ONE_MOD_Q); // make a context with a different manifesthash
var device = new EncryptionDevice(12345UL, 23456UL, 34567UL, "Location");
try
{
var mediator = new EncryptionMediator(internalManifest, context, device);
Assert.IsNull(mediator); // should not be created, so null at best
}
catch (Exception ex)
{
// if there is an exception then the manifest hash would not be equal
Assert.AreNotEqual(context.ManifestHash.ToHex(), internalManifest.ManifestHash.ToHex());
}
}
}
}

Просмотреть файл

@ -110,6 +110,11 @@ namespace ElectionGuard
CiphertextElectionContext context,
EncryptionDevice device)
{
if (manifest.ManifestHash.ToHex() != context.ManifestHash.ToHex())
{
Status.ELECTIONGUARD_STATUS_ERROR_INVALID_ARGUMENT.ThrowIfError();
}
var status = NativeInterface.EncryptionMediator.New(
manifest.Handle, context.Handle, device.Handle, out Handle);
status.ThrowIfError();

Просмотреть файл

@ -5,16 +5,16 @@
#include "electionguard/ballot_code.hpp"
#include "electionguard/elgamal.hpp"
#include "electionguard/hash.hpp"
#include "electionguard/precompute_buffers.hpp"
#include "log.hpp"
#include "nonces.hpp"
#include "serialize.hpp"
#include "utils.hpp"
#include "electionguard/precompute_buffers.hpp"
#include <nlohmann/json.hpp>
#include <algorithm>
#include <future>
#include <iostream>
#include <nlohmann/json.hpp>
extern "C" {
#include "../karamel/Hacl_Bignum4096.h"
@ -90,18 +90,10 @@ namespace electionguard
return DeviceSerializer::fromBson(move(data));
}
uint64_t EncryptionDevice::getDeviceUuid() const {
return pimpl->deviceUuid;
}
uint64_t EncryptionDevice::getSessionUuid() const {
return pimpl->sessionUuid;
}
uint64_t EncryptionDevice::getLaunchCode() const {
return pimpl->launchCode;
}
std::string EncryptionDevice::getLocation() const {
return pimpl->location;
}
uint64_t EncryptionDevice::getDeviceUuid() const { return pimpl->deviceUuid; }
uint64_t EncryptionDevice::getSessionUuid() const { return pimpl->sessionUuid; }
uint64_t EncryptionDevice::getLaunchCode() const { return pimpl->launchCode; }
std::string EncryptionDevice::getLocation() const { return pimpl->location; }
#pragma endregion
@ -127,6 +119,11 @@ namespace electionguard
const EncryptionDevice &encryptionDevice)
: pimpl(new Impl(internalManifest, context, encryptionDevice))
{
if (internalManifest.getManifestHash()->toHex() != context.getManifestHash()->toHex()) {
throw invalid_argument("manifest and context do not match hashes manifest:" +
internalManifest.getManifestHash()->toHex() +
" context:" + context.getManifestHash()->toHex());
}
}
EncryptionMediator::~EncryptionMediator() = default;
@ -296,8 +293,8 @@ namespace electionguard
auto pubkey_to_exp = triple1->get_pubkey_to_exp();
// Generate the encryption using precomputed values
ciphertext = elgamalEncrypt_with_precomputed(selection.getVote(),
*g_to_exp, *pubkey_to_exp);
ciphertext =
elgamalEncrypt_with_precomputed(selection.getVote(), *g_to_exp, *pubkey_to_exp);
if (ciphertext == nullptr) {
throw runtime_error("encryptSelection:: Error generating ciphertext");
}
@ -309,12 +306,10 @@ namespace electionguard
encrypted = CiphertextBallotSelection::make_with_precomputed(
selection.getObjectId(), description.getSequenceOrder(), *descriptionHash,
move(ciphertext), cryptoExtendedBaseHash, selection.getVote(),
move(precomputedTwoTriplesAndAQuad),
isPlaceholder, true);
move(precomputedTwoTriplesAndAQuad), isPlaceholder, true);
} else {
// Generate the encryption
ciphertext =
elgamalEncrypt(selection.getVote(), *selectionNonce, elgamalPublicKey);
ciphertext = elgamalEncrypt(selection.getVote(), *selectionNonce, elgamalPublicKey);
if (ciphertext == nullptr) {
throw runtime_error("encryptSelection:: Error generating ciphertext");
}
@ -410,8 +405,7 @@ namespace electionguard
}
unique_ptr<CiphertextBallotContest>
encryptContest(const PlaintextBallotContest &contest,
const InternalManifest &internalManifest,
encryptContest(const PlaintextBallotContest &contest, const InternalManifest &internalManifest,
const ContestDescriptionWithPlaceholders &description,
const ElementModP &elgamalPublicKey, const ElementModQ &cryptoExtendedBaseHash,
const ElementModQ &nonceSeed, bool shouldVerifyProofs /* = true */)
@ -419,8 +413,8 @@ namespace electionguard
{
// Validate Input
bool supportOvervotes = true;
eg_valid_contest_return_type_t is_valid_contest =
contest.isValid(description.getObjectId(), description.getSelections().size(),
eg_valid_contest_return_type_t is_valid_contest = contest.isValid(
description.getObjectId(), description.getSelections().size(),
description.getNumberElected(), description.getVotesAllowed(), supportOvervotes);
if ((is_valid_contest != SUCCESS) && (is_valid_contest != OVERVOTE)) {
throw invalid_argument("the plaintext contest was invalid");
@ -471,8 +465,8 @@ namespace electionguard
// if the is an overvote then we need to make all the selection votes 0
if (is_valid_contest == OVERVOTE) {
duplicate_selection = make_unique<PlaintextBallotSelection>(
selection_ptr->getObjectId(), 0, false);
duplicate_selection =
make_unique<PlaintextBallotSelection>(selection_ptr->getObjectId(), 0, false);
selection_ptr = duplicate_selection.get();
}
@ -516,9 +510,8 @@ namespace electionguard
make_unique<Nonces>(*sharedNonce->clone(), "constant-extended-data");
auto extendedDataNonce = noncesForExtendedData->get(0);
vector<uint8_t> extendedData_plaintext((uint8_t *)&extendedData.front(),
(uint8_t *)&extendedData.front() +
extendedData.size());
vector<uint8_t> extendedData_plaintext(
(uint8_t *)&extendedData.front(), (uint8_t *)&extendedData.front() + extendedData.size());
// Perform HashedElGamalCiphertext calculation
unique_ptr<HashedElGamalCiphertext> hashedElGamal =
@ -536,8 +529,8 @@ namespace electionguard
auto encryptedContest = CiphertextBallotContest::make(
contest.getObjectId(), description.getSequenceOrder(), *descriptionHash,
move(encryptedSelections), elgamalPublicKey, cryptoExtendedBaseHash, *chaumPedersenNonce,
description.getNumberElected(), sharedNonce->clone(), nullptr,
nullptr, move(hashedElGamal));
description.getNumberElected(), sharedNonce->clone(), nullptr, nullptr,
move(hashedElGamal));
if (encryptedContest == nullptr || encryptedContest->getProof() == nullptr) {
throw runtime_error("encryptedContest:: Error constructing encrypted constest");
@ -574,8 +567,8 @@ namespace electionguard
hasContest = true;
auto encrypted = encryptContest(
contest.get(), internalManifest, description.get(),
*context.getElGamalPublicKey(),
*context.getCryptoExtendedBaseHash(), nonceSeed, shouldVerifyProofs);
*context.getElGamalPublicKey(), *context.getCryptoExtendedBaseHash(),
nonceSeed, shouldVerifyProofs);
encryptedContests.push_back(move(encrypted));
break;

Просмотреть файл

@ -262,7 +262,8 @@ TEST_CASE("Encrypt full PlaintextBallot with WriteIn and Overvote with Encryptio
auto mediator = make_unique<EncryptionMediator>(*internal, *context, *device);
// Act
string plaintextBallot_json = string("{\"object_id\": \"03a29d15-667c-4ac8-afd7-549f19b8e4eb\","
string plaintextBallot_json = string(
"{\"object_id\": \"03a29d15-667c-4ac8-afd7-549f19b8e4eb\","
"\"style_id\": \"jefferson-county-ballot-style\", \"contests\": [ {\"object_id\":"
"\"justice-supreme-court\", \"sequence_order\": 0, \"ballot_selections\": [{"
"\"object_id\": \"john-adams-selection\", \"sequence_order\": 0, \"vote\": 1,"
@ -438,3 +439,37 @@ TEST_CASE("Encrypt simple ballot from file succeeds with precomputed values")
*context->getCryptoExtendedBaseHash()) == true);
PrecomputeBufferContext::empty_queues();
}
TEST_CASE("Create EncryptionMediator with same manifest hash")
{
auto secret = ElementModQ::fromHex(a_fixed_secret);
auto keypair = ElGamalKeyPair::fromSecret(*secret);
auto manifest = ManifestGenerator::getJeffersonCountyManifest_Minimal();
auto internal = make_unique<InternalManifest>(*manifest);
auto context = make_unique<CiphertextElectionContext>(
1UL, 1UL, keypair->getPublicKey()->clone(), Q().clone(),
internal.get()->getManifestHash()->clone(), Q().clone(), Q().clone());
auto device = make_unique<EncryptionDevice>(12345UL, 23456UL, 34567UL, "Location");
auto mediator = make_unique<EncryptionMediator>(*internal, *context, *device);
CHECK(mediator != nullptr);
}
TEST_CASE("Create EncryptionMediator with different manifest hash")
{
auto secret = ElementModQ::fromHex(a_fixed_secret);
auto keypair = ElGamalKeyPair::fromSecret(*secret);
auto manifest = ManifestGenerator::getJeffersonCountyManifest_Minimal();
auto internal = make_unique<InternalManifest>(*manifest);
auto context =
make_unique<CiphertextElectionContext>(1UL, 1UL, keypair->getPublicKey()->clone(),
Q().clone(), Q().clone(), Q().clone(), Q().clone());
auto device = make_unique<EncryptionDevice>(12345UL, 23456UL, 34567UL, "Location");
try {
auto mediator = make_unique<EncryptionMediator>(*internal, *context, *device);
CHECK(mediator == nullptr);
} catch (const std::exception &e) {
CHECK(internal->getManifestHash()->toHex() != context->getManifestHash()->toHex());
}
}