aboutsummaryrefslogtreecommitdiff
path: root/cmd/fscrypt/keys.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/fscrypt/keys.go')
-rw-r--r--cmd/fscrypt/keys.go67
1 files changed, 40 insertions, 27 deletions
diff --git a/cmd/fscrypt/keys.go b/cmd/fscrypt/keys.go
index 872ca2a..b57c01d 100644
--- a/cmd/fscrypt/keys.go
+++ b/cmd/fscrypt/keys.go
@@ -22,13 +22,14 @@
package main
import (
+ "bufio"
"fmt"
"io"
"log"
"os"
"github.com/pkg/errors"
- "golang.org/x/crypto/ssh/terminal"
+ "golang.org/x/term"
"github.com/google/fscrypt/actions"
"github.com/google/fscrypt/crypto"
@@ -55,14 +56,14 @@ var (
// struct is empty as the reader needs to maintain no internal state.
type passphraseReader struct{}
-// Read gets input from the terminal until a newline is encountered. This read
-// should be called with the maximum buffer size for the passphrase.
+// Read gets input from the terminal until a newline is encountered or the given
+// buffer is full.
func (p passphraseReader) Read(buf []byte) (int, error) {
// We read one byte at a time to handle backspaces
position := 0
for {
if position == len(buf) {
- return position, ErrMaxPassphrase
+ return position, nil
}
if _, err := io.ReadFull(os.Stdin, buf[position:position+1]); err != nil {
return position, err
@@ -86,25 +87,53 @@ func (p passphraseReader) Read(buf []byte) (int, error) {
// passphrase into a key. If we are not reading from a terminal, just read into
// the passphrase into the key normally.
func getPassphraseKey(prompt string) (*crypto.Key, error) {
- if !quietFlag.Value {
- fmt.Print(prompt)
- }
// Only disable echo if stdin is actually a terminal.
- if terminal.IsTerminal(stdinFd) {
- state, err := terminal.MakeRaw(stdinFd)
+ if term.IsTerminal(stdinFd) {
+ state, err := term.MakeRaw(stdinFd)
if err != nil {
return nil, err
}
defer func() {
- terminal.Restore(stdinFd, state)
+ term.Restore(stdinFd, state)
fmt.Println() // To align input
}()
}
+ if !quietFlag.Value {
+ fmt.Print(prompt)
+ }
+
return crypto.NewKeyFromReader(passphraseReader{})
}
+func makeRawKey(info actions.ProtectorInfo) (*crypto.Key, error) {
+ // When running non-interactively and no key was provided,
+ // try to read it from stdin
+ if keyFileFlag.Value == "" && !term.IsTerminal(stdinFd) {
+ return crypto.NewFixedLengthKeyFromReader(bufio.NewReader(os.Stdin),
+ metadata.InternalKeyLen)
+ }
+
+ prompt := fmt.Sprintf("Enter key file for protector %q: ", info.Name())
+ // Raw keys use a file containing the key data.
+ file, err := promptForKeyFile(prompt)
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ fileInfo, err := file.Stat()
+ if err != nil {
+ return nil, err
+ }
+
+ if fileInfo.Size() != metadata.InternalKeyLen {
+ return nil, errors.Wrap(ErrKeyFileLength, file.Name())
+ }
+ return crypto.NewFixedLengthKeyFromReader(file, metadata.InternalKeyLen)
+}
+
// makeKeyFunc creates an actions.KeyFunc. This function customizes the KeyFunc
// to whether or not it supports retrying, whether it confirms the passphrase,
// and custom prefix for printing (if any).
@@ -178,23 +207,7 @@ func makeKeyFunc(supportRetry, shouldConfirm bool, prefix string) actions.KeyFun
if prefix != "" {
return nil, ErrNotPassphrase
}
- prompt := fmt.Sprintf("Enter key file for protector %q: ", info.Name())
- // Raw keys use a file containing the key data.
- file, err := promptForKeyFile(prompt)
- if err != nil {
- return nil, err
- }
- defer file.Close()
-
- fileInfo, err := file.Stat()
- if err != nil {
- return nil, err
- }
-
- if fileInfo.Size() != metadata.InternalKeyLen {
- return nil, errors.Wrap(ErrKeyFileLength, file.Name())
- }
- return crypto.NewFixedLengthKeyFromReader(file, metadata.InternalKeyLen)
+ return makeRawKey(info)
default:
return nil, ErrInvalidSource