forked from qt-creator/qt-creator
SSH: Add support for the recommended cipher modes from RFC 4344.
New OpenSSH versions do not support the (required) CBC modes out of the box anymore, so let's add some CTR ones. Task-number: QTCREATORBUG-13340 Change-Id: Ia3e38be3aab95be258e64396283736d246c8b93b Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com> Reviewed-by: Christian Kandeler <christian.kandeler@digia.com>
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
#define SSHBOTANCONVERSIONS_P_H
|
#define SSHBOTANCONVERSIONS_P_H
|
||||||
|
|
||||||
#include "sshcapabilities_p.h"
|
#include "sshcapabilities_p.h"
|
||||||
|
#include "sshexception_p.h"
|
||||||
|
|
||||||
#include <botan/botan.h>
|
#include <botan/botan.h>
|
||||||
|
|
||||||
@@ -63,10 +64,22 @@ inline const char *botanKeyExchangeAlgoName(const QByteArray &rfcAlgoName)
|
|||||||
|
|
||||||
inline const char *botanCryptAlgoName(const QByteArray &rfcAlgoName)
|
inline const char *botanCryptAlgoName(const QByteArray &rfcAlgoName)
|
||||||
{
|
{
|
||||||
Q_ASSERT(rfcAlgoName == SshCapabilities::CryptAlgo3Des
|
if (rfcAlgoName == SshCapabilities::CryptAlgoAes128Cbc
|
||||||
|| rfcAlgoName == SshCapabilities::CryptAlgoAes128);
|
|| rfcAlgoName == SshCapabilities::CryptAlgoAes128Ctr) {
|
||||||
return rfcAlgoName == SshCapabilities::CryptAlgo3Des
|
return "AES-128";
|
||||||
? "TripleDES" : "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)
|
inline const char *botanEmsaAlgoName(const QByteArray &rfcAlgoName)
|
||||||
|
|||||||
@@ -62,11 +62,19 @@ const QList<QByteArray> SshCapabilities::PublicKeyAlgorithms
|
|||||||
= QList<QByteArray>() << SshCapabilities::PubKeyRsa
|
= QList<QByteArray>() << SshCapabilities::PubKeyRsa
|
||||||
<< SshCapabilities::PubKeyDss;
|
<< SshCapabilities::PubKeyDss;
|
||||||
|
|
||||||
const QByteArray SshCapabilities::CryptAlgo3Des("3des-cbc");
|
const QByteArray SshCapabilities::CryptAlgo3DesCbc("3des-cbc");
|
||||||
const QByteArray SshCapabilities::CryptAlgoAes128("aes128-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<QByteArray> SshCapabilities::EncryptionAlgorithms
|
const QList<QByteArray> SshCapabilities::EncryptionAlgorithms
|
||||||
= QList<QByteArray>() << SshCapabilities::CryptAlgoAes128
|
= QList<QByteArray>() << SshCapabilities::CryptAlgoAes256Ctr
|
||||||
<< SshCapabilities::CryptAlgo3Des;
|
<< SshCapabilities::CryptAlgoAes192Ctr
|
||||||
|
<< SshCapabilities::CryptAlgoAes128Ctr
|
||||||
|
<< SshCapabilities::CryptAlgo3DesCtr
|
||||||
|
<< SshCapabilities::CryptAlgoAes128Cbc
|
||||||
|
<< SshCapabilities::CryptAlgo3DesCbc;
|
||||||
|
|
||||||
const QByteArray SshCapabilities::HMacSha1("hmac-sha1");
|
const QByteArray SshCapabilities::HMacSha1("hmac-sha1");
|
||||||
const QByteArray SshCapabilities::HMacSha196("hmac-sha1-96");
|
const QByteArray SshCapabilities::HMacSha196("hmac-sha1-96");
|
||||||
|
|||||||
@@ -48,8 +48,12 @@ public:
|
|||||||
static const QByteArray PubKeyRsa;
|
static const QByteArray PubKeyRsa;
|
||||||
static const QList<QByteArray> PublicKeyAlgorithms;
|
static const QList<QByteArray> PublicKeyAlgorithms;
|
||||||
|
|
||||||
static const QByteArray CryptAlgo3Des;
|
static const QByteArray CryptAlgo3DesCbc;
|
||||||
static const QByteArray CryptAlgoAes128;
|
static const QByteArray CryptAlgo3DesCtr;
|
||||||
|
static const QByteArray CryptAlgoAes128Cbc;
|
||||||
|
static const QByteArray CryptAlgoAes128Ctr;
|
||||||
|
static const QByteArray CryptAlgoAes192Ctr;
|
||||||
|
static const QByteArray CryptAlgoAes256Ctr;
|
||||||
static const QList<QByteArray> EncryptionAlgorithms;
|
static const QList<QByteArray> EncryptionAlgorithms;
|
||||||
|
|
||||||
static const QByteArray HMacSha1;
|
static const QByteArray HMacSha1;
|
||||||
|
|||||||
@@ -65,6 +65,16 @@ void SshAbstractCryptoFacility::clearKeys()
|
|||||||
m_hMac.reset(0);
|
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)
|
void SshAbstractCryptoFacility::recreateKeys(const SshKeyExchange &kex)
|
||||||
{
|
{
|
||||||
checkInvariant();
|
checkInvariant();
|
||||||
@@ -72,8 +82,9 @@ void SshAbstractCryptoFacility::recreateKeys(const SshKeyExchange &kex)
|
|||||||
if (m_sessionId.isEmpty())
|
if (m_sessionId.isEmpty())
|
||||||
m_sessionId = kex.h();
|
m_sessionId = kex.h();
|
||||||
Algorithm_Factory &af = global_state().algorithm_factory();
|
Algorithm_Factory &af = global_state().algorithm_factory();
|
||||||
const std::string &cryptAlgo = botanCryptAlgoName(cryptAlgoName(kex));
|
const QByteArray &rfcCryptAlgoName = cryptAlgoName(kex);
|
||||||
BlockCipher * const cipher = af.prototype_block_cipher(cryptAlgo)->clone();
|
BlockCipher * const cipher
|
||||||
|
= af.prototype_block_cipher(botanCryptAlgoName(rfcCryptAlgoName))->clone();
|
||||||
|
|
||||||
m_cipherBlockSize = cipher->block_size();
|
m_cipherBlockSize = cipher->block_size();
|
||||||
const QByteArray ivData = generateHash(kex, ivChar(), m_cipherBlockSize);
|
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 quint32 keySize = cipher->key_spec().maximum_keylength();
|
||||||
const QByteArray cryptKeyData = generateHash(kex, keyChar(), keySize);
|
const QByteArray cryptKeyData = generateHash(kex, keyChar(), keySize);
|
||||||
SymmetricKey cryptKey(convertByteArray(cryptKeyData), keySize);
|
SymmetricKey cryptKey(convertByteArray(cryptKeyData), keySize);
|
||||||
|
Keyed_Filter * const cipherMode
|
||||||
Keyed_Filter * const cipherMode = makeCipherMode(cipher, new Null_Padding, iv, cryptKey);
|
= makeCipherMode(cipher, getMode(rfcCryptAlgoName), iv, cryptKey);
|
||||||
m_pipe.reset(new Pipe(cipherMode));
|
m_pipe.reset(new Pipe(cipherMode));
|
||||||
|
|
||||||
m_macLength = botanHMacKeyLen(hMacAlgoName(kex));
|
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,
|
QByteArray SshAbstractCryptoFacility::generateMac(const QByteArray &data,
|
||||||
quint32 dataSize) const
|
quint32 dataSize) const
|
||||||
{
|
{
|
||||||
@@ -168,11 +188,16 @@ QByteArray SshEncryptionFacility::hMacAlgoName(const SshKeyExchange &kex) const
|
|||||||
return kex.hMacAlgoClientToServer();
|
return kex.hMacAlgoClientToServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
Keyed_Filter *SshEncryptionFacility::makeCipherMode(BlockCipher *cipher,
|
Keyed_Filter *SshEncryptionFacility::makeCipherMode(BlockCipher *cipher, Mode mode,
|
||||||
BlockCipherModePaddingMethod *paddingMethod, const InitializationVector &iv,
|
const InitializationVector &iv, const SymmetricKey &key)
|
||||||
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
|
void SshEncryptionFacility::encrypt(QByteArray &data) const
|
||||||
@@ -360,11 +385,16 @@ QByteArray SshDecryptionFacility::hMacAlgoName(const SshKeyExchange &kex) const
|
|||||||
return kex.hMacAlgoServerToClient();
|
return kex.hMacAlgoServerToClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
Keyed_Filter *SshDecryptionFacility::makeCipherMode(BlockCipher *cipher,
|
Keyed_Filter *SshDecryptionFacility::makeCipherMode(BlockCipher *cipher, Mode mode, const InitializationVector &iv,
|
||||||
BlockCipherModePaddingMethod *paddingMethod, const InitializationVector &iv,
|
|
||||||
const SymmetricKey &key)
|
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,
|
void SshDecryptionFacility::decrypt(QByteArray &data, quint32 offset,
|
||||||
|
|||||||
@@ -53,9 +53,13 @@ public:
|
|||||||
quint32 macLength() const { return m_macLength; }
|
quint32 macLength() const { return m_macLength; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
enum Mode { CbcMode, CtrMode };
|
||||||
|
|
||||||
SshAbstractCryptoFacility();
|
SshAbstractCryptoFacility();
|
||||||
void convert(QByteArray &data, quint32 offset, quint32 dataSize) const;
|
void convert(QByteArray &data, quint32 offset, quint32 dataSize) const;
|
||||||
QByteArray sessionId() const { return m_sessionId; }
|
QByteArray sessionId() const { return m_sessionId; }
|
||||||
|
Botan::Keyed_Filter *makeCtrCipherMode(Botan::BlockCipher *cipher,
|
||||||
|
const Botan::InitializationVector &iv, const Botan::SymmetricKey &key);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SshAbstractCryptoFacility(const SshAbstractCryptoFacility &);
|
SshAbstractCryptoFacility(const SshAbstractCryptoFacility &);
|
||||||
@@ -64,15 +68,14 @@ private:
|
|||||||
virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const = 0;
|
virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const = 0;
|
||||||
virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const = 0;
|
virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const = 0;
|
||||||
virtual Botan::Keyed_Filter *makeCipherMode(Botan::BlockCipher *cipher,
|
virtual Botan::Keyed_Filter *makeCipherMode(Botan::BlockCipher *cipher,
|
||||||
Botan::BlockCipherModePaddingMethod *paddingMethod,
|
Mode mode, const Botan::InitializationVector &iv, const Botan::SymmetricKey &key) = 0;
|
||||||
const Botan::InitializationVector &iv,
|
|
||||||
const Botan::SymmetricKey &key) = 0;
|
|
||||||
virtual char ivChar() const = 0;
|
virtual char ivChar() const = 0;
|
||||||
virtual char keyChar() const = 0;
|
virtual char keyChar() const = 0;
|
||||||
virtual char macChar() const = 0;
|
virtual char macChar() const = 0;
|
||||||
|
|
||||||
QByteArray generateHash(const SshKeyExchange &kex, char c, quint32 length);
|
QByteArray generateHash(const SshKeyExchange &kex, char c, quint32 length);
|
||||||
void checkInvariant() const;
|
void checkInvariant() const;
|
||||||
|
static Mode getMode(const QByteArray &algoName);
|
||||||
|
|
||||||
QByteArray m_sessionId;
|
QByteArray m_sessionId;
|
||||||
QScopedPointer<Botan::Pipe> m_pipe;
|
QScopedPointer<Botan::Pipe> m_pipe;
|
||||||
@@ -98,8 +101,7 @@ private:
|
|||||||
virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const;
|
virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const;
|
||||||
virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const;
|
virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const;
|
||||||
virtual Botan::Keyed_Filter *makeCipherMode(Botan::BlockCipher *cipher,
|
virtual Botan::Keyed_Filter *makeCipherMode(Botan::BlockCipher *cipher,
|
||||||
Botan::BlockCipherModePaddingMethod *paddingMethod,
|
Mode mode, const Botan::InitializationVector &iv, const Botan::SymmetricKey &key);
|
||||||
const Botan::InitializationVector &iv, const Botan::SymmetricKey &key);
|
|
||||||
virtual char ivChar() const { return 'A'; }
|
virtual char ivChar() const { return 'A'; }
|
||||||
virtual char keyChar() const { return 'C'; }
|
virtual char keyChar() const { return 'C'; }
|
||||||
virtual char macChar() const { return 'E'; }
|
virtual char macChar() const { return 'E'; }
|
||||||
@@ -130,8 +132,7 @@ private:
|
|||||||
virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const;
|
virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const;
|
||||||
virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const;
|
virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const;
|
||||||
virtual Botan::Keyed_Filter *makeCipherMode(Botan::BlockCipher *cipher,
|
virtual Botan::Keyed_Filter *makeCipherMode(Botan::BlockCipher *cipher,
|
||||||
Botan::BlockCipherModePaddingMethod *paddingMethod,
|
Mode mode, const Botan::InitializationVector &iv, const Botan::SymmetricKey &key);
|
||||||
const Botan::InitializationVector &iv, const Botan::SymmetricKey &key);
|
|
||||||
virtual char ivChar() const { return 'B'; }
|
virtual char ivChar() const { return 'B'; }
|
||||||
virtual char keyChar() const { return 'D'; }
|
virtual char keyChar() const { return 'D'; }
|
||||||
virtual char macChar() const { return 'F'; }
|
virtual char macChar() const { return 'F'; }
|
||||||
|
|||||||
Reference in New Issue
Block a user