Chiffrement GPS
Le module GPS chiffre protege les coordonnees de localisation des ruchers lors des evaluations. Les coordonnees sont chiffrees cote client avec OpenPGP.js --- le serveur ne voit jamais les positions en clair. Seul l'eleveur (via son code PIN) et le moteur de calcul genetique BLUP (via sa cle privee) peuvent lire les coordonnees.
Page eleveur : Parametres > Securite > Protection GPS | Formulaire evaluation : capture automatique
Architecture
ELEVEUR SERVEUR (Supabase)
| |
|== CONSENTEMENT GDPR == |
|-- Bandeau opt-in (1ere fois) ---> profiles.gps_consent = true/false
|-- Detection mobile/desktop |
| |
|== SETUP PIN == |
|-- PIN 6+ chiffres |
|-- PBKDF2 + AES-256-GCM |
|-- Genere paire OpenPGP |
|-- Chiffre cle privee ---------> pgp_encrypted_private_key (blob)
|-- Cle publique ----------------> pgp_public_key
|-- 8 recovery codes ------------> gps_recovery_codes (hash + blob)
| |
|== EVALUATION (terrain) == |
|-- Consent check (gps_consent) |
|-- Mobile: GPS natif auto |
|-- Desktop: saisie manuelle |
| lat/lng + validation bornes |
|-- Chiffre avec cle publique ----> gps_encrypted (PGP armored)
|-- SHA-256 commitment -----------> gps_commitment
|-- Trigger verrouille -----------> gps_locked_at (immutable)
| |
|== CONSULTATION (carte) == |
|-- PIN --> AES --> cle privee |
|-- Dechiffre coords localement |
Composants techniques
Services cryptographiques
| Service | Fichier | Role |
|---|---|---|
| PIN Service | src/lib/gps/gps-pin-service.ts | PBKDF2 derivation, AES-256-GCM encrypt/decrypt, session 15min |
| PGP Service | src/lib/gps/gps-pgp-service.ts | OpenPGP encrypt multi-destinataires, signature EdDSA, dechiffrement |
Les deux services sont lazy-loaded (await import()) --- ils ne sont charges que dans le formulaire d'evaluation et la page parametres (~200KB openpgp.js).
Base de donnees
| Table/Colonne | Usage |
|---|---|
profiles.pgp_public_key | Cle publique OpenPGP (armored) |
profiles.pgp_encrypted_private_key | Cle privee chiffree AES (blob illisible sans PIN) |
profiles.pgp_key_fingerprint | 16 chars hex pour verification PIN |
profiles.pgp_pin_set | Boolean --- PIN configure ou non |
profiles.gps_consent | Boolean --- Consentement GDPR geolocalisation (opt-in explicite, default false) |
gps_recovery_codes | 8 codes de secours (hash SHA-256 + salt + blob AES) |
queen_evaluations.gps_encrypted | Bloc PGP armored (coords chiffrees) |
queen_evaluations.gps_signature | Signature EdDSA detachee |
queen_evaluations.gps_commitment | SHA-256 du plaintext (audit) |
queen_evaluations.gps_locked_at | Timestamp verrouillage (immutable) |
Triggers d'immutabilite
| Trigger | Comportement |
|---|---|
trg_lock_gps_update | Bloque toute modification de gps_encrypted, gps_commitment et gps_signature une fois gps_locked_at renseigne |
trg_lock_gps_delete | Bloque la suppression d'une evaluation dont le GPS est verrouille |
RPC Supabase
| Fonction | Usage |
|---|---|
setup_gps_pin() | Transaction atomique : met a jour le profil + insere 8 recovery codes. Valide le format PGP et fingerprint |
create_annual_evaluations() | Rotation annuelle : clone evaluations N-1 vers N avec GPS vierge. Idempotent (ON CONFLICT DO NOTHING) |
Consentement GDPR et detection device
Le module GPS inclut un bandeau de consentement GDPR (opt-in explicite) affiche lors du premier acces au formulaire d'evaluation. Le consentement reste local uniquement (state React) jusqu'a la sauvegarde reussie de l'evaluation --- profiles.gps_consent n'est persiste en DB qu'au moment du save. L'eleveur peut revoquer son consentement a tout moment via le bouton Desactiver la geolocalisation dans Parametres > Securite > Protection GPS.
Detection mobile/desktop : le hook useGpsCapture detecte le type d'appareil via navigator.userAgent et navigator.maxTouchPoints :
| Device | Comportement GPS | Source |
|---|---|---|
| Mobile (smartphone/tablette) | Capture automatique via navigator.geolocation | GPS natif |
| Desktop (ordinateur) | Saisie manuelle latitude/longitude | Champs input avec validation bornes (lat -90/+90, lng -180/+180) |
L'indicateur GPS sur le formulaire d'evaluation affiche le mode actif (automatique, manuel, ou desactive si consentement refuse). Les coordonnees manuelles sont soumises a la meme chaine de chiffrement OpenPGP que les coordonnees automatiques.
Cle BLUP
La paire de cles du moteur BLUP est generee une seule fois :
- Cle publique : stockee dans
NEXT_PUBLIC_BLUP_PGP_PUBLIC_KEY(.env.local+.envserveur). Exposee dans le bundle JS --- acceptable pour une cle publique - Cle privee : stockee dans
blup_engine/blup_private_key.asc(jamais commitee,.gitignore). Utilisee uniquement par le moteur Python pour dechiffrer les coords avant calcul de correction environnementale
Si la cle privee BLUP est compromise, toutes les coordonnees GPS chiffrees pour BLUP sont lisibles. Generer une nouvelle paire immediatement et re-chiffrer les evaluations concernees.
Cron rotation annuelle
Route : POST /api/cron/annual-evaluation-rotation
Auth : Bearer CRON_SECRET (timingSafeEqual)
Schedule : 1er janvier 00:00 UTC
Clone les evaluations de l'annee precedente vers la nouvelle annee avec GPS vierge. Idempotent grace a la contrainte UNIQUE(queen_id, eval_year).
# Test manuel
curl -sf -X POST -H "Authorization: Bearer $CRON_SECRET" \
https://beepass.io/api/cron/annual-evaluation-rotation
Securite
| Aspect | Implementation |
|---|---|
| Chiffrement | OpenPGP ECDH curve25519 (multi-destinataires : owner + BLUP) |
| Signature | OpenPGP EdDSA curve25519 detachee |
| Derivation PIN | PBKDF2-SHA256, 600 000 iterations (OWASP 2024) |
| Chiffrement cle privee | AES-256-GCM (Web Crypto API) |
| Recovery codes | Format XXXX-XXXX (4 bytes random), SHA-256 + salt 16 bytes |
| Session | Cle privee en memoire, expire apres 15 minutes |
| Immutabilite | Triggers Postgres BEFORE UPDATE/DELETE |
| Zero-knowledge | Supabase ne voit que des blobs AES et PGP illisibles |
Voir aussi
- Centre de securite --- outils d'analyse automatises
- WireGuard --- acces VPN admin