Поиск…


Вступление

Узнайте, как шифровать и расшифровывать данные с помощью Go. Имейте в виду, что это не курс криптографии, а способ достижения этого с помощью Go.

Шифрование и дешифрование

предисловие

Это подробный пример того, как шифровать и расшифровывать данные с помощью Go. Код использования сокращается, например, обработка ошибок не упоминается. Полный рабочий проект с обработкой ошибок и пользовательским интерфейсом можно найти здесь в Github.


шифрование

Введение и данные

В этом примере описывается полное рабочее шифрование и дешифрование в Go. Для этого нам нужны данные. В этом примере мы используем собственный 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
}

Затем мы хотим зашифровать такой secret . Полный рабочий пример можно найти здесь (ссылка на Github) . Теперь шаг за шагом:

Шаг 1

Прежде всего, нам нужен некий мастер-пароль для защиты тайны: masterPassword := "PASS"

Шаг 2

Все криптовые методы работают с байтами вместо строк. Таким образом, мы строим массив байтов с данными из нашего секрета.

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

Шаг 3

Мы создаем соль, чтобы предотвратить атаки радужного стола, ср. Википедия : saltBytes := uuid.NewV4().Bytes() . Здесь мы используем UUID v4, который не предсказуем.

Шаг 4

Теперь мы можем получить ключ и вектор из основного пароля и случайной соли в отношении 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:]

Шаг 5

Желаемый режим CBC работает со всеми блоками. Таким образом, мы должны проверить, соответствуют ли наши данные полному блоку. Если нет, мы должны заполнить его:

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
}

Шаг 6

Теперь мы создаем AES-шифр: aesBlockEncrypter, aesErr := aes.NewCipher(keyBytes)

Шаг 7

Мы сохраняем необходимую память для зашифрованных данных: encryptedData := make([]byte, len(secretBytesDecrypted)) . В случае AES-CBC зашифрованные данные имеют ту же длину, что и незашифрованные данные.

Шаг 8

Теперь мы должны создать encrypter и зашифровать данные:

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

Теперь зашифрованные данные находятся внутри переменной encryptedData .

Шаг 9

Зашифрованные данные должны быть сохранены. Но не только данные: без соли, зашифрованные данные не могут быть дешифрованы. Таким образом, мы должны использовать какой-то формат файла для управления этим. Здесь мы кодируем зашифрованные данные как base64, cf. Википедия :

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

Затем мы определяем наше содержимое файла и собственный формат файла. Формат выглядит так: salt[0x10]base64 content . Сначала мы храним соль. Чтобы отметить начало содержимого base64, мы храним байт 10 . Это работает, потому что base64 не использует это значение. Поэтому мы могли бы найти начало base64 путем поиска первого вхождения 10 от конца к началу файла.

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

Шаг 10

Наконец, мы могли бы написать наш файл: writeErr := ioutil.WriteFile("my secret.data", fileContent, 0644) .


Дешифрирование

Введение и данные

Что касается шифрования, нам нужны некоторые данные для работы. Таким образом, мы предполагаем, что у нас есть зашифрованный файл и secret указанной структуры. Цель состоит в том, чтобы прочитать зашифрованные данные из файла, расшифровать его и создать экземпляр структуры.

Шаг 1

Первый шаг идентичен шифрованию: нам нужен некий главный пароль для дешифрования секретного masterPassword := "PASS" .

Шаг 2

Теперь мы читаем зашифрованные данные из файла: encryptedFileData, bytesErr := ioutil.ReadFile(filename) .

Шаг 3

Как упоминалось ранее, мы могли разделить соли и зашифрованные данные байт 10 ограничителя, искаженный назад от конца до начала:

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

Шаг 4

Затем мы должны декодировать байты с кодировкой base64:

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

Шаг 5

Теперь мы можем получить ключ и вектор из основного пароля и случайной соли в отношении 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:]

Шаг 6

Создайте AES-шифр: aesBlockDecrypter, aesErr := aes.NewCipher(keyBytes) .

Шаг 7

Зарезервируйте необходимую память для дешифрованных данных: decryptedData := make([]byte, len(encryptedBytes)) . По определению он имеет ту же длину, что и зашифрованные данные.

Шаг 8

Теперь создайте decrypter и расшифруйте данные:

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

Шаг 9

Преобразуйте прочитанные байты в строку: decryptedString := string(decryptedData) . Поскольку нам нужны строки, разделите строку: lines := strings.Split(decryptedString, "\n") .

Шаг 10

Создайте secret из строк:

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]

Наконец, заново создайте разрывы строк в поле примечаний: artifact.Notes = strings.Replace(artifact.Notes, string(65000), "\n", -1) .



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow