Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-455: ensure BaseCipher.update() fulfills the contract #463

Merged
merged 1 commit into from
Feb 21, 2024

Conversation

tomaswolf
Copy link
Member

The org.apache.sshd.common.cipher.Cipher interface specifies for update(byte[] buffer, int offset, int length) that length bytes are encrypted or decrypted in-place in the given buffer, starting at the given offset.

The BaseCipher implementation just called javax.crypto.Cipher.update(). That, however, may buffer blocks and not update all data right away. (For instance, AES pipelined implementations may behave that way.) Buffered blocks may be returned/updated in subsequent update() calls. To ensure that really all bytes given are updated, one needs to call doFinal(), which always returns/updates such buffered blocks.

But javax.crypto.Cipher.doFinal() resets the cipher to its initial state. For use in SSH, this is not appropriate: the cipher must be reset not to the initial state but to the final state. This is done for CTR ciphers by adding the number of processed blocks to the initial IV and then using that IV for re-initialization. For CBC ciphers, the re-initialization IV must be the last encrypted block processed.

Note that in CTR mode, we cannot check for IV re-use. This is not a problem in practice because in the SSH protocol key exchanges happen long before an IV can wrap around.

Fixes #455.

The org.apache.sshd.common.cipher.Cipher interface specifies for
update(byte[] buffer, int offset, int length) that length bytes are
encrypted or decrypted in-place in the given buffer, starting at the
given offset.

The BaseCipher implementation just called javax.crypto.Cipher.update().
That, however, may buffer blocks and not update all data right away.
(For instance, AES pipelined implementations may behave that way.)
Buffered blocks may be returned/updated in subsequent update() calls.
To ensure that really all bytes given are updated, one needs to call
doFinal(), which always returns/updates such buffered blocks.

But javax.crypto.Cipher.doFinal() resets the cipher to its initial
state. For use in SSH, this is not appropriate: the cipher must be
reset not to the initial state but to the final state. This is done
for CTR ciphers by adding the number of processed blocks to the initial
IV and then using that IV for re-initialization. For CBC ciphers, the
re-initialization IV must be the last encrypted block processed.

Note that in CTR mode, we cannot check for IV re-use. This is not a
problem in practice because in the SSH protocol key exchanges happen
long before an IV can wrap around.
@tomaswolf tomaswolf merged commit ee382b0 into apache:master Feb 21, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
1 participant