Contactez-nous

Cryptographie avec la bibliothèque crypto

Explorez la bibliothèque crypto de Go : chiffrement symétrique/asymétrique, hachage, signatures, nombres aléatoires sécurisés, TLS/SSL et exemples de code pour sécuriser vos applications Go.

Exploration approfondie de la bibliothèque crypto de Go : Un arsenal de sécurité

La bibliothèque standard crypto de Go est un véritable arsenal de sécurité, offrant un ensemble complet et puissant d'algorithmes cryptographiques, de fonctions, et d'outils pour mettre en oeuvre des mécanismes de sécurité robustes dans vos applications Go. Que vous ayez besoin de chiffrer des données sensibles, de hacher des mots de passe, de créer des signatures numériques, de générer des nombres aléatoires sécurisés, ou de sécuriser les communications réseau avec TLS/SSL, la bibliothèque crypto de Go vous fournit les briques de base nécessaires pour construire des applications Go sécurisées et dignes de confiance.

Ce chapitre vous propose une exploration approfondie de la bibliothèque crypto de Go, en détaillant les sous-packages principaux et leurs fonctionnalités clés : crypto/aes (chiffrement symétrique AES), crypto/rsa (chiffrement asymétrique RSA), crypto/elliptic (cryptographie elliptique), crypto/sha256 et crypto/sha512 (fonctions de hachage SHA-2), golang.org/x/crypto/bcrypt et golang.org/x/crypto/argon2 (fonctions de hachage de mots de passe), crypto/rand (génération de nombres aléatoires sécurisés), et crypto/tls (TLS/SSL pour les communications réseau sécurisées). Pour chaque sous-package, nous examinerons les algorithmes et les fonctions disponibles, leurs cas d'utilisation typiques, des exemples de code concrets, et les bonnes pratiques pour les utiliser correctement et en toute sécurité. L'objectif est de vous fournir un guide expert et pratique pour maîtriser la bibliothèque crypto de Go et l'utiliser efficacement pour sécuriser vos applications Go à tous les niveaux.

Chiffrement symétrique avec crypto/aes : AES et modes de chiffrement

Le package crypto/aes de Go fournit l'implémentation de l'algorithme de chiffrement symétrique AES (Advanced Encryption Standard), l'algorithme de chiffrement symétrique le plus largement utilisé et considéré comme très robuste et performant. Le chiffrement symétrique (ou chiffrement à clé secrète) utilise la même clé pour le chiffrement (transformation des données en texte chiffré - ciphertext) et le déchiffrement (transformation du ciphertext en texte clair - plaintext). Le chiffrement symétrique est généralement plus rapide et plus efficace que le chiffrement asymétrique, et est bien adapté pour le chiffrement de volumes importants de données.

Algorithme AES (Advanced Encryption Standard) :

AES est un algorithme de chiffrement par blocs symétrique, standardisé par le NIST (National Institute of Standards and Technology) et largement adopté dans le monde entier pour le chiffrement de données sensibles. AES est considéré comme un algorithme de chiffrement très sûr et robuste contre les attaques connues (lorsqu'il est utilisé correctement avec des clés suffisamment longues et des modes de chiffrement appropriés). AES supporte différentes tailles de clés (128 bits, 192 bits, 256 bits), la taille de clé AES-256 (256 bits) étant généralement recommandée pour une sécurité maximale.

Modes de chiffrement par blocs (Block Cipher Modes) :

L'algorithme AES est un chiffre par blocs (block cipher) : il chiffre les données par blocs de taille fixe (128 bits = 16 octets pour AES). Pour chiffrer des données de taille variable (supérieure à la taille des blocs), il est nécessaire d'utiliser un mode de chiffrement par blocs (block cipher mode), qui définit comment l'algorithme de chiffrement par blocs est appliqué à des blocs de données successifs et comment les blocs sont chaînés entre eux.

Modes de chiffrement par blocs courants supportés par crypto/aes :

  • cipher.NewCBCEncrypter (CBC - Cipher Block Chaining) : Mode de chiffrement par blocs CBC (Cipher Block Chaining). Un des modes de chiffrement les plus anciens et les plus utilisés. En mode CBC, chaque bloc de plaintext est XORé avec le ciphertext du bloc précédent avant d'être chiffré, créant une dépendance en chaîne entre les blocs (d'où le nom "chaining"). Le mode CBC nécessite un vecteur d'initialisation (IV - Initialization Vector) aléatoire et unique pour chaque chiffrement, qui doit être transmis avec le ciphertext (généralement préfixé au ciphertext). CBC est considéré comme sécurisé, mais il est séquentiel (le chiffrement et le déchiffrement doivent être effectués bloc par bloc, en séquence) et n'offre pas de protection intégrée contre les attaques d'intégrité.
  • cipher.NewCTR (CTR - Counter Mode) : Mode de chiffrement par blocs CTR (Counter Mode). Un mode de chiffrement moderne et performant, qui transforme un chiffre par blocs (comme AES) en un chiffre de flux (stream cipher). En mode CTR, un compteur est chiffré avec le chiffre par blocs, et le résultat est XORé avec le plaintext pour produire le ciphertext. Le mode CTR permet le chiffrement et le déchiffrement en parallèle, et offre une meilleure performance que les modes séquentiels comme CBC. CTR nécessite également un vecteur d'initialisation (IV) aléatoire et unique pour chaque chiffrement (appelé nonce dans le contexte de CTR), qui doit être transmis avec le ciphertext. CTR est considéré comme sécurisé et offre une bonne performance et flexibilité.
  • cipher.NewGCM (GCM - Galois/Counter Mode) : Mode de chiffrement par blocs GCM (Galois/Counter Mode). Un mode de chiffrement authentifié (Authenticated Encryption with Associated Data - AEAD) moderne, performant, et fortement recommandé pour la plupart des applications. GCM combine le chiffrement en mode CTR avec un mécanisme d'authentification basé sur le code d'authentification de message GMAC (Galois Message Authentication Code). GCM assure à la fois la confidentialité (chiffrement) et l'intégrité (authentification) des données, et détecte toute modification ou altération du ciphertext. GCM est très performant (grâce au mode CTR et à l'implémentation optimisée de GMAC) et est considéré comme sécurisé et robuste contre les attaques connues. GCM nécessite également un nonce (IV) aléatoire et unique pour chaque chiffrement, et permet de transmettre des données authentifiées additionnelles (AAD - Associated Authenticated Data) qui ne sont pas chiffrées mais sont incluses dans le calcul de l'authentification (utile pour protéger l'intégrité des headers ou des métadonnées associées aux données chiffrées). Privilégiez l'utilisation du mode GCM pour le chiffrement AES dans la plupart des applications Go, en raison de sa sécurité, de sa performance, et de sa fonctionnalité d'authentification intégrée.

Exemple de chiffrement AES-256 en mode GCM avec crypto/aes :

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "encoding/hex"
    "fmt"
    "io"
    "log"
    "os"
)

func main() {
    // Clé AES-256 (32 octets = 256 bits) - Générer une clé aléatoire sécurisée
    cléAES := make([]byte, 32)
    if _, err := io.ReadFull(rand.Reader, cléAES); err != nil {
        log.Fatal(err)
    }

    // Créer le cipher AES en mode GCM (Galois/Counter Mode)
    block, err := aes.NewCipher(cléAES)
    if err != nil {
        log.Fatal(err)
    }
    gcm, err := cipher.NewGCM(block)
    if err != nil {
        log.Fatal(err)
    }

    // Nonce (IV) GCM - Générer un nonce aléatoire unique (taille recommandée par GCM)
    nonce := make([]byte, gcm.NonceSize())
    if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
        log.Fatal(err)
    }

    // Plaintext (données à chiffrer)
    plaintext := []byte("Données très sensibles à chiffrer avec AES-GCM")

    // Chiffrer avec AES-GCM (chiffrement authentifié)
    ciphertext := gcm.Seal(nonce, nonce, plaintext, nil) // AAD (données authentifiées additionnelles) = nil dans cet exemple

    fmt.Printf("Texte clair : %s\n", plaintext)
    fmt.Printf("Texte chiffré (hex) : %x\n", ciphertext)

    // Déchiffrer avec AES-GCM
    nonceDéchiffrement, ciphertextDéchiffrement := ciphertext[:gcm.NonceSize()], ciphertext[gcm.NonceSize():]
    plaintextDéchiffré, err := gcm.Open(nil, nonceDéchiffrement, ciphertextDéchiffrement, nil) // AAD = nil (doit correspondre à la valeur utilisée lors du chiffrement)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Texte déchiffré : %s\n", plaintextDéchiffré)
}

Cet exemple illustre le chiffrement AES-256 en mode GCM avec crypto/aes, en utilisant les fonctions aes.NewCipher et cipher.NewGCM pour créer le cipher AES-GCM, gcm.Seal pour chiffrer les données (avec authentification), et gcm.Open pour déchiffrer les données et vérifier l'authentification. Le mode GCM est fortement recommandé pour le chiffrement AES en Go, car il offre à la fois la confidentialité et l'intégrité des données chiffrées.

Chiffrement asymétrique avec crypto/rsa : RSA et clés publiques/privées

Le package crypto/rsa de Go fournit l'implémentation de l'algorithme de chiffrement asymétrique RSA (Rivest-Shamir-Adleman), l'un des algorithmes de chiffrement asymétrique les plus anciens et les plus largement utilisés. Le chiffrement asymétrique (ou chiffrement à clé publique) utilise une paire de clés : une clé publique (publique et partageable) et une clé privée (secrète et à garder confidentielle).

Algorithme RSA (Rivest-Shamir-Adleman) :

RSA est un algorithme de chiffrement asymétrique basé sur la difficulté mathématique de la factorisation des grands nombres premiers. RSA est utilisé pour différentes opérations cryptographiques :

  • Chiffrement et déchiffrement : Le chiffrement RSA permet de chiffrer des données avec la clé publique d'un destinataire (chiffrement à clé publique) et de les déchiffrer uniquement avec la clé privée correspondante (déchiffrement à clé privée). Seul le détenteur de la clé privée peut déchiffrer les données chiffrées avec la clé publique correspondante, assurant la confidentialité des données. Le chiffrement RSA est généralement utilisé pour chiffrer des petits volumes de données (clés de session, secrets, etc.), car il est plus lent que le chiffrement symétrique pour les grands volumes de données.
  • Signatures numériques : Le chiffrement RSA permet de créer des signatures numériques pour vérifier l'authenticité et l'intégrité des données. Un émetteur peut signer des données avec sa clé privée (signature à clé privée), et n'importe quel destinataire peut vérifier la signature avec la clé publique correspondante. La signature numérique garantit que les données proviennent bien de l'émetteur (authentification) et qu'elles n'ont pas été modifiées en transit (intégrité). Les signatures numériques RSA sont largement utilisées pour la signature de code, les certificats numériques, l'authentification, et d'autres applications de sécurité.
  • Echange de clés (Key Exchange) : RSA peut également être utilisé pour l'échange de clés cryptographiques entre deux parties, permettant d'établir un canal de communication chiffré et sécurisé (par exemple, pour l'échange de clés de session pour le chiffrement symétrique).

Génération de clés RSA avec crypto/rsa : rsa.GenerateKey

Pour utiliser le chiffrement RSA, vous devez d'abord générer une paire de clés RSA : une clé privée (à garder secrète) et une clé publique (à partager publiquement). La fonction rsa.GenerateKey(rand io.Reader, bits int) (*PrivateKey, error) du package crypto/rsa permet de générer une nouvelle paire de clés RSA.

package main

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "encoding/pem"
    "log"
    "os"
)

func genererCleRSA() (*rsa.PrivateKey, *rsa.PublicKey) {
    clePrivee, err := rsa.GenerateKey(rand.Reader, 2048) // Génération d'une clé privée RSA-2048 bits
    if err != nil {
        log.Fatalf("Erreur lors de la génération de la clé RSA: %v", err)
    }
    clePublique := &clePrivee.PublicKey // Extraction de la clé publique à partir de la clé privée
    return clePrivee, clePublique
}

func sauvegarderClePriveePEM(clePrivee *rsa.PrivateKey, nomFichier string) {
    // ... (code pour sérialiser la clé privée RSA au format PEM et la sauvegarder dans un fichier) ...
}

func sauvegarderClePubliquePEM(clePublique *rsa.PublicKey, nomFichier string) {
    // ... (code pour sérialiser la clé publique RSA au format PEM et la sauvegarder dans un fichier) ...
}

func main() {
    clePrivee, clePublique := genererCleRSA()

    // Sauvegarder la clé privée et la clé publique au format PEM (pour stockage ou échange)
    sauvegarderClePriveePEM(clePrivee, "cle_privee.pem")
    sauvegarderClePubliquePEM(clePublique, "cle_publique.pem")

    log.Println("Paire de clés RSA générée et sauvegardée (cle_privee.pem, cle_publique.pem).")
}

Chiffrement et déchiffrement RSA avec crypto/rsa : rsa.EncryptPKCS1v15 et rsa.DecryptPKCS1v15

Le package crypto/rsa fournit les fonctions rsa.EncryptPKCS1v15(rand io.Reader, pub *PublicKey, plaintext []byte) ([]byte, error) pour le chiffrement RSA (avec padding PKCS#1 v1.5) et rsa.DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) ([]byte, error) pour le déchiffrement RSA (avec padding PKCS#1 v1.5).

Signature et vérification de signature RSA avec crypto/rsa : rsa.SignPKCS1v15 et rsa.VerifyPKCS1v15

Le package crypto/rsa fournit également les fonctions rsa.SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) pour la création de signatures numériques RSA (avec padding PKCS#1 v1.5) et rsa.VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error pour la vérification des signatures numériques RSA (avec padding PKCS#1 v1.5). Pour signer des données avec RSA, vous devez d'abord hacher les données avec une fonction de hachage cryptographique (comme SHA-256) et signer le hash des données avec la clé privée RSA. Pour vérifier la signature, vous devez hacher à nouveau les données, et vérifier que la signature correspond au hash des données et à la clé publique RSA de l'émetteur.

Bonnes pratiques pour l'utilisation de la cryptographie avec la bibliothèque crypto

Pour utiliser la cryptographie de manière sécurisée et efficace avec la bibliothèque crypto de Go, et éviter les erreurs de sécurité courantes, voici quelques bonnes pratiques essentielles à suivre :

  • Utiliser des algorithmes cryptographiques robustes et éprouvés : Privilégiez l'utilisation d'algorithmes cryptographiques robustes et éprouvés, qui sont considérés comme sûrs et résistants aux attaques connues par la communauté cryptographique. Pour le chiffrement symétrique, utilisez AES-256 (mode GCM recommandé) ou ChaCha20-Poly1305. Pour le chiffrement asymétrique, utilisez RSA-2048 bits ou plus (ou de préférence la cryptographie elliptique - ECC, voir point suivant). Pour le hachage de mots de passe, utilisez argon2 (recommandé) ou bcrypt. Pour les fonctions de hachage général, utilisez SHA-256 ou SHA-512 (famille SHA-2). Evitez d'utiliser des algorithmes cryptographiques obsolètes, faibles, ou non recommandés pour la sécurité (comme DES, RC4, MD5, SHA-1), sauf dans des cas très spécifiques et justifiés (compatibilité legacy, etc.) et avec une connaissance approfondie des risques et des limitations de ces algorithmes.
  • Privilégier la cryptographie authentifiée (AEAD) pour le chiffrement symétrique : Pour le chiffrement symétrique, utilisez des modes de chiffrement authentifiés (AEAD - Authenticated Encryption with Associated Data) comme AES-GCM (Galois/Counter Mode) ou ChaCha20-Poly1305. Les modes AEAD combinent le chiffrement (confidentialité) et l'authentification (intégrité et authenticité) des données en une seule opération, offrant une sécurité plus forte et plus facile à utiliser que les modes de chiffrement non authentifiés (comme CBC ou CTR) qui nécessitent d'ajouter un mécanisme d'authentification séparé (MAC - Message Authentication Code). AES-GCM est fortement recommandé pour la plupart des applications Go qui nécessitent du chiffrement symétrique.
  • Générer des clés cryptographiques et des nonces (IVs) aléatoires sécurisés (crypto/rand) : Utilisez toujours le package crypto/rand de Go pour générer des clés cryptographiques (clés AES, clés RSA, clés ECC), des sels pour le hachage de mots de passe, des vecteurs d'initialisation (IVs) pour le chiffrement symétrique, des nonces pour les protocoles d'authentification, et tout autre type de secret ou de valeur aléatoire utilisé pour la sécurité. crypto/rand fournit une source d'aléa cryptographiquement sécurisée et imprévisible, essentielle pour la robustesse des algorithmes cryptographiques. Evitez d'utiliser math/rand pour la cryptographie, car il n'est pas cryptographiquement sécurisé et est prévisible.
  • Stocker et gérer les clés cryptographiques et les secrets de manière sécurisée (Secrets Vaults) : Ne stockez jamais les clés cryptographiques, les mots de passe, les clés API, ou tout autre type de secret directement dans votre code source, les fichiers de configuration, ou les variables d'environnement non sécurisées. Utilisez des coffres-forts à secrets (secrets vaults) dédiés pour le stockage sécurisé, la gestion, et l'accès contrôlé aux secrets (voir chapitre précédent sur la gestion sécurisée des données sensibles).
  • Suivre les recommandations et les bonnes pratiques de la cryptographie moderne : Restez informé des bonnes pratiques de la cryptographie moderne et des recommandations de sécurité de la communauté cryptographique. Utilisez des bibliothèques cryptographiques éprouvées et validées (comme la bibliothèque crypto de Go). Evitez d'implémenter vos propres algorithmes cryptographiques "maison" ou de réinventer la roue, sauf si vous êtes un expert en cryptographie et que vous avez des raisons très spécifiques de le faire. Consultez régulièrement les mises à jour de sécurité et les bulletins de sécurité des bibliothèques cryptographiques que vous utilisez, et mettez à jour vos dépendances cryptographiques si nécessaire pour corriger les vulnérabilités connues.
  • Faire auditer votre code et vos pratiques cryptographiques par des experts : Faites auditer votre code et vos pratiques cryptographiques par des experts en sécurité pour identifier les vulnérabilités potentielles, les erreurs d'implémentation, ou les mauvaises pratiques de sécurité. La cryptographie est un domaine complexe et subtil, et il est facile de commettre des erreurs de sécurité si vous n'avez pas une expertise approfondie en cryptographie. Les audits de sécurité réguliers sont essentiels pour garantir la sécurité et la robustesse des aspects cryptographiques de vos applications Go qui manipulent des données sensibles.

En appliquant ces bonnes pratiques, vous utiliserez la cryptographie de manière sécurisée, efficace, et responsable dans vos applications Go, et vous protégerez efficacement les données sensibles de vos utilisateurs et de votre système contre les menaces et les vulnérabilités de sécurité.