Szukaj…


Wprowadzenie

Dowiedz się, jak szyfrować i deszyfrować dane za pomocą Go. Pamiętaj, że nie jest to kurs o kryptografii, ale raczej o tym, jak to osiągnąć za pomocą Go.

Szyfrowanie i deszyfrowanie

Przedmowa

To jest szczegółowy przykład na temat szyfrowania i deszyfrowania danych za pomocą Go. Kod użycia jest skrócony, np. Obsługa błędów nie jest wspomniana. W pełni działający projekt z obsługą błędów i interfejsem użytkownika można znaleźć na Github tutaj .


Szyfrowanie

Wprowadzenie i dane

Ten przykład opisuje w pełni działające szyfrowanie i deszyfrowanie w Go. W tym celu potrzebujemy danych. W tym przykładzie używamy naszej secret struktury danych:

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
}

Następnie chcemy zaszyfrować taki secret . Pełny działający przykład można znaleźć tutaj (link do Github) . Teraz proces krok po kroku:

Krok 1

Przede wszystkim potrzebujemy pewnego rodzaju hasła głównego, aby zabezpieczyć sekret: masterPassword := "PASS"

Krok 2

Wszystkie metody kryptograficzne pracujące z bajtami zamiast ciągów. Dlatego konstruujemy tablicę bajtów z danymi z naszego tajnego klucza.

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,
))

Krok 3

Tworzymy sól, aby zapobiec atakom na tęczowy stół, por. Wikipedia : saltBytes := uuid.NewV4().Bytes() . W tym przypadku używamy UUID v4, którego nie można przewidzieć.

Krok 4

Teraz możemy uzyskać klucz i wektor z hasła głównego i losowej soli, w odniesieniu do 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:]

Krok 5

Pożądany tryb CBC działa z całymi blokami. Dlatego musimy sprawdzić, czy nasze dane są wyrównane do pełnego bloku. Jeśli nie, musimy go uzupełnić:

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
}

Krok 6

Teraz tworzymy szyfr AES: aesBlockEncrypter, aesErr := aes.NewCipher(keyBytes)

Krok 7

Zastrzegamy niezbędną pamięć dla zaszyfrowanych danych: encryptedData := make([]byte, len(secretBytesDecrypted)) . W przypadku AES-CBC zaszyfrowane dane miały taką samą długość jak niezaszyfrowane dane.

Krok 8

Teraz powinniśmy utworzyć szyfrator i zaszyfrować dane:

aesEncrypter := cipher.NewCBCEncrypter(aesBlockEncrypter, vectorBytes)
aesEncrypter.CryptBlocks(encryptedData, secretBytesDecrypted)

Teraz zaszyfrowane dane znajdują się w zmiennej encryptedData .

Krok 9

Zaszyfrowane dane muszą być przechowywane. Ale nie tylko dane: bez soli zaszyfrowane dane nie mogłyby zostać odszyfrowane. Dlatego do zarządzania tym musimy użyć jakiegoś formatu pliku. Tutaj kodujemy zaszyfrowane dane jako base64, por. Wikipedia :

encodedBytes := make([]byte, base64.StdEncoding.EncodedLen(len(encryptedData)))
base64.StdEncoding.Encode(encodedBytes, encryptedData)

Następnie definiujemy naszą zawartość pliku i własny format pliku. Format wygląda następująco: salt[0x10]base64 content . Najpierw przechowujemy sól. Aby zaznaczyć początek zawartości base64, przechowujemy bajt 10 . To działa, ponieważ base64 nie używa tej wartości. Dlatego możemy znaleźć początek base64, wyszukując pierwsze wystąpienie 10 od końca do początku pliku.

fileContent := make([]byte, len(saltBytes))
copy(fileContent, saltBytes)
fileContent = append(fileContent, 10)
fileContent = append(fileContent, encodedBytes...)

Krok 10

Wreszcie możemy napisać nasz plik: writeErr := ioutil.WriteFile("my secret.data", fileContent, 0644) .


Deszyfrowanie

Wprowadzenie i dane

Jeśli chodzi o szyfrowanie, potrzebujemy danych do pracy. Dlatego zakładamy, że mamy zaszyfrowany plik i wspomnianą strukturę secret . Celem jest odczytanie zaszyfrowanych danych z pliku, odszyfrowanie go i utworzenie instancji struktury.

Krok 1

Pierwszy krok jest identyczny z szyfrowaniem: Potrzebujemy pewnego rodzaju hasła głównego, aby odszyfrować sekret: masterPassword := "PASS" .

Krok 2

Teraz czytamy zaszyfrowane dane z pliku: encryptedFileData, bytesErr := ioutil.ReadFile(filename) .

Krok 3

Jak wspomniano wcześniej, możemy podzielić sól i zaszyfrowane dane według bajtu separatora 10 , przeszukując wstecz od końca do początku:

for n := len(encryptedFileData) - 1; n > 0; n-- {
    if encryptedFileData[n] == 10 {
        saltBytes = encryptedFileData[:n]
        encryptedBytesBase64 = encryptedFileData[n+1:]
        break
    }
} 

Krok 4

Następnie musimy zdekodować bajty zakodowane w base64:

decodedBytes := make([]byte, len(encryptedBytesBase64))
countDecoded, decodedErr := base64.StdEncoding.Decode(decodedBytes, encryptedBytesBase64)
encryptedBytes = decodedBytes[:countDecoded]

Krok 5

Teraz możemy uzyskać klucz i wektor z hasła głównego i losowej soli, w odniesieniu do 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:]

Krok 6

Utwórz szyfr AES: aesBlockDecrypter, aesErr := aes.NewCipher(keyBytes) .

Krok 7

Zarezerwuj niezbędną pamięć dla odszyfrowanych danych: decryptedData := make([]byte, len(encryptedBytes)) . Z definicji ma taką samą długość jak zaszyfrowane dane.

Krok 8

Teraz utwórz deszyfrator i odszyfruj dane:

aesDecrypter := cipher.NewCBCDecrypter(aesBlockDecrypter, vectorBytes)
aesDecrypter.CryptBlocks(decryptedData, encryptedBytes)

Krok 9

Konwertuj odczytane bajty na ciąg: decryptedString := string(decryptedData) . Ponieważ potrzebujemy linii, podziel ciąg: lines := strings.Split(decryptedString, "\n") .

Krok 10

Zbuduj secret z linii:

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]

Na koniec utwórz ponownie podziały wiersza w polu notatek: artifact.Notes = strings.Replace(artifact.Notes, string(65000), "\n", -1) .



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow