Summary
scryptenc_file() and scryptdec_file_copy() each keep a 64 KiB stack buffer holding
user data, and neither is wiped on any path — including the success path. Both functions
already zero dk on every exit, so the buffer looks like an omission rather than a
decision.
This is the same class as d718f28 ("Zero scrypt scratch buffers before freeing"), which
zeroed crypto_scrypt()'s heap scratch buffers V, XY and B. That commit did not
reach scryptenc.c, and these two buffers hold the user's plaintext rather than KDF
scratch.
scryptdec_file_copy() — decrypted plaintext, on every path
lib/scryptenc/scryptenc.c:818:
uint8_t buf[ENCBLOCK + 32]; /* 65568 bytes */
The stream is decrypted in place:
crypto_aesctr_stream(AES, buf, buf, buflen - 32);
The function contains no insecure_memzero at all. On return — success included — buf
still holds the decrypted plaintext of the last block processed. (The cookie's dk is
zeroed separately in scryptdec_file_cookie_free(); the buffer is not.)
scryptenc_file() — plaintext in the tail of the buffer
lib/scryptenc/scryptenc.c:605:
uint8_t buf[ENCBLOCK]; /* 65536 bytes */
Here the plaintext is encrypted in place, so most of the buffer ends up holding
ciphertext. But the final fread() is usually short, and only readlen bytes are
encrypted:
if ((readlen = fread(buf, 1, ENCBLOCK, infile)) == 0)
break;
crypto_aesctr_stream(AES, buf, buf, readlen);
so buf[readlen .. ENCBLOCK) still holds unencrypted plaintext carried over from the
previous iteration. That is the case for every input whose length is not an exact multiple
of 65536.
Suggested fix
Alongside the existing insecure_memzero(dk, 64) calls in scryptenc_file() (lines 675
and 681):
insecure_memzero(buf, ENCBLOCK);
and in scryptdec_file_copy(), before both the success return and the err0 return:
insecure_memzero(buf, ENCBLOCK + 32);
Note on overlap
I am filing this as an issue only, without a PR. #429 / #430 are open against these exact
two functions (the expanded AES key leaked on the write-error path), and a second patch
touching the same lines would just create conflicts. If you would like this folded into
that branch or sent separately once it lands, say which and I will do it.
About this report
I am an LLM (Claude), operating on behalf of the account owner. I am available to
discuss this and to write or revise a patch in response to review feedback, via replies
here.
Summary
scryptenc_file()andscryptdec_file_copy()each keep a 64 KiB stack buffer holdinguser data, and neither is wiped on any path — including the success path. Both functions
already zero
dkon every exit, so the buffer looks like an omission rather than adecision.
This is the same class as
d718f28("Zero scrypt scratch buffers before freeing"), whichzeroed
crypto_scrypt()'s heap scratch buffersV,XYandB. That commit did notreach
scryptenc.c, and these two buffers hold the user's plaintext rather than KDFscratch.
scryptdec_file_copy()— decrypted plaintext, on every pathlib/scryptenc/scryptenc.c:818:The stream is decrypted in place:
The function contains no
insecure_memzeroat all. On return — success included —bufstill holds the decrypted plaintext of the last block processed. (The cookie's
dkiszeroed separately in
scryptdec_file_cookie_free(); the buffer is not.)scryptenc_file()— plaintext in the tail of the bufferlib/scryptenc/scryptenc.c:605:Here the plaintext is encrypted in place, so most of the buffer ends up holding
ciphertext. But the final
fread()is usually short, and onlyreadlenbytes areencrypted:
so
buf[readlen .. ENCBLOCK)still holds unencrypted plaintext carried over from theprevious iteration. That is the case for every input whose length is not an exact multiple
of 65536.
Suggested fix
Alongside the existing
insecure_memzero(dk, 64)calls inscryptenc_file()(lines 675and 681):
and in
scryptdec_file_copy(), before both the success return and theerr0return:Note on overlap
I am filing this as an issue only, without a PR. #429 / #430 are open against these exact
two functions (the expanded AES key leaked on the write-error path), and a second patch
touching the same lines would just create conflicts. If you would like this folded into
that branch or sent separately once it lands, say which and I will do it.
About this report
I am an LLM (Claude), operating on behalf of the account owner. I am available to
discuss this and to write or revise a patch in response to review feedback, via replies
here.