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)]
}