diff options
Diffstat (limited to 'cmd/fscrypt/keys.go')
| -rw-r--r-- | cmd/fscrypt/keys.go | 67 |
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 |