diff --git a/src/libs/ssh/sshbotanconversions_p.h b/src/libs/ssh/sshbotanconversions_p.h index 3b1fd2fce89..ae8fb9806c9 100644 --- a/src/libs/ssh/sshbotanconversions_p.h +++ b/src/libs/ssh/sshbotanconversions_p.h @@ -32,6 +32,7 @@ #define SSHBOTANCONVERSIONS_P_H #include "sshcapabilities_p.h" +#include "sshexception_p.h" #include @@ -63,10 +64,22 @@ inline const char *botanKeyExchangeAlgoName(const QByteArray &rfcAlgoName) inline const char *botanCryptAlgoName(const QByteArray &rfcAlgoName) { - Q_ASSERT(rfcAlgoName == SshCapabilities::CryptAlgo3Des - || rfcAlgoName == SshCapabilities::CryptAlgoAes128); - return rfcAlgoName == SshCapabilities::CryptAlgo3Des - ? "TripleDES" : "AES-128"; + if (rfcAlgoName == SshCapabilities::CryptAlgoAes128Cbc + || rfcAlgoName == SshCapabilities::CryptAlgoAes128Ctr) { + return "AES-128"; + } + if (rfcAlgoName == SshCapabilities::CryptAlgo3DesCbc + || rfcAlgoName == SshCapabilities::CryptAlgo3DesCtr) { + return "TripleDES"; + } + if (rfcAlgoName == SshCapabilities::CryptAlgoAes192Ctr) { + return "AES-192"; + } + if (rfcAlgoName == SshCapabilities::CryptAlgoAes256Ctr) { + return "AES-256"; + } + throw SshClientException(SshInternalError, SSH_TR("Unexpected cipher \"%1\"") + .arg(QString::fromLatin1(rfcAlgoName))); } inline const char *botanEmsaAlgoName(const QByteArray &rfcAlgoName) diff --git a/src/libs/ssh/sshcapabilities.cpp b/src/libs/ssh/sshcapabilities.cpp index 41d89b74e69..bbabafe10a9 100644 --- a/src/libs/ssh/sshcapabilities.cpp +++ b/src/libs/ssh/sshcapabilities.cpp @@ -62,11 +62,19 @@ const QList SshCapabilities::PublicKeyAlgorithms = QList() << SshCapabilities::PubKeyRsa << SshCapabilities::PubKeyDss; -const QByteArray SshCapabilities::CryptAlgo3Des("3des-cbc"); -const QByteArray SshCapabilities::CryptAlgoAes128("aes128-cbc"); +const QByteArray SshCapabilities::CryptAlgo3DesCbc("3des-cbc"); +const QByteArray SshCapabilities::CryptAlgo3DesCtr("3des-ctr"); +const QByteArray SshCapabilities::CryptAlgoAes128Cbc("aes128-cbc"); +const QByteArray SshCapabilities::CryptAlgoAes128Ctr("aes128-ctr"); +const QByteArray SshCapabilities::CryptAlgoAes192Ctr("aes192-ctr"); +const QByteArray SshCapabilities::CryptAlgoAes256Ctr("aes256-ctr"); const QList SshCapabilities::EncryptionAlgorithms - = QList() << SshCapabilities::CryptAlgoAes128 - << SshCapabilities::CryptAlgo3Des; + = QList() << SshCapabilities::CryptAlgoAes256Ctr + << SshCapabilities::CryptAlgoAes192Ctr + << SshCapabilities::CryptAlgoAes128Ctr + << SshCapabilities::CryptAlgo3DesCtr + << SshCapabilities::CryptAlgoAes128Cbc + << SshCapabilities::CryptAlgo3DesCbc; const QByteArray SshCapabilities::HMacSha1("hmac-sha1"); const QByteArray SshCapabilities::HMacSha196("hmac-sha1-96"); diff --git a/src/libs/ssh/sshcapabilities_p.h b/src/libs/ssh/sshcapabilities_p.h index 469578b7685..af51b23d44b 100644 --- a/src/libs/ssh/sshcapabilities_p.h +++ b/src/libs/ssh/sshcapabilities_p.h @@ -48,8 +48,12 @@ public: static const QByteArray PubKeyRsa; static const QList PublicKeyAlgorithms; - static const QByteArray CryptAlgo3Des; - static const QByteArray CryptAlgoAes128; + static const QByteArray CryptAlgo3DesCbc; + static const QByteArray CryptAlgo3DesCtr; + static const QByteArray CryptAlgoAes128Cbc; + static const QByteArray CryptAlgoAes128Ctr; + static const QByteArray CryptAlgoAes192Ctr; + static const QByteArray CryptAlgoAes256Ctr; static const QList EncryptionAlgorithms; static const QByteArray HMacSha1; diff --git a/src/libs/ssh/sshcryptofacility.cpp b/src/libs/ssh/sshcryptofacility.cpp index 1ae94b3cdc1..08abce26907 100644 --- a/src/libs/ssh/sshcryptofacility.cpp +++ b/src/libs/ssh/sshcryptofacility.cpp @@ -65,6 +65,16 @@ void SshAbstractCryptoFacility::clearKeys() m_hMac.reset(0); } +SshAbstractCryptoFacility::Mode SshAbstractCryptoFacility::getMode(const QByteArray &algoName) +{ + if (algoName.endsWith("-ctr")) + return CtrMode; + if (algoName.endsWith("-cbc")) + return CbcMode; + throw SshClientException(SshInternalError, SSH_TR("Unexpected cipher \"%1\"") + .arg(QString::fromLatin1(algoName))); +} + void SshAbstractCryptoFacility::recreateKeys(const SshKeyExchange &kex) { checkInvariant(); @@ -72,8 +82,9 @@ void SshAbstractCryptoFacility::recreateKeys(const SshKeyExchange &kex) if (m_sessionId.isEmpty()) m_sessionId = kex.h(); Algorithm_Factory &af = global_state().algorithm_factory(); - const std::string &cryptAlgo = botanCryptAlgoName(cryptAlgoName(kex)); - BlockCipher * const cipher = af.prototype_block_cipher(cryptAlgo)->clone(); + const QByteArray &rfcCryptAlgoName = cryptAlgoName(kex); + BlockCipher * const cipher + = af.prototype_block_cipher(botanCryptAlgoName(rfcCryptAlgoName))->clone(); m_cipherBlockSize = cipher->block_size(); const QByteArray ivData = generateHash(kex, ivChar(), m_cipherBlockSize); @@ -82,8 +93,8 @@ void SshAbstractCryptoFacility::recreateKeys(const SshKeyExchange &kex) const quint32 keySize = cipher->key_spec().maximum_keylength(); const QByteArray cryptKeyData = generateHash(kex, keyChar(), keySize); SymmetricKey cryptKey(convertByteArray(cryptKeyData), keySize); - - Keyed_Filter * const cipherMode = makeCipherMode(cipher, new Null_Padding, iv, cryptKey); + Keyed_Filter * const cipherMode + = makeCipherMode(cipher, getMode(rfcCryptAlgoName), iv, cryptKey); m_pipe.reset(new Pipe(cipherMode)); m_macLength = botanHMacKeyLen(hMacAlgoName(kex)); @@ -119,6 +130,15 @@ void SshAbstractCryptoFacility::convert(QByteArray &data, quint32 offset, } } +Keyed_Filter *SshAbstractCryptoFacility::makeCtrCipherMode(BlockCipher *cipher, + const InitializationVector &iv, const SymmetricKey &key) +{ + StreamCipher_Filter * const filter = new StreamCipher_Filter(new CTR_BE(cipher)); + filter->set_key(key); + filter->set_iv(iv); + return filter; +} + QByteArray SshAbstractCryptoFacility::generateMac(const QByteArray &data, quint32 dataSize) const { @@ -168,11 +188,16 @@ QByteArray SshEncryptionFacility::hMacAlgoName(const SshKeyExchange &kex) const return kex.hMacAlgoClientToServer(); } -Keyed_Filter *SshEncryptionFacility::makeCipherMode(BlockCipher *cipher, - BlockCipherModePaddingMethod *paddingMethod, const InitializationVector &iv, - const SymmetricKey &key) +Keyed_Filter *SshEncryptionFacility::makeCipherMode(BlockCipher *cipher, Mode mode, + const InitializationVector &iv, const SymmetricKey &key) { - return new CBC_Encryption(cipher, paddingMethod, key, iv); + switch (mode) { + case CbcMode: + return new CBC_Encryption(cipher, new Null_Padding, key, iv); + case CtrMode: + return makeCtrCipherMode(cipher, iv, key); + } + return 0; // For dumb compilers. } void SshEncryptionFacility::encrypt(QByteArray &data) const @@ -360,11 +385,16 @@ QByteArray SshDecryptionFacility::hMacAlgoName(const SshKeyExchange &kex) const return kex.hMacAlgoServerToClient(); } -Keyed_Filter *SshDecryptionFacility::makeCipherMode(BlockCipher *cipher, - BlockCipherModePaddingMethod *paddingMethod, const InitializationVector &iv, +Keyed_Filter *SshDecryptionFacility::makeCipherMode(BlockCipher *cipher, Mode mode, const InitializationVector &iv, const SymmetricKey &key) { - return new CBC_Decryption(cipher, paddingMethod, key, iv); + switch (mode) { + case CbcMode: + return new CBC_Decryption(cipher, new Null_Padding, key, iv); + case CtrMode: + return makeCtrCipherMode(cipher, iv, key); + } + return 0; // For dumb compilers. } void SshDecryptionFacility::decrypt(QByteArray &data, quint32 offset, diff --git a/src/libs/ssh/sshcryptofacility_p.h b/src/libs/ssh/sshcryptofacility_p.h index e8335e80d6a..60294286990 100644 --- a/src/libs/ssh/sshcryptofacility_p.h +++ b/src/libs/ssh/sshcryptofacility_p.h @@ -53,9 +53,13 @@ public: quint32 macLength() const { return m_macLength; } protected: + enum Mode { CbcMode, CtrMode }; + SshAbstractCryptoFacility(); void convert(QByteArray &data, quint32 offset, quint32 dataSize) const; QByteArray sessionId() const { return m_sessionId; } + Botan::Keyed_Filter *makeCtrCipherMode(Botan::BlockCipher *cipher, + const Botan::InitializationVector &iv, const Botan::SymmetricKey &key); private: SshAbstractCryptoFacility(const SshAbstractCryptoFacility &); @@ -64,15 +68,14 @@ private: virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const = 0; virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const = 0; virtual Botan::Keyed_Filter *makeCipherMode(Botan::BlockCipher *cipher, - Botan::BlockCipherModePaddingMethod *paddingMethod, - const Botan::InitializationVector &iv, - const Botan::SymmetricKey &key) = 0; + Mode mode, const Botan::InitializationVector &iv, const Botan::SymmetricKey &key) = 0; virtual char ivChar() const = 0; virtual char keyChar() const = 0; virtual char macChar() const = 0; QByteArray generateHash(const SshKeyExchange &kex, char c, quint32 length); void checkInvariant() const; + static Mode getMode(const QByteArray &algoName); QByteArray m_sessionId; QScopedPointer m_pipe; @@ -98,8 +101,7 @@ private: virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const; virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const; virtual Botan::Keyed_Filter *makeCipherMode(Botan::BlockCipher *cipher, - Botan::BlockCipherModePaddingMethod *paddingMethod, - const Botan::InitializationVector &iv, const Botan::SymmetricKey &key); + Mode mode, const Botan::InitializationVector &iv, const Botan::SymmetricKey &key); virtual char ivChar() const { return 'A'; } virtual char keyChar() const { return 'C'; } virtual char macChar() const { return 'E'; } @@ -130,8 +132,7 @@ private: virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const; virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const; virtual Botan::Keyed_Filter *makeCipherMode(Botan::BlockCipher *cipher, - Botan::BlockCipherModePaddingMethod *paddingMethod, - const Botan::InitializationVector &iv, const Botan::SymmetricKey &key); + Mode mode, const Botan::InitializationVector &iv, const Botan::SymmetricKey &key); virtual char ivChar() const { return 'B'; } virtual char keyChar() const { return 'D'; } virtual char macChar() const { return 'F'; }