-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
OpenSSHKey: correctly parse aes-256-cbc/ctr keys #1682
OpenSSHKey: correctly parse aes-256-cbc/ctr keys #1682
Conversation
There's some work to be done to fix the tests, working on that now. |
I've updated the tests to include an AES-256-CBC and AES-256-CTR key, as emitted by
|
If anyone can tell me why it's not able to decrypt those two encrypted RSA keys in the two new tests, that'd be great. OpenSSL doesn't have any trouble with them, and I'm not sure what's going wrong in KeePassXC. |
Found the problem. It was a key size issue. We were using a 16-byte key and not filling out the full 32-byte width required for AES256. |
src/sshagent/OpenSSHKey.cpp
Outdated
QByteArray keyData = hash.result(); | ||
QByteArray keyData; | ||
QByteArray mdBuf; | ||
mdBuf.resize(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Freshly constructed QByteArray is zero length so this would be superfluous.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True enough. I'll drop that.
@@ -90,39 +90,39 @@ void TestOpenSSHKey::testParseDSA() | |||
QCOMPARE(key.fingerprint(), QString("SHA256:tbbNuLN1hja8JNASDTlLOZQsbTlJDzJlz/oAGK3sX18")); | |||
} | |||
|
|||
void TestOpenSSHKey::testDecryptAES128CBC() | |||
void TestOpenSSHKey::testDecryptRSAAES128CBC() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is nitpicking on something I started but maybe this naming scheme doesn't work any more. I'm thinking of using the KDF rather than "RSA" or "PEM". So "MD5" in this case and "BCrypt" for encrypted OpenSSH keys. Not really important anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The naming scheme made me cringe a bit as I was writing it. But there is a distinction to be made between RSA/OpenSSH key files.
Looks good to me. Could you please rebase this against release/2.3.2? Thanks. |
Done! |
src/sshagent/OpenSSHKey.cpp
Outdated
QByteArray keyData = hash.result(); | ||
QByteArray keyData; | ||
QByteArray mdBuf; | ||
for (;;) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should use a do/while loop instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's really nitpicky.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe, but it's ensuring we are keeping a consistent style. And TBH, an empty for loop header is just extremely ugly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed, but I'm not sure it looks any better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does. Thank you very much.
cipher.reset(new SymmetricCipher(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Decrypt)); | ||
} else if (m_cipherName == "aes256-ctr") { | ||
} else if (m_cipherName == "aes256-ctr" || m_cipherName.compare("aes-256-ctr", Qt::CaseInsensitive) == 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use comparison operator with the first one but compare()
with the second one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could probably just make it a comparison operator, but the .compare is copying the behavior used for the aes-128-cbc above this.
With the OpenSSH key type it is presumably fixed lower case while with encrypted RSA PEMs it could be upper or lower case? I don't think I've ever seen an encrypted RSA PEM with DEK-Info
parameter of aes-128-cbc
in lower case, but it seems this code was already prepared for that possibility. Could just move them both to == operators.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
compare is used for case-insensitive comparison. == cannot do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The DEK-Info cipher was normalized to lowercase as the OpenSSH key types are lowercase as well.
@@ -319,9 +319,9 @@ bool OpenSSHKey::openPrivateKey(const QString& passphrase) | |||
|
|||
if (m_cipherName.compare("aes-128-cbc", Qt::CaseInsensitive) == 0) { | |||
cipher.reset(new SymmetricCipher(SymmetricCipher::Aes128, SymmetricCipher::Cbc, SymmetricCipher::Decrypt)); | |||
} else if (m_cipherName == "aes256-cbc") { | |||
} else if (m_cipherName == "aes256-cbc" || m_cipherName.compare("aes-256-cbc", Qt::CaseInsensitive) == 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same ==
versus .compare()
here.
996a5e8
to
a5e607b
Compare
a5e607b
to
e0d9918
Compare
AES-256 uses a 32-byte (256-bit) key size. This un-breaks the loader and tests added for AES-256-CBC and AES-256-CTR PEM keys. Signed-off-by: Steven Noonan <[email protected]>
Signed-off-by: Steven Noonan <[email protected]>
e0d9918
to
2202f07
Compare
Ping @tycho @phoerious @hifi is this ready for merge? |
I believe it's been ready for some time. Just waiting on someone to sign off on it... |
- Enable high entropy ASLR on Windows [#1747] - Enhance favicon fetching [#1786] - Fix crash on Windows due to autotype [#1691] - Fix dark tray icon changing all icons [#1680] - Fix --pw-stdin not using getPassword function [#1686] - Fix placeholders being resolved in notes [#1907] - Enable auto-type start delay to be configurable [#1908] - Browser: Fix native messaging reply size [#1719] - Browser: Increase maximum buffer size [#1720] - Browser: Enhance usability and functionality [#1810, #1822, #1830, #1884, #1906] - SSH Agent: Parse aes-256-cbc/ctr keys [#1682] - SSH Agent: Enhance usability and functionality [#1677, #1679, #1681, #1787]
AES-256 uses a 32-byte (256-bit) key size. This un-breaks the loader and tests added for AES-256-CBC and AES-256-CTR PEM keys. * OpenSSHKey: correctly parse encrypted PEM AES-256-CBC/AES-256-CTR keys * OpenSSHKey: use correct key derivation for AES-256
Description
The code for parsing OpenSSH private key files is broken for aes-256-cbc and aes-256-ctr encrypted keys in PEM format.
Motivation and context
... to correctly load encrypted SSH keys.
How has this been tested?
Not fully tested yet.
Types of changes
Checklist:
-DWITH_ASAN=ON
. [REQUIRED]