veyron/security/agent: Added encryption to agent and option not
to encrypt.

* Password will only be requested when the PEM Block is not encrypted.
* Next step is to change the agent from a signer to a principal. Coming
  soon...

Change-Id: I811bb6af636d83243052465039192c7bfa307cc1
diff --git a/security/util.go b/security/util.go
index 0ae070f..175d49f 100644
--- a/security/util.go
+++ b/security/util.go
@@ -28,42 +28,50 @@
 	return acl
 }
 
-// LoadPEMKey loads a key from 'r', assuming that it was saved using SavePEMKey
-// and the specified passphrase 'passphrase'.
-// If passphrase is nil, the key will still be encrypted with a random salt, but
-// this will offer no protection as the salt is stored with the PEMKey.
-func LoadPEMKey(r io.Reader, passphrase []byte) (interface{}, error) {
-	pemKeyBytes, err := ioutil.ReadAll(r)
+var MissingPassphraseErr = errors.New("passphrase required for decrypting private key")
+
+// loadPEMKey loads a key from 'r'. passphrase should be non-nil if the key held in 'r' is
+// encrypted, otherwise a MissingPassphraseErr will be returned.
+// If the key held in 'r' is unencrypted, 'passphrase' will be ignored.
+func loadPEMKey(r io.Reader, passphrase []byte) (interface{}, error) {
+	pemBlockBytes, err := ioutil.ReadAll(r)
 	if err != nil {
 		return nil, err
 	}
-
-	pemKey, _ := pem.Decode(pemKeyBytes)
-	if pemKey == nil {
+	pemBlock, _ := pem.Decode(pemBlockBytes)
+	if pemBlock == nil {
 		return nil, errors.New("no PEM key block read")
 	}
-
-	data, err := x509.DecryptPEMBlock(pemKey, passphrase)
-	if err != nil {
-		return nil, err
+	var data []byte
+	if x509.IsEncryptedPEMBlock(pemBlock) {
+		if passphrase == nil {
+			return nil, MissingPassphraseErr
+		}
+		data, err = x509.DecryptPEMBlock(pemBlock, passphrase)
+		if err != nil {
+			return nil, err
+		}
+	} else {
+		data = pemBlock.Bytes
 	}
 
-	switch pemKey.Type {
+	switch pemBlock.Type {
 	case ecPrivateKeyPEMType:
 		return x509.ParseECPrivateKey(data)
 	}
-	return nil, fmt.Errorf("PEM key block has an unrecognized type: %v", pemKey.Type)
+	return nil, fmt.Errorf("PEM key block has an unrecognized type: %v", pemBlock.Type)
 }
 
-// SavePEMKey marshals 'key', encrypts it using 'passphrase', and saves the bytes to 'w' in PEM format.
+// savePEMKey marshals 'key', encrypts it using 'passphrase', and saves the bytes to 'w' in PEM format.
+// If passphrase is nil, the key will not be encrypted.
 //
 // For example, if key is an ECDSA private key, it will be marshaled
 // in ASN.1, DER format, encrypted, and then written in a PEM block.
-func SavePEMKey(w io.Writer, key interface{}, passphrase []byte) error {
+func savePEMKey(w io.Writer, key interface{}, passphrase []byte) error {
 	var data []byte
+	var err error
 	switch k := key.(type) {
 	case *ecdsa.PrivateKey:
-		var err error
 		if data, err = x509.MarshalECPrivateKey(k); err != nil {
 			return err
 		}
@@ -71,9 +79,17 @@
 		return fmt.Errorf("key of type %T cannot be saved", k)
 	}
 
-	pemKey, err := x509.EncryptPEMBlock(rand.Reader, ecPrivateKeyPEMType, data, passphrase, x509.PEMCipherAES256)
-	if err != nil {
-		return fmt.Errorf("failed to encrypt pem block: %v", err)
+	var pemKey *pem.Block
+	if passphrase != nil {
+		pemKey, err = x509.EncryptPEMBlock(rand.Reader, ecPrivateKeyPEMType, data, passphrase, x509.PEMCipherAES256)
+		if err != nil {
+			return fmt.Errorf("failed to encrypt pem block: %v", err)
+		}
+	} else {
+		pemKey = &pem.Block{
+			Type:  ecPrivateKeyPEMType,
+			Bytes: data,
+		}
 	}
 
 	return pem.Encode(w, pemKey)