Go
Kryptographie
Suche…
Einführung
Finden Sie heraus, wie Sie mit Go Daten verschlüsseln und entschlüsseln können. Beachten Sie, dass dies kein Kurs über Kryptographie ist, sondern wie Sie ihn mit Go erreichen.
Verschlüsselung und Entschlüsselung
Vorwort
Dies ist ein detailliertes Beispiel, wie Daten mit Go verschlüsselt und entschlüsselt werden. Der Anwendungscode ist kurz, dh die Fehlerbehandlung wird nicht erwähnt. Der vollständige Arbeitsprojekt mit der Fehlerbehandlung und Benutzeroberfläche könnte auf Github finden hier .
Verschlüsselung
Einleitung und Daten
Dieses Beispiel beschreibt eine vollständige Verschlüsselung und Entschlüsselung in Go. Dazu benötigen wir Daten. In diesem Beispiel verwenden wir unsere eigenen Datenstruktur secret
:
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
}
Als nächstes wollen wir ein solches secret
verschlüsseln. Das vollständige Arbeitsbeispiel finden Sie hier (Link zu Github) . Nun der Schritt für Schritt:
Schritt 1
Zunächst benötigen wir eine Art Master-Passwort, um das Geheimnis zu schützen: masterPassword := "PASS"
Schritt 2
Alle Krypto-Methoden, die mit Bytes statt mit Strings arbeiten. Daher bauen wir ein Byte-Array mit den Daten unseres Geheimnisses auf.
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,
))
Schritt 3
Wir erzeugen etwas Salz, um Regenbogenangriffe zu verhindern, vgl. Wikipedia : saltBytes := uuid.NewV4().Bytes()
. Hier verwenden wir eine UUID v4, die nicht vorhersehbar ist.
Schritt 4
Nun können wir einen Schlüssel und einen Vektor aus dem Master-Passwort und dem Zufalls-Salt für RFC 2898 ableiten:
keyLength := 256
rfc2898Iterations := 6
keyVectorData := pbkdf2.Key(masterPassword, saltBytes, rfc2898Iterations, (keyLength/8)+aes.BlockSize, sha1.New)
keyBytes := keyVectorData[:keyLength/8]
vectorBytes := keyVectorData[keyLength/8:]
Schritt 5
Der gewünschte CBC-Modus funktioniert mit ganzen Blöcken. Daher müssen wir prüfen, ob unsere Daten auf einen vollständigen Block ausgerichtet sind. Wenn nicht, müssen wir es auffüllen:
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
}
Schritt 6
Jetzt erstellen wir eine AES-Chiffre: aesBlockEncrypter, aesErr := aes.NewCipher(keyBytes)
Schritt 7
Wir reservieren den erforderlichen Speicher für die verschlüsselten Daten: encryptedData := make([]byte, len(secretBytesDecrypted))
. Im Falle von AES-CBC hatten die verschlüsselten Daten die gleiche Länge wie die unverschlüsselten Daten.
Schritt 8
Nun sollten wir den Verschlüsseler erstellen und die Daten verschlüsseln:
aesEncrypter := cipher.NewCBCEncrypter(aesBlockEncrypter, vectorBytes)
aesEncrypter.CryptBlocks(encryptedData, secretBytesDecrypted)
Die verschlüsselten Daten befinden sich jetzt in der Variablen encryptedData
.
Schritt 9
Die verschlüsselten Daten müssen gespeichert werden. Aber nicht nur die Daten: Ohne das Salz könnten die verschlüsselten Daten nicht entschlüsselt werden. Daher müssen wir ein Dateiformat verwenden, um dies zu verwalten. Hier verschlüsseln wir die verschlüsselten Daten als base64, vgl. Wikipedia :
encodedBytes := make([]byte, base64.StdEncoding.EncodedLen(len(encryptedData)))
base64.StdEncoding.Encode(encodedBytes, encryptedData)
Als Nächstes definieren wir unseren Dateiinhalt und unser eigenes Dateiformat. Das Format sieht folgendermaßen aus: salt[0x10]base64 content
. Zuerst lagern wir das Salz. Um den Anfang des base64-Inhalts zu markieren, speichern wir das Byte 10
. Dies funktioniert, weil base64 diesen Wert nicht verwendet. Daher konnten wir den Anfang von base64 finden, indem wir das erste Vorkommen von 10
vom Ende bis zum Anfang der Datei suchen.
fileContent := make([]byte, len(saltBytes))
copy(fileContent, saltBytes)
fileContent = append(fileContent, 10)
fileContent = append(fileContent, encodedBytes...)
Schritt 10
Schließlich könnten wir unsere Datei schreiben: writeErr := ioutil.WriteFile("my secret.data", fileContent, 0644)
.
Entschlüsselung
Einleitung und Daten
Für die Verschlüsselung benötigen wir einige Daten, um damit arbeiten zu können. Wir gehen also davon aus, dass wir eine verschlüsselte Datei und die erwähnte Struktur secret
. Ziel ist es, die verschlüsselten Daten aus der Datei zu lesen, zu entschlüsseln und eine Instanz der Struktur zu erstellen.
Schritt 1
Der erste Schritt ist identisch mit der Verschlüsselung: Wir benötigen eine Art Master-Passwort, um das Geheimnis zu entschlüsseln: masterPassword := "PASS"
.
Schritt 2
Nun lesen wir die verschlüsselten Daten aus der Datei: encryptedFileData, bytesErr := ioutil.ReadFile(filename)
.
Schritt 3
Wie bereits erwähnt, konnten wir Salt- und verschlüsselte Daten nach dem Trennzeichen-Byte 10
aufteilen, das vom Ende bis zum Anfang gesucht wurde:
for n := len(encryptedFileData) - 1; n > 0; n-- {
if encryptedFileData[n] == 10 {
saltBytes = encryptedFileData[:n]
encryptedBytesBase64 = encryptedFileData[n+1:]
break
}
}
Schritt 4
Als Nächstes müssen wir die base64-codierten Bytes dekodieren:
decodedBytes := make([]byte, len(encryptedBytesBase64))
countDecoded, decodedErr := base64.StdEncoding.Decode(decodedBytes, encryptedBytesBase64)
encryptedBytes = decodedBytes[:countDecoded]
Schritt 5
Nun können wir einen Schlüssel und einen Vektor aus dem Master-Passwort und dem Zufalls-Salt für RFC 2898 ableiten:
keyLength := 256
rfc2898Iterations := 6
keyVectorData := pbkdf2.Key(masterPassword, saltBytes, rfc2898Iterations, (keyLength/8)+aes.BlockSize, sha1.New)
keyBytes := keyVectorData[:keyLength/8]
vectorBytes := keyVectorData[keyLength/8:]
Schritt 6
Erstellen Sie eine AES-Verschlüsselung: aesBlockDecrypter, aesErr := aes.NewCipher(keyBytes)
.
Schritt 7
Reservieren Sie den erforderlichen Speicher für die entschlüsselten Daten: decryptedData := make([]byte, len(encryptedBytes))
. Definitionsgemäß hat es dieselbe Länge wie die verschlüsselten Daten.
Schritt 8
Erstellen Sie nun den Entschlüsseler und entschlüsseln Sie die Daten:
aesDecrypter := cipher.NewCBCDecrypter(aesBlockDecrypter, vectorBytes)
aesDecrypter.CryptBlocks(decryptedData, encryptedBytes)
Schritt 9
Konvertieren Sie die gelesenen Bytes in string: decryptedString := string(decryptedData)
. Da wir Zeilen benötigen, teilen Sie die Zeichenfolge: lines := strings.Split(decryptedString, "\n")
.
Schritt 10
Konstruiere ein secret
aus den Linien:
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]
Erstellen Sie schließlich die Zeilenumbrüche innerhalb des Notizfeldes neu: artifact.Notes = strings.Replace(artifact.Notes, string(65000), "\n", -1)