Buscar..


Introducción

Descubra cómo cifrar y descifrar datos con Go. Tenga en cuenta que este no es un curso sobre criptografía, sino cómo lograrlo con Go.

Cifrado y descifrado

Prefacio

Este es un ejemplo detallado sobre cómo cifrar y descifrar datos con Go. El código de uso se acorta, por ejemplo, no se menciona el manejo de errores. El proyecto de trabajo completo con manejo de errores e interfaz de usuario se puede encontrar en Github aquí .


Cifrado

Introducción y datos

Este ejemplo describe un cifrado y descifrado completo en Go. Para ello, necesitamos un dato. En este ejemplo, usamos nuestro propio secret estructura de datos:

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
}

A continuación, queremos cifrar tal secret . El ejemplo completo de trabajo se puede encontrar aquí (enlace a Github) . Ahora, el proceso paso a paso:

Paso 1

En primer lugar, necesitamos un tipo de contraseña maestra para proteger el secreto: masterPassword := "PASS"

Paso 2

Todos los métodos criptográficos que trabajan con bytes en lugar de cadenas. Por lo tanto, construimos una matriz de bytes con los datos de nuestro secreto.

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

Paso 3

Creamos algo de sal para prevenir ataques a la mesa del arco iris, cf. Wikipedia : saltBytes := uuid.NewV4().Bytes() . Aquí, usamos un UUID v4 que no es predecible.

Etapa 4

Ahora, podemos derivar una clave y un vector a partir de la contraseña maestra y el salt aleatorio, con respecto al 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:]

Paso 5

El modo CBC deseado funciona con bloques enteros. Por lo tanto, tenemos que verificar si nuestros datos están alineados con un bloque completo. Si no, tenemos que rellenarla:

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
}

Paso 6

Ahora creamos un cifrado AES: aesBlockEncrypter, aesErr := aes.NewCipher(keyBytes)

Paso 7

Reservamos la memoria necesaria para los datos cifrados: encryptedData := make([]byte, len(secretBytesDecrypted)) . En el caso de AES-CBC, los datos cifrados tenían la misma longitud que los datos no cifrados.

Paso 8

Ahora, debemos crear el cifrador y cifrar los datos:

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

Ahora, los datos encriptados están dentro de la variable encryptedData .

Paso 9

Los datos cifrados deben ser almacenados. Pero no solo los datos: sin la sal, los datos cifrados no se podrían descifrar. Por lo tanto, debemos usar algún tipo de formato de archivo para gestionar esto. Aquí, codificamos los datos cifrados como base64, cf. Wikipedia :

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

A continuación, definimos el contenido de nuestro archivo y nuestro propio formato de archivo. El formato se ve así: salt[0x10]base64 content . Primero, almacenamos la sal. Para marcar el comienzo del contenido base64, almacenamos el byte 10 . Esto funciona, porque base64 no usa este valor. Por lo tanto, podríamos encontrar el inicio de base64 buscando la primera aparición de 10 desde el final hasta el principio del archivo.

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

Paso 10

Finalmente, podríamos escribir nuestro archivo: writeErr := ioutil.WriteFile("my secret.data", fileContent, 0644) .


Descifrado

Introducción y datos

En cuanto al cifrado, necesitamos algunos datos para trabajar. Por lo tanto, asumimos que tenemos un archivo cifrado y la estructura secret mencionada. El objetivo es leer los datos cifrados del archivo, descifrarlos y crear una instancia de la estructura.

Paso 1

El primer paso es idéntico al cifrado: necesitamos un tipo de contraseña maestra para descifrar el secreto: masterPassword := "PASS" .

Paso 2

Ahora, leemos los datos cifrados del archivo: encryptedFileData, bytesErr := ioutil.ReadFile(filename) .

Paso 3

Como se mencionó anteriormente, podríamos dividir la sal y los datos cifrados por el byte 10 delimitador, buscados hacia atrás desde el final hasta el principio:

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

Etapa 4

A continuación, debemos decodificar los bytes codificados en base64:

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

Paso 5

Ahora, podemos derivar una clave y un vector a partir de la contraseña maestra y el salt aleatorio, con respecto al 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:]

Paso 6

Cree un cifrado AES: aesBlockDecrypter, aesErr := aes.NewCipher(keyBytes) .

Paso 7

Reserve la memoria necesaria para los datos descifrados: decryptedData := make([]byte, len(encryptedBytes)) . Por definición, tiene la misma longitud que los datos encriptados.

Paso 8

Ahora, crea el descifrador y descifra los datos:

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

Paso 9

Convierta los bytes leídos en cadena: decryptedString := string(decryptedData) . Como necesitamos líneas, divida la cadena: lines := strings.Split(decryptedString, "\n") .

Paso 10

Construye un secret fuera de las líneas:

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]

Finalmente, vuelva a crear los saltos de línea dentro del campo de notas: artifact.Notes = strings.Replace(artifact.Notes, string(65000), "\n", -1) .



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow