Release: 1.2.2
Environment
AMD K6-II 400, Redhat 8.0, bash script, 4096 bit key
Description
Creating a pipe command I used '-e -' to encode from stdin, the program didn't give any warnings about using -, and it seemed to work but occasionally produced unreadable output files.
Using - for stdin will occasionally produce a corrupt output file that can only be decrypted upto the first 4096 bytes.
Program determines if stdin is being used with code like this:
if (filename) /* testing for null */
{
/* stdin code */
}
else
{
/* explicit file name code */
}
However if '-' is used for stdin then filename is not NULL, it points to a string containing '-'.
The intermittent problem happens because of similar code in 'encode_simple' and 'encode_crypt':
if( filename && !opt.textmode ) {
off_t tmpsize;
if ( !(tmpsize = iobuf_get_filelength(inp)) )
log_info(_("%s: WARNING: empty file\n"), filename );
/* We can't encode the length of very large files because
OpenPGP uses only 32 bit for file sizes. So if the the
size of a file is larger than 2^32 minus some bytes for
packet headers, we switch to partial length encoding. */
if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
filesize = tmpsize;
else
filesize = 0;
}
else
filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */The 'iobuf_get_filelength' call expects a file but when used on stdin (because '-' was used) it returns 0 sometimes other times it returns a number. I suspect this is a timing issue with pipes. Sometimes stdin will have pending bytes at this point, and sometimes not.
How To Repeat
Used with GNUPG source README file:
cat README | gpg -r user@somehost.com -o test.gpg -e -
Outputs message:
gpg: do_plaintext(): wrote 26446 bytes but expected 4096 bytes
When tyring to decrypt:
$ gpg -o test.txt -d test.gpg
You need a passphrase to unlock the secret key for
user: "xxxxx <xxxxx@xxxx>"
4096-bit ELG-E key, ID 8D8E8035, created 2003-05-12 (main key ID 867E58B2)
gpg: encrypted with 4096-bit ELG-E key, ID 8D8E8035, created 2003-05-12
"video <video@beast4>"
gpg: [don't know]: invalid packet (ctb=2d)
gpg: [don't know]: invalid packet (ctb=78)
gpg: WARNING: encrypted message has been manipulated!
gpg: [don't know]: invalid packet (ctb=2e)
Only first 4096 bytes of file are decrypted successfully.
Fix
In g10.c I changed the line in main():
fname = argc? *argv : NULL;
to:
if (argc > 0)
{
if (strcmp(*argv, "-") != 0)
{
fname = *argv;
}
else
{
fname = NULL;
}else
{
fname = NULL;
}
This seemed to work, however to keep using the official release I simply removed the '-' from the command line:
cat README | gpg -r user@somehost.com -o test.gpg -e
which works fine without changing code.
Release Note
Checked at that only valid filenames are passed to iobuf_get_filelength.
Thanks for this very detailed bug report.