Skip to content

Instantly share code, notes, and snippets.

@ayubmalik
Last active September 27, 2023 19:43
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ayubmalik/2c973c2a7ae7e0d22ece7f5c4dfbd726 to your computer and use it in GitHub Desktop.
Save ayubmalik/2c973c2a7ae7e0d22ece7f5c4dfbd726 to your computer and use it in GitHub Desktop.
Go (golang) crypto sample using cipher.StreamWriter and cipher.StreamReader to wrap io.Writer and io.Reader with AES encryption.
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"crypto/rand"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
)
// EncryptedWriter wraps w with an OFB cipher stream.
func EncryptedWriter(key string, w io.Writer) (*cipher.StreamWriter, error) {
// generate random initial value
iv := make([]byte, aes.BlockSize)
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
// write clear IV to allow for decryption
n, err := w.Write(iv)
if err != nil || n != len(iv) {
return nil, errors.New("could not write initial value")
}
block, err := newBlock(key)
if err != nil {
return nil, err
}
stream := cipher.NewOFB(block, iv)
return &cipher.StreamWriter{S: stream, W: w}, nil
}
// EncryptedReader wraps r with an OFB cipher stream.
func EncryptedReader(key string, r io.Reader) (*cipher.StreamReader, error) {
// read initial value
iv := make([]byte, aes.BlockSize)
n, err := r.Read(iv)
if err != nil || n != len(iv) {
return nil, errors.New("could not read initial value")
}
block, err := newBlock(key)
if err != nil {
return nil, err
}
stream := cipher.NewOFB(block, iv)
return &cipher.StreamReader{S: stream, R: r}, nil
}
func newBlock(key string) (cipher.Block, error) {
hash := md5.Sum([]byte(key))
block, err := aes.NewCipher(hash[:])
if err != nil {
return nil, err
}
return block, nil
}
func main() {
// Load your secret key from a safe
// place and use for encrypt/decrypt
secretKey := "1234567890abcdefghijk"
/******************************************/
/* example to encrypt/decrypt to a string */
/******************************************/
var sb strings.Builder
w, err := EncryptedWriter(secretKey, &sb)
if err != nil {
panic(err)
}
// as w is a StreamWriter we can write/encrypt directly to it
w.Write([]byte("Hello gophers!"))
encrypted := sb.String()
fmt.Printf("encrypted message = %s\n", encrypted)
// as r is a StreamReader we can decrypt/read directly from it
r, err := EncryptedReader(secretKey, strings.NewReader(encrypted))
if err != nil {
panic(err)
}
decrypted, _ := ioutil.ReadAll(r)
fmt.Printf("decrypted message = %s\n", decrypted)
/*********************************************************/
/* example to encrypt/decrypt to a file */
/* skipping error handling and file.Close() for examples */
/*********************************************************/
file, err := os.Create("/tmp/encmsg.txt")
if err != nil {
panic(err)
}
w, _ = EncryptedWriter(secretKey, file)
io.WriteString(w, "Hello again gophers!")
file, _ = os.Open("/tmp/encmsg.txt") // use flags/file param for prod code
r, _ = EncryptedReader(secretKey, file)
contents, _ := ioutil.ReadAll(r)
fmt.Printf("contents of decrypted file = %s\n", contents)
}
@snowdream
Copy link

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment