feat(ssh): support passphrase-encrypted OpenSSH keys - #590
Open
ElCruncharino wants to merge 1 commit into
Open
Conversation
Adds bcrypt_pbkdf and the Blowfish schedule it needs (neither is in BouncyCastle), ported from OpenBSD's reference C. Verified against OpenBSD's own KAT vectors, golang.org/x/crypto/ssh's own encrypted-key fixtures, and real ssh-keygen/age round trips. Constants live in their own file (BlowfishConstants.kt) so the actual logic in Blowfish.kt stays a normal size. A wrong passphrase now throws IncorrectPassphraseException (a subtype of InvalidSshKeyException) instead of the generic checksum-mismatch error, so callers can show a useful message. bcrypt kdf rounds are capped at 1000, matching the existing ScryptIdentity.maxWorkFactor precedent, so a hostile key file can't force an unbounded-cost decrypt.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#547 added ssh-ed25519 and ssh-rsa support, but only for unencrypted keys. This adds the common case: a passphrase-encrypted key from
ssh-keygen.OpenSSH derives the key from your passphrase with
bcrypt_pbkdf(not textbook bcrypt), then encrypts with AES-CTR or AES-CBC. Neitherbcrypt_pbkdfnor its underlying Blowfish schedule is in BouncyCastle, soBcryptPbkdf.kt/Blowfish.ktare ported from OpenBSD's own C reference, with constants and known-answer vectors pulled from that source by script instead of hand-typed.SshKey.parseIdentitygets apassphrase: ByteArrayoverload. A wrong passphrase throwsIncorrectPassphraseException(a subtype ofInvalidSshKeyException) instead of a generic checksum error. KDF rounds are capped at 1000, the same precedent asScryptIdentity.maxWorkFactor.Tested against OpenBSD's own known-answer vectors, real
ssh-keygenoutput, and two ofgolang.org/x/crypto/ssh's encrypted-key fixtures, the same corpus age's own SSH support tests against.Notes for review:
SshKey.parseIdentity(privateKey, passphrase),IncorrectPassphraseException. In thekage.apidiff.InvalidSshKeyExceptionis nowopensoIncorrectPassphraseExceptioncan extend it../gradlew test checkKotlinAbi animalsnifferMain spotlessCheck.