Is there a simple method to encrypt and decrypt in Go?

1,092 views
Skip to first unread message

Santiago Corredoira

unread,
Mar 7, 2015, 5:24:01 AM3/7/15
to golan...@googlegroups.com
I mean something that handles the key padding, cypher initialization and everything else, like:

Encrypt(message, password []byte) []byte
Decrypt(message, password []byte) []byte

If not, here is what I am doing now:

func Encrypt(plaintext, password []byte) ([]byte, error) {
// pad the message for aes
plaintext = pad(plaintext)
if len(plaintext)%aes.BlockSize != 0 {
log.Fatal("plaintext is not a multiple of the block size")
}

key, err := generateKey(password)
if err != nil {
return nil, err
}

block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}

// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic(err)
}

mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)

return ciphertext, nil
}

func Decrypt(ciphertext, password []byte) ([]byte, error) {
key, err := generateKey(password)
if err != nil {
return nil, err
}

block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}

if len(ciphertext) < aes.BlockSize {
return nil, errors.New("ciphertext too short")
}

iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]

// CBC mode always works in whole blocks.
if len(ciphertext)%aes.BlockSize != 0 {
return nil, errors.New("error decrypting")
}

mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(ciphertext, ciphertext)

ciphertext = unpad(ciphertext)
if len(ciphertext) == 0 {
return nil, errors.New("error decrypting")
}

return ciphertext, nil
}

var salt []byte = []byte(`.... some random text ....`)

func generateKey(password []byte) ([]byte, error) {
return scrypt.Key(password, salt, 16384, 8, 1, 32)
}

// Pad applies the PKCS #7 padding scheme on the buffer.
func pad(in []byte) []byte {
padding := aes.BlockSize - (len(in) % aes.BlockSize)
if padding == 0 {
padding = aes.BlockSize
}
for i := 0; i < padding; i++ {
in = append(in, byte(padding))
}
return in
}

// Unpad strips the PKCS #7 padding on a buffer. If the padding is invalid, nil is returned.
func unpad(in []byte) []byte {
if len(in) == 0 {
return nil
}

padding := in[len(in)-1]
if int(padding) > len(in) || padding > aes.BlockSize {
return nil
} else if padding == 0 {
return nil
}

for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
if in[i] != padding {
return nil
}
}
return in[:len(in)-int(padding)]
}

Axel Wagner

unread,
Mar 7, 2015, 5:35:39 AM3/7/15
to Santiago Corredoira, golan...@googlegroups.com
Hi,

have a look at https://godoc.org/golang.org/x/crypto/nacl it has the
kind of simple API you are probably looking for.
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Santiago Corredoira

unread,
Mar 7, 2015, 6:45:25 AM3/7/15
to golan...@googlegroups.com, scorr...@gmail.com
Hi,

I have already looked at it but you still have to provide "nonces" and handle the key padding. I already handle the message and key padding in the code I pasted but I'm not sure if it is the right way.

thank you.

Christoph Hack

unread,
Mar 7, 2015, 12:19:36 PM3/7/15
to golan...@googlegroups.com, scorr...@gmail.com
The simplest solution is in my opinion the openpgp package, especially:

I use it in a personal password manager for the command line which stores a encryption JSON file (with armor encoding).

-christoph

Santiago Corredoira

unread,
Mar 7, 2015, 3:27:58 PM3/7/15
to golan...@googlegroups.com, scorr...@gmail.com
thank you.
Reply all
Reply to author
Forward
0 new messages