Go
Cryptographie
Recherche…
Introduction
Découvrez comment chiffrer et déchiffrer les données avec Go. Gardez à l'esprit que ce n'est pas un cours sur la cryptographie, mais plutôt comment y parvenir avec Go.
Cryptage et décryptage
Avant-propos
Ceci est un exemple détaillé sur la façon de chiffrer et déchiffrer les données avec Go. Le code d'utilisation est raccourci, par exemple la gestion des erreurs n'est pas mentionnée. Le projet de travail complet avec gestion des erreurs et interface utilisateur se trouve sur Github ici .
Cryptage
Introduction et données
Cet exemple décrit un chiffrement et un déchiffrement complets dans Go. Pour ce faire, nous avons besoin de données. Dans cet exemple, nous utilisons notre propre secret
structure de données:
type secret struct {
DisplayName string
Notes string
Username string
EMail string
CopyMethod string
Password string
CustomField01Name string
CustomField01Data string
CustomField02Name string
CustomField02Data string
CustomField03Name string
CustomField03Data string
CustomField04Name string
CustomField04Data string
CustomField05Name string
CustomField05Data string
CustomField06Name string
CustomField06Data string
}
Ensuite, nous voulons chiffrer un tel secret
. L'exemple de travail complet peut être trouvé ici (lien vers Github) . Maintenant, le processus pas à pas:
Étape 1
Tout d'abord, nous avons besoin d'une sorte de mot de passe maître pour protéger le secret: masterPassword := "PASS"
Étape 2
Toutes les méthodes de cryptage utilisant des octets au lieu de chaînes. Ainsi, nous construisons un tableau d'octets avec les données de notre secret.
secretBytesDecrypted := []byte(fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
artifact.DisplayName,
strings.Replace(artifact.Notes, "\n", string(65000), -1),
artifact.Username,
artifact.EMail,
artifact.CopyMethod,
artifact.Password,
artifact.CustomField01Name,
artifact.CustomField01Data,
artifact.CustomField02Name,
artifact.CustomField02Data,
artifact.CustomField03Name,
artifact.CustomField03Data,
artifact.CustomField04Name,
artifact.CustomField04Data,
artifact.CustomField05Name,
artifact.CustomField05Data,
artifact.CustomField06Name,
artifact.CustomField06Data,
))
Étape 3
Nous créons du sel afin de prévenir les attaques à l'arc-en-ciel, cf. Wikipedia : saltBytes := uuid.NewV4().Bytes()
. Ici, nous utilisons un UUID v4 qui n'est pas prévisible.
Étape 4
Maintenant, nous sommes en mesure de dériver une clé et un vecteur du mot de passe maître et du sel aléatoire, en ce qui concerne RFC 2898:
keyLength := 256
rfc2898Iterations := 6
keyVectorData := pbkdf2.Key(masterPassword, saltBytes, rfc2898Iterations, (keyLength/8)+aes.BlockSize, sha1.New)
keyBytes := keyVectorData[:keyLength/8]
vectorBytes := keyVectorData[keyLength/8:]
Étape 5
Le mode CBC souhaité fonctionne avec des blocs entiers. Nous devons donc vérifier si nos données sont alignées sur un bloc complet. Sinon, nous devons le remplir:
if len(secretBytesDecrypted)%aes.BlockSize != 0 {
numberNecessaryBlocks := int(math.Ceil(float64(len(secretBytesDecrypted)) / float64(aes.BlockSize)))
enhanced := make([]byte, numberNecessaryBlocks*aes.BlockSize)
copy(enhanced, secretBytesDecrypted)
secretBytesDecrypted = enhanced
}
Étape 6
Maintenant, nous créons un chiffrement AES: aesBlockEncrypter, aesErr := aes.NewCipher(keyBytes)
Étape 7
Nous réservons la mémoire nécessaire aux données chiffrées: encryptedData := make([]byte, len(secretBytesDecrypted))
. Dans le cas d'AES-CBC, les données chiffrées avaient la même longueur que les données non chiffrées.
Étape 8
Maintenant, nous devrions créer le crypteur et crypter les données:
aesEncrypter := cipher.NewCBCEncrypter(aesBlockEncrypter, vectorBytes)
aesEncrypter.CryptBlocks(encryptedData, secretBytesDecrypted)
Maintenant, les données chiffrées se trouvent dans la variable encryptedData
.
Étape 9
Les données cryptées doivent être stockées. Mais pas seulement les données: sans le sel, les données chiffrées n'ont pas pu être déchiffrées. Nous devons donc utiliser un format de fichier pour gérer cela. Ici, nous encodons les données chiffrées en base64, cf. Wikipedia :
encodedBytes := make([]byte, base64.StdEncoding.EncodedLen(len(encryptedData)))
base64.StdEncoding.Encode(encodedBytes, encryptedData)
Ensuite, nous définissons notre contenu de fichier et notre propre format de fichier. Le format ressemble à ceci: salt[0x10]base64 content
. Tout d'abord, nous stockons le sel. Afin de marquer le début du contenu de base64, nous stockons l’octet 10
. Cela fonctionne, car base64 n'utilise pas cette valeur. Par conséquent, nous pourrions trouver le début de base64 en recherchant la première occurrence de 10
de la fin au début du fichier.
fileContent := make([]byte, len(saltBytes))
copy(fileContent, saltBytes)
fileContent = append(fileContent, 10)
fileContent = append(fileContent, encodedBytes...)
Étape 10
Enfin, nous pourrions écrire notre fichier: writeErr := ioutil.WriteFile("my secret.data", fileContent, 0644)
.
Décryptage
Introduction et données
En ce qui concerne le chiffrement, nous avons besoin de certaines données pour travailler. Ainsi, nous supposons que nous avons un fichier crypté et la structure mentionnée secret
. L'objectif est de lire les données chiffrées à partir du fichier, de les déchiffrer et de créer une instance de la structure.
Étape 1
La première étape est identique au chiffrement: nous avons besoin d'une sorte de mot de passe principal pour déchiffrer le secret: masterPassword := "PASS"
.
Étape 2
Maintenant, nous lisons les données chiffrées à partir du fichier: encryptedFileData, bytesErr := ioutil.ReadFile(filename)
.
Étape 3
Comme mentionné précédemment, nous pourrions diviser les données de sel et les données cryptées par l’octet de délimiteur 10
, recherché en arrière de la fin au début:
for n := len(encryptedFileData) - 1; n > 0; n-- {
if encryptedFileData[n] == 10 {
saltBytes = encryptedFileData[:n]
encryptedBytesBase64 = encryptedFileData[n+1:]
break
}
}
Étape 4
Ensuite, nous devons décoder les octets encodés en base64:
decodedBytes := make([]byte, len(encryptedBytesBase64))
countDecoded, decodedErr := base64.StdEncoding.Decode(decodedBytes, encryptedBytesBase64)
encryptedBytes = decodedBytes[:countDecoded]
Étape 5
Maintenant, nous sommes en mesure de dériver une clé et un vecteur du mot de passe maître et du sel aléatoire, en ce qui concerne RFC 2898:
keyLength := 256
rfc2898Iterations := 6
keyVectorData := pbkdf2.Key(masterPassword, saltBytes, rfc2898Iterations, (keyLength/8)+aes.BlockSize, sha1.New)
keyBytes := keyVectorData[:keyLength/8]
vectorBytes := keyVectorData[keyLength/8:]
Étape 6
Créez un chiffrement AES: aesBlockDecrypter, aesErr := aes.NewCipher(keyBytes)
.
Étape 7
Réservez la mémoire nécessaire pour les données déchiffrées: decryptedData := make([]byte, len(encryptedBytes))
. Par définition, il a la même longueur que les données cryptées.
Étape 8
Maintenant, créez le décrypteur et décryptez les données:
aesDecrypter := cipher.NewCBCDecrypter(aesBlockDecrypter, vectorBytes)
aesDecrypter.CryptBlocks(decryptedData, encryptedBytes)
Étape 9
Convertissez les octets de lecture en chaîne: decryptedString := string(decryptedData)
. Comme nous avons besoin de lignes, séparez la chaîne: lines := strings.Split(decryptedString, "\n")
.
Étape 10
Construis un secret
sur les lignes:
artifact := secret{}
artifact.DisplayName = lines[0]
artifact.Notes = lines[1]
artifact.Username = lines[2]
artifact.EMail = lines[3]
artifact.CopyMethod = lines[4]
artifact.Password = lines[5]
artifact.CustomField01Name = lines[6]
artifact.CustomField01Data = lines[7]
artifact.CustomField02Name = lines[8]
artifact.CustomField02Data = lines[9]
artifact.CustomField03Name = lines[10]
artifact.CustomField03Data = lines[11]
artifact.CustomField04Name = lines[12]
artifact.CustomField04Data = lines[13]
artifact.CustomField05Name = lines[14]
artifact.CustomField05Data = lines[15]
artifact.CustomField06Name = lines[16]
artifact.CustomField06Data = lines[17]
Enfin, recréez les sauts de ligne dans le champ notes: artifact.Notes = strings.Replace(artifact.Notes, string(65000), "\n", -1)
.