Skip to content

Instantly share code, notes, and snippets.

@mrcrilly
Last active August 29, 2015 14:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrcrilly/492e519e0e3513e42e2a to your computer and use it in GitHub Desktop.
Save mrcrilly/492e519e0e3513e42e2a to your computer and use it in GitHub Desktop.
Simple GCM Encryption in Go
package main
// Core
import (
"fmt"
"io"
// Crypto, core
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
// Crypto, external
"code.google.com/p/go.crypto/pbkdf2"
// Encoding
// import "encoding/base64"
)
const (
PBKDF2_ITERATIONS = 8184
SECRET_BYTE_LENGTH = 32
)
type GCMPackage struct {
PlainText []byte
OptionalData []byte
CipherText []byte
Salt []byte
IVector []byte
haveencrypted bool
haveplain bool
}
func main() {
password := []byte("super secret password, yo!")
message := []byte("Hello, Barry!")
gp, _ := NewGCMPackage()
gp.Encrypt(password, message)
fmt.Println("Secure Message: " + string(gp.CipherText))
}
func NewGCMPackage() (gp *GCMPackage, err error) {
salt, err := GenerateSalt()
if err != nil {
panic(err)
}
ivector, err := GenerateIV(12) // Nonce for GCM; length currently hard coded
if err != nil {
panic(err)
}
return &GCMPackage{
Salt: salt,
IVector: ivector,
haveencrypted: false,
haveplain: false,
}, err
}
func NewGCMPackageWithSecrets(ctext, salt, iv []byte) (gp *GCMPackage, err error) {
gcm := &GCMPackage{
Salt: salt,
IVector: iv,
CipherText: ctext,
}
return gcm, err
}
func (gp *GCMPackage) Encrypt(password, ptext []byte) (err error) {
secret, err := GenerateSecretKey(password, gp.Salt)
if err != nil {
panic(err)
}
bcipher, err := aes.NewCipher(secret)
if err != nil {
panic(err)
}
gcm, err := cipher.NewGCM(bcipher)
if err != nil {
panic(err)
}
gp.CipherText = gcm.Seal(gp.CipherText, []byte(gp.IVector), ptext, gp.OptionalData)
gp.haveencrypted = true
// Clear the memory containing the secret after use
for i := 0; i <= len(secret)-1; i++ {secret[i]=0}
return err
}
func (gp *GCMPackage) Decrypt(password []byte) (err error) {
if ! gp.haveencrypted {
panic("No encrypted available to decrypt")
}
secret, err := GenerateSecretKey(password, gp.Salt)
if err != nil {
panic(err)
}
bcipher, err := aes.NewCipher(secret)
if err != nil {
panic(err)
}
gcm, err := cipher.NewGCM(bcipher)
if err != nil {
panic(err)
}
gp.PlainText, err = gcm.Open(gp.PlainText, gp.IVector, gp.CipherText, gp.OptionalData)
if err != nil {
panic(err)
}
gp.haveplain = true
// Clear the memory containing the secret after use
for i := 0; i <= len(secret)-1; i++ {secret[i]=0}
return err
}
func GenerateIV(size int) (ivector []byte, err error) {
return GenerateRandomBits(size)
}
func GenerateSecretKey(password, salt []byte) (key []byte, err error) {
return pbkdf2.Key(password, salt, PBKDF2_ITERATIONS, SECRET_BYTE_LENGTH, sha256.New), nil
}
func GenerateSalt() (salt []byte, err error) {
return GenerateRandomBits(SECRET_BYTE_LENGTH)
}
func GenerateRandomBits(size int) (rbits []byte, err error) {
rbits = make([]byte, size)
_, err = io.ReadFull(rand.Reader, rbits)
if err != nil {
panic(err)
}
return rbits, err
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment