Canaux classiques : un temps d’exécution qui dépend de bits secrets (Kocher, 1996), des accès mémoire dépendant de secrets et observés via des caches partagés (Flush+Reload et techniques similaires), les traces de consommation et les traces électromagnétiques des cartes à puce et des microcontrôleurs, et l’injection de fautes (perturbations de tension ou d’horloge, lasers, Rowhammer) qui amène un appareil à produire une signature erronée à partir de laquelle la clé peut être calculée. Les attaques temporelles à distance sont praticables elles aussi : Lucky Thirteen (2013) a attaqué par le réseau les vérifications du remplissage CBC de TLS.
La cryptographie asymétrique est particulièrement exposée, car la multiplication scalaire et l’exponentiation modulaire bouclent sur les bits de la clé ou du nonce. Les parades sont le code en temps constant (sans branchements, indices mémoire ni instructions à durée variable qui dépendent de secrets), le masquage (blinding) des scalaires et des messages, les formules complètes avec des échelles uniformes et, contre les fautes, la vérification d’une signature avant de la diffuser ainsi que les nonces hedged.
Pour les développeurs, la règle pratique est d’utiliser des bibliothèques maintenues qui ont fait leurs preuves en matière de temps constant (BoringSSL, OpenSSL, libsodium, le paquet crypto de Go, RustCrypto, les bibliothèques noble) et de ne jamais réimplémenter l’arithmétique. Dans les langages dotés d’un compilateur JIT ou d’un ramasse-miettes, le comportement en temps constant n’est assuré qu’au mieux, ce qui compte sur les hôtes partagés et dans les navigateurs.