Skip to content

Instantly share code, notes, and snippets.

@dchest
Last active December 21, 2015 09:19
Show Gist options
  • Select an option

  • Save dchest/6284090 to your computer and use it in GitHub Desktop.

Select an option

Save dchest/6284090 to your computer and use it in GitHub Desktop.
// Package secretentropy wraps any random Reader to produce a random Reader
// that mixes a secret into its output.
//
// Example usage with DSA where priv is *dsa.PrivateKey, and message is a
// message byte slice we're going to sign:
//
// srand := secretentropy.NewReader(rand.Reader, privateKey.X.Bytes(), message)
// r, s, err := dsa.Sign(srand, priv, messageHash)
//
package secretentropy
import (
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"encoding/binary"
"io"
"time"
)
// NewReader returns a new io.Reader that wraps rand, mixing it with secrets.
//
// Basically, the returned reader encrypts the bytes from rand with AES-256
// in CTR mode with key generated by hashing all given secrets with SHA-256.
func NewReader(rand io.Reader, secrets ...[]byte) io.Reader {
// Hash secrets into a 32-byte key.
h := sha256.New()
for _, s := range secrets {
h.Write(s)
}
key := h.Sum(nil)
// Wrap rand into AES-encrypted stream.
aesCipher, err := aes.NewCipher(key)
if err != nil {
panic("secretentropy: " + err.Error())
}
// Who cares about IV when we encrypt random bytes and secrets are
// supposed to be unique? It can as well be all-zero. Let's use time,
// because we can. Note: cipher's package CTR mode counter starts from
// the end of IV, so we put our "nonce" in the first 8 bytes.
var iv [aes.BlockSize]byte
binary.LittleEndian.PutUint64(iv[:], uint64(time.Now().UnixNano()))
return &cipher.StreamReader{S: cipher.NewCTR(aesCipher, iv[:]), R: rand}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment