can't pass password via stdin during decrypt
Environment
- OS: Linux 6.9.11
- age version: 1.2.0
PROBLEM
Currently (afaik) it's not possible to pass passphrase to age via stdin, like:
echo -n "$passphrase" | age -d -o output_file input_file
Here, age knows that stdin is NOT used for data, because I specified input file explicitly.
This also does not work with:
some_cli_password_manager | age -d -i - -o output_file input_file
Rationale:
- passphrase is eventually read from stdin
- sometimes you must use passswords (can't use keys) in script & automation
- most cli tools allows it (cryptsetup etc.)
- also #364
what if you pass it in like age ... <(echo -n "$passphrase") ...? Note that I didn't test, just aware of that shell feature.
what if you pass it in like
age ... <(echo -n "$passphrase") ...? Note that I didn't test, just aware of that shell feature.
Any method which is using stdin (like <( cmd ) here) will not work, due to the age not supporting passphrase via stdin during decryption. This is what I'm actually asking for :)
But the command I provided does not use stdin? It makes a pipe kind of file and returns the path to it to the command.
But the command I provided does not use stdin? It makes a pipe kind of file and returns the path to it to the command.
That will not work because age --decrypt does not take passphrase as an command line argument (see below age --help).
The problem is that INPUT may (but not must) be used by age for content of encrypt/decrypt operation, hence age must distinguish such mode (content on stdin) from password on stdin scenario, in two ways:
- either implictly (user provided input as filename) hence if stdin is attached it must be key/passphrase material,
- either explicitly (by using some kind of option plus stdin).
$ age --help
Usage:
age [--encrypt] (-r RECIPIENT | -R PATH)... [--armor] [-o OUTPUT] [INPUT]
age [--encrypt] --passphrase [--armor] [-o OUTPUT] [INPUT]
age --decrypt [-i PATH]... [-o OUTPUT] [INPUT]
Here, age knows that stdin is NOT used for data, because I specified input file explicitly.
But it needs to tell piped input vs terminal apart which might be tricky. E.g. this:
diff --git a/cmd/age/age.go b/cmd/age/age.go
index e5d17e2..29fa88e 100644
--- a/cmd/age/age.go
+++ b/cmd/age/age.go
@@ -455,10 +455,19 @@ func decryptNotPass(flags identityFlags, in io.Reader, out io.Writer) {
}
func decryptPass(in io.Reader, out io.Writer) {
+ passphrase := passphrasePromptForDecryption
+
+ if in != os.Stdin && !term.IsTerminal(int(os.Stdin.Fd())) {
+ passphrase = func() (string, error) {
+ b, err := io.ReadAll(os.Stdin)
+ return string(b), err
+ }
+ }
+
identities := []age.Identity{
// If there is an scrypt recipient (it will have to be the only one and)
// this identity will be invoked.
- &LazyScryptIdentity{passphrasePromptForDecryption},
+ &LazyScryptIdentity{passphrase},
}
decrypt(identities, in, out)
works in terminal but breaks testcript tests.
An alternative might be to add passphrase file flag and then use /dev/stdin as a value.
works in terminal but breaks testcript tests.
can you expand on this?
works in terminal but breaks testcript tests.
can you expand on this?
Some existing tests that use terminal input need to be fixed, see #641
The new batchpass plugin handles non-interactive passphrase encryption. See https://github.com/FiloSottile/age/discussions/256#discussioncomment-15334934 for usage and a warning.