Golang : Derive cryptographic key from passwords with Argon2
Argon2 is a method used to derive cryptographic key from passwords which has a few advantages over the "traditional method" of key generation from passwords. To learn more about the Argon2 method and the advantage it offers, please see https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
Below is an example adapted from previous AES tutorial, but this time ... instead of hard coding the AES key, we will use Argon2 to generate the key from our password.
Here you go!
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"golang.org/x/crypto/argon2"
)
func main() {
passwd := []byte("password")
salt := randStr(32, "alphanum") // generate a 32 bytes of random alpha-numeric string
// read more the advantage of using Argon2 to derive cryptographic keys from password
//https://tip.golang.org/pkg/golang.org/x/crypto/argon2/
argon2key := argon2.IDKey(passwd, salt, 1, 64*1024, 4, 32)
fmt.Println("Salt : ", salt)
fmt.Println("Argon2 Key : ", argon2key)
fmt.Println("Size of argon2 key : ", len(argon2key))
// taken from https://socketloop.com/tutorials/golang-how-to-encrypt-with-aes-crypto
// instead of hardcoding our 32 bytes AES key, we now use the key from Argon2
block, err := aes.NewCipher([]byte(argon2key))
if err != nil {
panic(err)
}
fmt.Printf("%d bytes NewCipher key with block size of %d bytes\n", len(argon2key), block.BlockSize)
// 16 bytes for AES-128, 24 bytes for AES-192, 32 bytes for AES-256
ciphertext := []byte("abcdef1234567890ghijklmno98765432")
iv := ciphertext[:aes.BlockSize] // const BlockSize = 16, doesn't matter if AES-256 or AES-192... still use this constant
// verify
// fmt.Println(string(iv))
secret := []byte("Hello! 妳好嗎?")
// encrypt
encrypter := cipher.NewCFBEncrypter(block, iv)
encrypted := make([]byte, len(secret))
encrypter.XORKeyStream(encrypted, secret)
fmt.Printf("%s encrypted to %v\n", secret, encrypted)
// verify
//fmt.Printf("%s encrypted to %s\n", secret, string(encrypted))
// let's decrypt back and see how it goes
decrypter := cipher.NewCFBDecrypter(block, iv) // simple!
decrypted := make([]byte, len(encrypted))
decrypter.XORKeyStream(decrypted, encrypted)
fmt.Printf("%s decrypted to %s\n", string(encrypted), decrypted)
}
// MODIFIED from https://socketloop.com/tutorials/golang-how-to-generate-random-string
func randStr(strSize int, randType string) []byte {
var dictionary string
if randType == "alphanum" {
dictionary = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
}
if randType == "alpha" {
dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
}
if randType == "number" {
dictionary = "0123456789"
}
var bytes = make([]byte, strSize)
rand.Read(bytes)
for k, v := range bytes {
bytes[k] = dictionary[v%byte(len(dictionary))]
}
return bytes
}
Sample output:
Salt : [79 86 116 122 119 119 86 103 76 114 100 85 78 52 68 114 99 54 101 118 99 121 68 81 119 77 115 52 115 102 112 114]
Argon2 Key : [151 57 205 221 57 249 116 92 116 49 39 27 249 199 53 72 203 75 105 96 108 251 91 180 217 231 14 42 160 210 222 169]
Size of argon2 key : 32
32 bytes NewCipher key with block size of 4930928 bytes
Hello! 妳好嗎? encrypted to [19 124 253 101 212 157 235 168 47 158 7 27 145 220 53 5 74]
|�eԝ�/��5J decrypted to Hello! 妳好嗎?
Happy coding!
References:
https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
https://socketloop.com/tutorials/golang-how-to-encrypt-with-aes-crypto
https://socketloop.com/tutorials/golang-how-to-generate-random-string
https://tip.golang.org/pkg/golang.org/x/crypto/argon2/
https://socketloop.com/tutorials/golang-automatically-figure-out-array-length-size-with-three-dots
See also : Golang : Encrypt and decrypt data with AES crypto
By Adam Ng(黃武俊)
IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.
Advertisement
Tutorials
+38.6k Golang : How to iterate over a []string(array)
+10.8k Golang : Fix fmt.Scanf() on Windows will scan input twice problem
+7.2k Golang : Rename part of filename
+11.6k Golang : Split strings into command line arguments
+9.2k Golang : Qt get screen resolution and display on center example
+5k Swift : Convert string array to array example
+9.9k Fix ERROR 1045 (28000): Access denied for user 'root'@'ip-address' (using password: YES)
+15.3k Golang : Convert date format and separator yyyy-mm-dd to dd-mm-yyyy
+17.9k Golang : Get download file size
+6.8k Golang : How to fix html/template : "somefile" is undefined error?
+16.2k Golang : Fix cannot convert buffer (type *bytes.Buffer) to type string error
+17.9k Golang : Get path name to current directory or folder