diff --git a/e-voting-system/backend/routes/votes.py b/e-voting-system/backend/routes/votes.py index 5f53696..c43b86b 100644 --- a/e-voting-system/backend/routes/votes.py +++ b/e-voting-system/backend/routes/votes.py @@ -423,14 +423,17 @@ async def setup_election( # Générer les clés ElGamal si nécessaire if not election.public_key: elgamal = ElGamal() - election.public_key = elgamal.public_key_bytes + # Store as base64-encoded bytes (database column is LargeBinary) + # public_key_bytes returns UTF-8 "p:g:h", then encode to base64 + election.public_key = base64.b64encode(elgamal.public_key_bytes) + db.add(election) db.commit() return { "status": "initialized", "election_id": election_id, "public_keys": { - "elgamal_pubkey": base64.b64encode(election.public_key).decode() if election.public_key else None + "elgamal_pubkey": election.public_key.decode('utf-8') if election.public_key else None }, "blockchain_blocks": blockchain.get_block_count() } @@ -467,7 +470,7 @@ async def get_public_keys( ) return { - "elgamal_pubkey": base64.b64encode(election.public_key).decode() + "elgamal_pubkey": election.public_key.decode('utf-8') if election.public_key else None } diff --git a/e-voting-system/frontend/lib/crypto-client.ts b/e-voting-system/frontend/lib/crypto-client.ts index 65c7acd..0f981e0 100644 --- a/e-voting-system/frontend/lib/crypto-client.ts +++ b/e-voting-system/frontend/lib/crypto-client.ts @@ -67,52 +67,57 @@ export class ElGamalEncryption { } try { - // Decode the base64 public key - // Format from backend: base64("p:g:h") where p, g, h are decimal numbers - let publicKeyStr: string; - try { - publicKeyStr = atob(publicKeyBase64); - } catch (e) { - throw new Error(`Failed to decode public key from base64: ${e}`); - } + // Decode base64: base64("p:g:h") → "p:g:h" + const publicKeyStr = this._decodeBase64(publicKeyBase64); + const [p, g, h] = this._parsePublicKey(publicKeyStr); - // Parse public key (format: p:g:h separated by colons) - const publicKeyData = publicKeyStr.split(":"); + // Generate random r for encryption + const r = BigInt(Math.floor(Math.random() * (Number(p) - 2)) + 1); - if (publicKeyData.length < 3) { - throw new Error( - `Invalid public key format. Expected "p:g:h" but got "${publicKeyStr}"` - ); - } - - const p = BigInt(publicKeyData[0]); // Prime - const g = BigInt(publicKeyData[1]); // Generator - const h = BigInt(publicKeyData[2]); // Public key = g^x mod p - - // Validate parameters - if (p <= 0n || g <= 0n || h <= 0n) { - throw new Error("Invalid public key parameters: p, g, h must be positive"); - } - - // Generate random number for encryption - const maxRandom = Number(p) - 2; - if (maxRandom <= 0) { - throw new Error("Public key prime p is too small"); - } - const r = BigInt(Math.floor(Math.random() * maxRandom) + 1); - - // ElGamal encryption: (c1, c2) = (g^r mod p, m * h^r mod p) + // ElGamal: (c1, c2) = (g^r mod p, m * h^r mod p) const c1 = this._modPow(g, r, p); const c2 = (BigInt(vote) * this._modPow(h, r, p)) % p; - // Return as "c1:c2" in base64 - const encrypted = `${c1.toString()}:${c2.toString()}`; - return btoa(encrypted); + // Return encrypted as base64("c1:c2") + return btoa(`${c1}:${c2}`); } catch (error) { - console.error("ElGamal encryption failed:", error); - throw new Error( - `Encryption failed: ${error instanceof Error ? error.message : String(error)}` - ); + const msg = error instanceof Error ? error.message : String(error); + throw new Error(`ElGamal encryption failed: ${msg}`); + } + } + + /** + * Decode base64 string with clear error handling + */ + private static _decodeBase64(base64: string): string { + try { + return atob(base64); + } catch (e) { + throw new Error(`Invalid base64: ${base64.substring(0, 20)}... - ${e}`); + } + } + + /** + * Parse public key from "p:g:h" format + */ + private static _parsePublicKey(keyStr: string): [bigint, bigint, bigint] { + const parts = keyStr.split(":"); + if (parts.length !== 3) { + throw new Error(`Expected "p:g:h" format, got: ${keyStr}`); + } + + try { + const p = BigInt(parts[0]); + const g = BigInt(parts[1]); + const h = BigInt(parts[2]); + + if (p <= 0n || g <= 0n || h <= 0n) { + throw new Error("p, g, h must all be positive"); + } + + return [p, g, h]; + } catch (e) { + throw new Error(`Failed to parse key: ${e}`); } }