Move {En,De}cryptCBC and MakeRandom to symcrypt.

The symcrypt package now contains common secret-key code that is
redefined in a number of packages.
This commit is contained in:
Kyle
2014-01-10 03:58:43 -07:00
parent a696c85bba
commit 1916f385ed
5 changed files with 113 additions and 112 deletions

View File

@@ -9,13 +9,13 @@ import (
"crypto/aes"
"crypto/cipher"
"crypto/hmac"
"crypto/rand"
"crypto/sha1"
"encoding/json"
"errors"
"github.com/cloudflare/redoctober/keycache"
"github.com/cloudflare/redoctober/padding"
"github.com/cloudflare/redoctober/passvault"
"github.com/cloudflare/redoctober/symcrypt"
"sort"
"strconv"
)
@@ -51,13 +51,6 @@ type EncryptedData struct {
Signature []byte
}
// makeRandom is a helper to make new buffer full of random data
func makeRandom(length int) (bytes []byte, err error) {
bytes = make([]byte, length)
_, err = rand.Read(bytes)
return
}
// encryptKey encrypts data with the key associated with name inner,
// then name outer
func encryptKey(nameInner, nameOuter string, clearKey []byte, pubKeys map[string]SingleWrappedKey) (out MultiWrappedKey, err error) {
@@ -265,7 +258,7 @@ func Encrypt(in []byte, names []string, min int) (resp []byte, err error) {
}
// Generate random IV and encryption key
ivBytes, err := makeRandom(16)
ivBytes, err := symcrypt.MakeRandom(16)
if err != nil {
return
}
@@ -274,7 +267,7 @@ func Encrypt(in []byte, names []string, min int) (resp []byte, err error) {
// encrypted.IV
encrypted.IV = append([]byte{}, ivBytes...)
clearKey, err := makeRandom(16)
clearKey, err := symcrypt.MakeRandom(16)
if err != nil {
return
}
@@ -295,7 +288,7 @@ func Encrypt(in []byte, names []string, min int) (resp []byte, err error) {
if rec.GetType() == passvault.RSARecord || rec.GetType() == passvault.ECCRecord {
// only wrap key with RSA key if found
if singleWrappedKey.aesKey, err = makeRandom(16); err != nil {
if singleWrappedKey.aesKey, err = symcrypt.MakeRandom(16); err != nil {
return nil, err
}

View File

@@ -6,7 +6,6 @@ package ecdh
import (
"crypto/aes"
"crypto/cipher"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/hmac"
@@ -14,6 +13,7 @@ import (
"crypto/sha1"
"errors"
"github.com/cloudflare/redoctober/padding"
"github.com/cloudflare/redoctober/symcrypt"
)
var Curve = elliptic.P256
@@ -37,13 +37,13 @@ func Encrypt(pub ecdsa.PublicKey, in []byte) (out []byte, err error) {
return nil, errors.New("Failed to generate encryption key")
}
shared := x.Bytes()
iv, err := makeRandom(16)
iv, err := symcrypt.MakeRandom(16)
if err != nil {
return
}
paddedIn := padding.AddPadding(in)
ct, err := encryptCBC(paddedIn, iv, shared[:16])
ct, err := symcrypt.EncryptCBC(paddedIn, iv, shared[:16])
if err != nil {
return
}
@@ -92,50 +92,10 @@ func Decrypt(priv *ecdsa.PrivateKey, in []byte) (out []byte, err error) {
return nil, errors.New("Invalid MAC")
}
paddedOut, err := decryptCBC(ct[aes.BlockSize:tagStart], ct[:aes.BlockSize], shared[:16])
paddedOut, err := symcrypt.DecryptCBC(ct[aes.BlockSize:tagStart], ct[:aes.BlockSize], shared[:16])
if err != nil {
return
}
out, err = padding.RemovePadding(paddedOut)
return
}
// Utility functions copied from passvault. These handle encryption
// and decryption of data using AES-128-CBC.
// decryptCBC decrypt bytes using a key and IV with AES in CBC mode.
func decryptCBC(data, iv, key []byte) (decryptedData []byte, err error) {
aesCrypt, err := aes.NewCipher(key)
if err != nil {
return
}
ivBytes := append([]byte{}, iv...)
decryptedData = make([]byte, len(data))
aesCBC := cipher.NewCBCDecrypter(aesCrypt, ivBytes)
aesCBC.CryptBlocks(decryptedData, data)
return
}
// encryptCBC encrypt data using a key and IV with AES in CBC mode.
func encryptCBC(data, iv, key []byte) (encryptedData []byte, err error) {
aesCrypt, err := aes.NewCipher(key)
if err != nil {
return
}
ivBytes := append([]byte{}, iv...)
encryptedData = make([]byte, len(data))
aesCBC := cipher.NewCBCEncrypter(aesCrypt, ivBytes)
aesCBC.CryptBlocks(encryptedData, data)
return
}
// makeRandom is a helper that makes a new buffer full of random data
func makeRandom(length int) ([]byte, error) {
bytes := make([]byte, length)
_, err := rand.Read(bytes)
return bytes, err
}

View File

@@ -10,7 +10,6 @@ import (
"bytes"
"code.google.com/p/go.crypto/scrypt"
"crypto/aes"
"crypto/cipher"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
@@ -22,6 +21,7 @@ import (
"errors"
"github.com/cloudflare/redoctober/ecdh"
"github.com/cloudflare/redoctober/padding"
"github.com/cloudflare/redoctober/symcrypt"
"io/ioutil"
"math/big"
mrand "math/rand"
@@ -97,7 +97,7 @@ type Summary struct {
func init() {
// seed math.random from crypto.random
seedBytes, _ := makeRandom(8)
seedBytes, _ := symcrypt.MakeRandom(8)
seedBuf := bytes.NewBuffer(seedBytes)
n64, _ := binary.ReadVarint(seedBuf)
mrand.Seed(n64)
@@ -109,40 +109,33 @@ func hashPassword(password string, salt []byte) ([]byte, error) {
return scrypt.Key([]byte(password), salt, N, R, P, KEYLENGTH)
}
// makeRandom is a helper that makes a new buffer full of random data
func makeRandom(length int) ([]byte, error) {
bytes := make([]byte, length)
_, err := rand.Read(bytes)
return bytes, err
}
// encryptRSARecord takes an RSA private key and encrypts it with
// a password key
func encryptRSARecord(newRec *PasswordRecord, rsaPriv *rsa.PrivateKey, passKey []byte) (err error) {
if newRec.RSAKey.RSAExpIV, err = makeRandom(16); err != nil {
if newRec.RSAKey.RSAExpIV, err = symcrypt.MakeRandom(16); err != nil {
return
}
paddedExponent := padding.AddPadding(rsaPriv.D.Bytes())
if newRec.RSAKey.RSAExp, err = encryptCBC(paddedExponent, newRec.RSAKey.RSAExpIV, passKey); err != nil {
if newRec.RSAKey.RSAExp, err = symcrypt.EncryptCBC(paddedExponent, newRec.RSAKey.RSAExpIV, passKey); err != nil {
return
}
if newRec.RSAKey.RSAPrimePIV, err = makeRandom(16); err != nil {
if newRec.RSAKey.RSAPrimePIV, err = symcrypt.MakeRandom(16); err != nil {
return
}
paddedPrimeP := padding.AddPadding(rsaPriv.Primes[0].Bytes())
if newRec.RSAKey.RSAPrimeP, err = encryptCBC(paddedPrimeP, newRec.RSAKey.RSAPrimePIV, passKey); err != nil {
if newRec.RSAKey.RSAPrimeP, err = symcrypt.EncryptCBC(paddedPrimeP, newRec.RSAKey.RSAPrimePIV, passKey); err != nil {
return
}
if newRec.RSAKey.RSAPrimeQIV, err = makeRandom(16); err != nil {
if newRec.RSAKey.RSAPrimeQIV, err = symcrypt.MakeRandom(16); err != nil {
return
}
paddedPrimeQ := padding.AddPadding(rsaPriv.Primes[1].Bytes())
newRec.RSAKey.RSAPrimeQ, err = encryptCBC(paddedPrimeQ, newRec.RSAKey.RSAPrimeQIV, passKey)
newRec.RSAKey.RSAPrimeQ, err = symcrypt.EncryptCBC(paddedPrimeQ, newRec.RSAKey.RSAPrimeQIV, passKey)
return
}
@@ -154,12 +147,12 @@ func encryptECCRecord(newRec *PasswordRecord, ecPriv *ecdsa.PrivateKey, passKey
return
}
if newRec.ECKey.ECPrivIV, err = makeRandom(16); err != nil {
if newRec.ECKey.ECPrivIV, err = symcrypt.MakeRandom(16); err != nil {
return
}
paddedX509 := padding.AddPadding(ecX509)
newRec.ECKey.ECPriv, err = encryptCBC(paddedX509, newRec.ECKey.ECPrivIV, passKey)
newRec.ECKey.ECPriv, err = symcrypt.EncryptCBC(paddedX509, newRec.ECKey.ECPrivIV, passKey)
return
}
@@ -167,7 +160,7 @@ func encryptECCRecord(newRec *PasswordRecord, ecPriv *ecdsa.PrivateKey, passKey
func createPasswordRec(password string, admin bool) (newRec PasswordRecord, err error) {
newRec.Type = DefaultRecordType
if newRec.PasswordSalt, err = makeRandom(16); err != nil {
if newRec.PasswordSalt, err = symcrypt.MakeRandom(16); err != nil {
return
}
@@ -175,7 +168,7 @@ func createPasswordRec(password string, admin bool) (newRec PasswordRecord, err
return
}
if newRec.KeySalt, err = makeRandom(16); err != nil {
if newRec.KeySalt, err = symcrypt.MakeRandom(16); err != nil {
return
}
@@ -211,7 +204,7 @@ func createPasswordRec(password string, admin bool) (newRec PasswordRecord, err
}
// encrypt AES key with password key
aesKey, err := makeRandom(16)
aesKey, err := symcrypt.MakeRandom(16)
if err != nil {
return
}
@@ -257,36 +250,6 @@ func encryptECB(data, key []byte) (encryptedData []byte, err error) {
return
}
// decryptCBC decrypt bytes using a key and IV with AES in CBC mode.
func decryptCBC(data, iv, key []byte) (decryptedData []byte, err error) {
aesCrypt, err := aes.NewCipher(key)
if err != nil {
return
}
ivBytes := append([]byte{}, iv...)
decryptedData = make([]byte, len(data))
aesCBC := cipher.NewCBCDecrypter(aesCrypt, ivBytes)
aesCBC.CryptBlocks(decryptedData, data)
return
}
// encryptCBC encrypt data using a key and IV with AES in CBC mode.
func encryptCBC(data, iv, key []byte) (encryptedData []byte, err error) {
aesCrypt, err := aes.NewCipher(key)
if err != nil {
return
}
ivBytes := append([]byte{}, iv...)
encryptedData = make([]byte, len(data))
aesCBC := cipher.NewCBCEncrypter(aesCrypt, ivBytes)
aesCBC.CryptBlocks(encryptedData, data)
return
}
// InitFromDisk reads the record from disk and initialize global context.
func InitFromDisk(path string) error {
jsonDiskRecord, err := ioutil.ReadFile(path)
@@ -358,7 +321,7 @@ func InitFromDisk(path string) error {
if records.Version == 0 {
records.Version = DEFAULT_VERSION
records.VaultId = int(mrand.Int31())
records.HmacKey, err = makeRandom(16)
records.HmacKey, err = symcrypt.MakeRandom(16)
if err != nil {
return err
}
@@ -429,14 +392,14 @@ func ChangePassword(name, password, newPassword string) (err error) {
}
// add the password salt and hash
if pr.PasswordSalt, err = makeRandom(16); err != nil {
if pr.PasswordSalt, err = symcrypt.MakeRandom(16); err != nil {
return
}
if pr.HashedPassword, err = hashPassword(newPassword, pr.PasswordSalt); err != nil {
return
}
if pr.KeySalt, err = makeRandom(16); err != nil {
if pr.KeySalt, err = symcrypt.MakeRandom(16); err != nil {
return
}
newPassKey, err := derivePasswordKey(newPassword, pr.KeySalt)
@@ -623,7 +586,7 @@ func (pr PasswordRecord) GetKeyECC(password string) (key *ecdsa.PrivateKey, err
return
}
x509Padded, err := decryptCBC(pr.ECKey.ECPriv, pr.ECKey.ECPrivIV, passKey)
x509Padded, err := symcrypt.DecryptCBC(pr.ECKey.ECPriv, pr.ECKey.ECPrivIV, passKey)
if err != nil {
return
}
@@ -651,7 +614,7 @@ func (pr PasswordRecord) GetKeyRSA(password string) (key rsa.PrivateKey, err err
return
}
rsaExponentPadded, err := decryptCBC(pr.RSAKey.RSAExp, pr.RSAKey.RSAExpIV, passKey)
rsaExponentPadded, err := symcrypt.DecryptCBC(pr.RSAKey.RSAExp, pr.RSAKey.RSAExpIV, passKey)
if err != nil {
return
}
@@ -660,7 +623,7 @@ func (pr PasswordRecord) GetKeyRSA(password string) (key rsa.PrivateKey, err err
return
}
rsaPrimePPadded, err := decryptCBC(pr.RSAKey.RSAPrimeP, pr.RSAKey.RSAPrimePIV, passKey)
rsaPrimePPadded, err := symcrypt.DecryptCBC(pr.RSAKey.RSAPrimeP, pr.RSAKey.RSAPrimePIV, passKey)
if err != nil {
return
}
@@ -669,7 +632,7 @@ func (pr PasswordRecord) GetKeyRSA(password string) (key rsa.PrivateKey, err err
return
}
rsaPrimeQPadded, err := decryptCBC(pr.RSAKey.RSAPrimeQ, pr.RSAKey.RSAPrimeQIV, passKey)
rsaPrimeQPadded, err := symcrypt.DecryptCBC(pr.RSAKey.RSAPrimeQ, pr.RSAKey.RSAPrimeQIV, passKey)
if err != nil {
return
}

46
symcrypt/symcrypt.go Normal file
View File

@@ -0,0 +1,46 @@
// Package symcrypt contains common symmetric encryption functions.
package symcrypt
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
)
// DecryptCBC decrypt bytes using a key and IV with AES in CBC mode.
func DecryptCBC(data, iv, key []byte) (decryptedData []byte, err error) {
aesCrypt, err := aes.NewCipher(key)
if err != nil {
return
}
ivBytes := append([]byte{}, iv...)
decryptedData = make([]byte, len(data))
aesCBC := cipher.NewCBCDecrypter(aesCrypt, ivBytes)
aesCBC.CryptBlocks(decryptedData, data)
return
}
// EncryptCBC encrypt data using a key and IV with AES in CBC mode.
func EncryptCBC(data, iv, key []byte) (encryptedData []byte, err error) {
aesCrypt, err := aes.NewCipher(key)
if err != nil {
return
}
ivBytes := append([]byte{}, iv...)
encryptedData = make([]byte, len(data))
aesCBC := cipher.NewCBCEncrypter(aesCrypt, ivBytes)
aesCBC.CryptBlocks(encryptedData, data)
return
}
// MakeRandom is a helper that makes a new buffer full of random data.
func MakeRandom(length int) ([]byte, error) {
bytes := make([]byte, length)
_, err := io.ReadFull(rand.Reader, bytes)
return bytes, err
}

39
symcrypt/symcrypt_test.go Normal file
View File

@@ -0,0 +1,39 @@
package symcrypt
import (
"bytes"
"github.com/cloudflare/redoctober/padding"
"testing"
)
func TestCrypt(t *testing.T) {
msg := []byte("One ping only, please.")
padMsg := padding.AddPadding(msg)
key, err := MakeRandom(16)
if err != nil {
t.Fatalf("%v", err)
}
iv, err := MakeRandom(16)
if err != nil {
t.Fatalf("%v", err)
}
out, err := EncryptCBC(padMsg, iv, key)
if err != nil {
t.Fatalf("%v", err)
}
out, err = DecryptCBC(out, iv, key)
if err != nil {
t.Fatalf("%v", err)
}
unpadOut, err := padding.RemovePadding(out)
if err != nil {
t.Fatalf("%v", err)
} else if !bytes.Equal(unpadOut, msg) {
t.Fatal("Decrypted message doesn't match original plaintext.")
}
}