Go
Criptografía
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)
.