Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
1 contributor

Users who have contributed to this file

161 lines (140 sloc) 4.09 KB
// Sample of encrypting and decrypting a whole file with crypto/aes.
//
// Eli Bendersky [https://eli.thegreenplace.net]
// This code is in the public domain.
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/binary"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
)
// encryptFile encrypts the file specified by filename with the given key,
// placing the result in outFilename (or filename + ".enc" if outFilename is
// empty). The key has to be 16, 24 or 32 bytes long to select between AES-128,
// AES-192 or AES-256. Returns the name of the output file if successful.
func encryptFile(key []byte, filename string, outFilename string) (string, error) {
if len(outFilename) == 0 {
outFilename = filename + ".enc"
}
plaintext, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
of, err := os.Create(outFilename)
if err != nil {
return "", err
}
defer of.Close()
// Write the original plaintext size into the output file first, encoded in
// a 8-byte integer.
origSize := uint64(len(plaintext))
if err = binary.Write(of, binary.LittleEndian, origSize); err != nil {
return "", err
}
// Pad plaintext to a multiple of BlockSize with random padding.
if len(plaintext)%aes.BlockSize != 0 {
bytesToPad := aes.BlockSize - (len(plaintext) % aes.BlockSize)
padding := make([]byte, bytesToPad)
if _, err := rand.Read(padding); err != nil {
return "", err
}
plaintext = append(plaintext, padding...)
}
// Generate random IV and write it to the output file.
iv := make([]byte, aes.BlockSize)
if _, err := rand.Read(iv); err != nil {
return "", err
}
if _, err = of.Write(iv); err != nil {
return "", err
}
// Ciphertext has the same size as the padded plaintext.
ciphertext := make([]byte, len(plaintext))
// Use AES implementation of the cipher.Block interface to encrypt the whole
// file in CBC mode.
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext, plaintext)
if _, err = of.Write(ciphertext); err != nil {
return "", err
}
return outFilename, nil
}
// decryptFile decrypts the file specified by filename with the given key. See
// doc for encryptFile for more details.
func decryptFile(key []byte, filename string, outFilename string) (string, error) {
if len(outFilename) == 0 {
outFilename = filename + ".dec"
}
ciphertext, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
of, err := os.Create(outFilename)
if err != nil {
return "", err
}
defer of.Close()
// cipertext has the original plaintext size in the first 8 bytes, then IV
// in the next 16 bytes, then the actual ciphertext in the rest of the buffer.
// Read the original plaintext size, and the IV.
var origSize uint64
buf := bytes.NewReader(ciphertext)
if err = binary.Read(buf, binary.LittleEndian, &origSize); err != nil {
return "", err
}
iv := make([]byte, aes.BlockSize)
if _, err = buf.Read(iv); err != nil {
return "", err
}
// The remaining ciphertext has size=paddedSize.
paddedSize := len(ciphertext) - 8 - aes.BlockSize
if paddedSize%aes.BlockSize != 0 {
return "", fmt.Errorf("want padded plaintext size to be aligned to block size")
}
plaintext := make([]byte, paddedSize)
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(plaintext, ciphertext[8+aes.BlockSize:])
if _, err := of.Write(plaintext[:origSize]); err != nil {
return "", err
}
return outFilename, nil
}
func main() {
encFlag := flag.Bool("e", false, "encrypt")
decFlag := flag.Bool("d", false, "decrypt")
flag.Parse()
filename := flag.Arg(0)
// Uses a constant key
key := bytes.Repeat([]byte("1"), 32)
if *encFlag {
outFilename, err := encryptFile(key, filename, "")
if err != nil {
log.Fatal(err)
}
fmt.Println("Encrypted output file:", outFilename)
} else if *decFlag {
outFilename, err := decryptFile(key, filename, "")
if err != nil {
log.Fatal(err)
}
fmt.Println("Decrypted output file:", outFilename)
} else {
fmt.Println(flag.Usage)
os.Exit(1)
}
}
You can’t perform that action at this time.