summaryrefslogtreecommitdiff
path: root/src/protocol/internal
diff options
context:
space:
mode:
Diffstat (limited to 'src/protocol/internal')
-rw-r--r--src/protocol/internal/fqterm_ssh2_kex.cpp33
-rw-r--r--src/protocol/internal/fqterm_ssh2_packet.cpp24
-rw-r--r--src/protocol/internal/fqterm_ssh_mac.cpp53
-rw-r--r--src/protocol/internal/fqterm_ssh_mac.h54
-rw-r--r--src/protocol/internal/fqterm_ssh_packet.cpp39
-rw-r--r--src/protocol/internal/fqterm_ssh_packet.h14
-rw-r--r--src/protocol/internal/ssh_mac.c82
-rw-r--r--src/protocol/internal/ssh_mac.h55
8 files changed, 188 insertions, 166 deletions
diff --git a/src/protocol/internal/fqterm_ssh2_kex.cpp b/src/protocol/internal/fqterm_ssh2_kex.cpp
index 906acca..570c29f 100644
--- a/src/protocol/internal/fqterm_ssh2_kex.cpp
+++ b/src/protocol/internal/fqterm_ssh2_kex.cpp
@@ -167,8 +167,32 @@ bool FQTermSSH2Kex::negotiateAlgorithms() {
}
packet_receiver_->cipher = s2c(0);
+ // mac algo c2s
+ size_t m_c2s_len = packet_receiver_->getInt();
+ char m_c2s[m_c2s_len+1];
+ packet_receiver_->getRawData(m_c2s, m_c2s_len);
+ m_c2s[m_c2s_len] = '\0';
+ const struct ssh_mac_t * mac_c2s = search_mac(m_c2s);
+ if (mac_c2s == NULL) {
+ emit kexError(tr("No matching c2s MAC algorithms!"));
+ return false;
+ }
+ packet_sender_->mac = mac_c2s->new_mac(mac_c2s);
+
+ // mac algo s2c
+ size_t m_s2c_len = packet_receiver_->getInt();
+ char m_s2c[m_s2c_len+1];
+ packet_receiver_->getRawData(m_s2c, m_s2c_len);
+ m_s2c[m_s2c_len] = '\0';
+ const struct ssh_mac_t * mac_s2c = search_mac(m_s2c);
+ if (mac_s2c == NULL) {
+ emit kexError(tr("No matching s2c MAC algorithms!"));
+ return false;
+ }
+ packet_receiver_->mac = mac_s2c->new_mac(mac_s2c);
+
std::vector<char> name_lists;
- for (int i = 4; i < 10; ++i) {
+ for (int i = 6; i < 10; ++i) {
int name_lists_len = packet_receiver_->getInt();
if (name_lists_len > 0) {
name_lists.resize(name_lists_len);
@@ -191,8 +215,8 @@ bool FQTermSSH2Kex::negotiateAlgorithms() {
packet_sender_->putString("ssh-rsa");
packet_sender_->putString(all_ciphers_list);
packet_sender_->putString(all_ciphers_list);
- packet_sender_->putString("hmac-sha1");
- packet_sender_->putString("hmac-sha1");
+ packet_sender_->putString(all_macs_list);
+ packet_sender_->putString(all_macs_list);
packet_sender_->putString("none");
packet_sender_->putString("none");
packet_sender_->putString("");
@@ -330,9 +354,6 @@ bool FQTermSSH2Kex::changeKeyAlg() {
memcpy(session_id_, H_, dh->digest.hashlen);
}
- packet_sender_->setMacType(FQTERM_SSH_HMAC_SHA1);
- packet_receiver_->setMacType(FQTERM_SSH_HMAC_SHA1);
-
// From RFC 4253 section 7.2:
// Initial IV client to server: HASH(K || H || "A" || session_id)
// (Here K is encoded as mpint and "A" as byte and session_id as raw
diff --git a/src/protocol/internal/fqterm_ssh2_packet.cpp b/src/protocol/internal/fqterm_ssh2_packet.cpp
index aed8b48..28c7847 100644
--- a/src/protocol/internal/fqterm_ssh2_packet.cpp
+++ b/src/protocol/internal/fqterm_ssh2_packet.cpp
@@ -62,9 +62,8 @@ void FQTermSSH2PacketSender::makePacket() {
// 2. renew the output buffer.
int total_len = non_padding_len + padding_len;
- if (is_mac_) {
- total_len += mac_->digestSize();
- }
+ if (is_mac_)
+ total_len += mac->dgstSize;
delete output_buffer_;
output_buffer_ = new FQTermSSHBuffer(total_len);
@@ -95,8 +94,8 @@ void FQTermSSH2PacketSender::makePacket() {
buffer.putInt(sequence_no_);
buffer.putRawData((const char *)packet, len);
- std::vector<u_char> digest(mac_->digestSize());
- mac_->getDigest(buffer.data(), buffer.len(), &digest[0]);
+ std::vector<u_char> digest(mac->dgstSize);
+ mac->getmac(mac, buffer.data(), buffer.len(), &digest[0]);
FQ_TRACE("ssh2packet", 9) << "Making packets...";
FQ_TRACE("ssh2packet", 9) << "Append MAC with sequence_no_" << sequence_no_;
@@ -121,7 +120,7 @@ void FQTermSSH2PacketSender::makePacket() {
// with the given algorithm.
u_char *data = output_buffer_->data();
- int len = output_buffer_->len() - mac_->digestSize();
+ int len = output_buffer_->len() - mac->dgstSize;
FQ_TRACE("ssh2packet", 9) << "An packet (without MAC) to be encrypted:"
<< len << " bytes:\n"
@@ -174,7 +173,7 @@ void FQTermSSH2PacketReceiver::parseData(FQTermSSHBuffer *input) {
return ;
}
- int expected_input_len = 4 + packet_len + (is_mac_ ? mac_->digestSize() : 0);
+ int expected_input_len = 4 + packet_len + (is_mac_ ? mac->dgstSize : 0);
if (input->len() < (long)expected_input_len) {
FQ_TRACE("ssh2packet", 3)
@@ -189,15 +188,15 @@ void FQTermSSH2PacketReceiver::parseData(FQTermSSHBuffer *input) {
if (is_decrypt_) {
// decrypte blocks left.
unsigned char *tmp = input->data() + cipher->blkSize;
- int left_len = expected_input_len - cipher->blkSize - mac_->digestSize();
+ int left_len = expected_input_len - cipher->blkSize - mac->dgstSize;
FQ_VERIFY(cipher->crypt(cipher, tmp, tmp, left_len)==1);
}
// 3. check MAC
if (is_mac_) {
- int digest_len = mac_->digestSize();
+ int digest_len = mac->dgstSize;
std::vector<u_char> digest(digest_len);
- mac_->getDigest(input->data(), expected_input_len - digest_len, &digest[0]);
+ mac->getmac(mac, input->data(), expected_input_len - digest_len, &digest[0]);
u_char *received_digest = input->data() + expected_input_len - digest_len;
@@ -213,9 +212,8 @@ void FQTermSSH2PacketReceiver::parseData(FQTermSSHBuffer *input) {
std::vector<u_char> data(packet_len);
input->getRawData((char*)&data[0], packet_len);
- if (is_mac_) {
- input->consume(mac_->digestSize());
- }
+ if (is_mac_)
+ input->consume(mac->dgstSize);
int padding_len = data[0];
diff --git a/src/protocol/internal/fqterm_ssh_mac.cpp b/src/protocol/internal/fqterm_ssh_mac.cpp
deleted file mode 100644
index e2d345f..0000000
--- a/src/protocol/internal/fqterm_ssh_mac.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/***************************************************************************
- * fqterm, a terminal emulator for both BBS and *nix. *
- * Copyright (C) 2008 fqterm development group. *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. *
- ***************************************************************************/
-
-#include <openssl/evp.h>
-#include <openssl/hmac.h>
-
-#include "fqterm_trace.h"
-#include "fqterm_ssh_mac.h"
-#include "fqterm_ssh_packet.h"
-
-namespace FQTerm {
-
-void FQTermSSHSHA1::setKey(const unsigned char *key) {
- memcpy(key_, key, keySize());
-}
-
-int FQTermSSHSHA1::keySize() const {
- return SHA_DIGEST_LENGTH;
-}
-
-int FQTermSSHSHA1::digestSize() const {
- return SHA_DIGEST_LENGTH;
-}
-
-void FQTermSSHSHA1::getDigest(const unsigned char *data, int len, unsigned char *digest) const {
- unsigned int tmp;
- HMAC(EVP_sha1(), key_, SHA_DIGEST_LENGTH, data, len, digest, &tmp);
-
- FQ_TRACE("SHA1", 9) << "Key: \n" << dumpHexString << std::string((char *)key_, SHA_DIGEST_LENGTH);
- FQ_TRACE("SHA1", 9) << "data len:" << len;
- FQ_TRACE("SHA1", 9) << "data:\n" << dumpHexString << std::string((char *)data, len);
- FQ_TRACE("SHA1", 9) << "digest len:" << tmp;
- FQ_TRACE("SHA1", 9) << "digest:\n" << dumpHexString << std::string((char *)digest, tmp);
-}
-
-} // namespace FQTerm
diff --git a/src/protocol/internal/fqterm_ssh_mac.h b/src/protocol/internal/fqterm_ssh_mac.h
deleted file mode 100644
index 545909c..0000000
--- a/src/protocol/internal/fqterm_ssh_mac.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/***************************************************************************
- * fqterm, a terminal emulator for both BBS and *nix. *
- * Copyright (C) 2008 fqterm development group. *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. *
- ***************************************************************************/
-
-#ifndef FQTERM_SSH_MAC_H
-#define FQTERM_SSH_MAC_H
-
-#include <openssl/sha.h>
-
-namespace FQTerm {
-
-class FQTermSSHMac {
-public:
- FQTermSSHMac() {}
- virtual ~FQTermSSHMac() {}
- virtual void setKey(const unsigned char *key) = 0;
- virtual int keySize() const = 0;
- virtual int digestSize() const = 0;
- virtual void getDigest(const unsigned char *data, int len, unsigned char *digest) const = 0;
-};
-
-const int FQTERM_SSH_MAC_NONE = 0;
-const int FQTERM_SSH_HMAC_SHA1 = 1;
-
-class FQTermSSHSHA1: public FQTermSSHMac {
- unsigned char key_[SHA_DIGEST_LENGTH];
-
-public:
- virtual void setKey(const unsigned char *key);
- virtual int keySize() const;
- virtual int digestSize() const;
- virtual void getDigest(const unsigned char *data, int len, unsigned char *digest) const;
-};
-
-
-} // namespace FQTerm
-
-#endif // FQTERM_SSH_MAC_H
diff --git a/src/protocol/internal/fqterm_ssh_packet.cpp b/src/protocol/internal/fqterm_ssh_packet.cpp
index 402d1b8..d9a8f89 100644
--- a/src/protocol/internal/fqterm_ssh_packet.cpp
+++ b/src/protocol/internal/fqterm_ssh_packet.cpp
@@ -41,8 +41,7 @@ FQTermSSHPacketSender::FQTermSSHPacketSender() {
cipher = NULL;
is_mac_ = false;
- mac_type_ = FQTERM_SSH_MAC_NONE;
- mac_ = NULL;
+ mac = NULL;
is_compressed_ = false;
@@ -54,6 +53,8 @@ FQTermSSHPacketSender::~FQTermSSHPacketSender() {
delete output_buffer_;
if (cipher)
cipher->cleanup(cipher);
+ if (mac)
+ mac->cleanup(mac);
}
void FQTermSSHPacketSender::putRawData(const char *data, int len) {
@@ -104,22 +105,9 @@ void FQTermSSHPacketSender::resetEncryption() {
is_encrypt_ = false;
}
-void FQTermSSHPacketSender::setMacType(int macType) {
- mac_type_ = macType;
-
- delete mac_;
- mac_ = NULL;
-
- switch (mac_type_) {
- case FQTERM_SSH_HMAC_SHA1:
- mac_ = new FQTermSSHSHA1;
- break;
- }
-}
-
void FQTermSSHPacketSender::startMac(const u_char *key) {
is_mac_ = true;
- mac_->setKey(key);
+ memcpy(mac->key, key, mac->keySize);
}
void FQTermSSHPacketSender::resetMac() {
@@ -138,8 +126,7 @@ FQTermSSHPacketReceiver::FQTermSSHPacketReceiver() {
cipher = NULL;
is_mac_ = false;
- mac_type_ = FQTERM_SSH_MAC_NONE;
- mac_ = NULL;
+ mac = NULL;
is_compressed_ = false;
@@ -151,6 +138,8 @@ FQTermSSHPacketReceiver::~FQTermSSHPacketReceiver()
delete buffer_;
if (cipher)
cipher->cleanup(cipher);
+ if (mac)
+ mac->cleanup(mac);
}
void FQTermSSHPacketReceiver::getRawData(char *data, int length) {
@@ -195,21 +184,9 @@ void FQTermSSHPacketReceiver::resetEncryption() {
is_decrypt_ = false;
}
-void FQTermSSHPacketReceiver::setMacType(int macType) {
- mac_type_ = macType;
- delete mac_;
- mac_ = NULL;
-
- switch (mac_type_) {
- case FQTERM_SSH_HMAC_SHA1:
- mac_ = new FQTermSSHSHA1;
- break;
- }
-}
-
void FQTermSSHPacketReceiver::startMac(const u_char *key) {
is_mac_ = true;
- mac_->setKey(key);
+ memcpy(mac->key, key, mac->keySize);
}
void FQTermSSHPacketReceiver::resetMac() {
diff --git a/src/protocol/internal/fqterm_ssh_packet.h b/src/protocol/internal/fqterm_ssh_packet.h
index 705a11b..7caa663 100644
--- a/src/protocol/internal/fqterm_ssh_packet.h
+++ b/src/protocol/internal/fqterm_ssh_packet.h
@@ -27,7 +27,7 @@
#include "fqterm_ssh_types.h"
#include "fqterm_ssh_buffer.h"
-#include "fqterm_ssh_mac.h"
+#include "ssh_mac.h"
#include "fqterm_serialization.h"
#include "ssh_cipher.h"
@@ -39,6 +39,7 @@ class FQTermSSHPacketSender: public QObject {
FQTermSSHBuffer *output_buffer_;
FQTermSSHBuffer *buffer_;
ssh_cipher_t *cipher;
+ ssh_mac_t *mac;
FQTermSSHPacketSender();
virtual ~FQTermSSHPacketSender();
@@ -54,13 +55,12 @@ class FQTermSSHPacketSender: public QObject {
virtual int getIVSize() const { return cipher->IVSize;}
virtual int getKeySize() const { return cipher->keySize;}
- int getMacKeySize() const { return mac_->keySize();}
+ int getMacKeySize() const { return mac->keySize;}
public slots:
void startEncryption(const u_char *key, const u_char *IV = NULL);
void resetEncryption();
- void setMacType(int macType);
void startMac(const u_char *sessionkey);
void resetMac();
@@ -74,8 +74,6 @@ class FQTermSSHPacketSender: public QObject {
int cipher_type_;
bool is_mac_;
- int mac_type_;
- FQTermSSHMac *mac_;
bool is_compressed_;
@@ -89,6 +87,7 @@ class FQTermSSHPacketReceiver: public QObject {
public:
FQTermSSHBuffer *buffer_;
ssh_cipher_t *cipher;
+ ssh_mac_t *mac;
FQTermSSHPacketReceiver();
virtual ~FQTermSSHPacketReceiver();
@@ -108,14 +107,13 @@ class FQTermSSHPacketReceiver: public QObject {
virtual int packetDataLen() const { return real_data_len_;}
virtual int getIVSize() const { return cipher->IVSize;}
virtual int getKeySize() const { return cipher->keySize;}
- int getMacKeySize() const { return mac_->keySize();}
+ int getMacKeySize() const { return mac->keySize;}
virtual void parseData(FQTermSSHBuffer *input) = 0;
public slots:
void startEncryption(const u_char *key, const u_char *IV = NULL);
void resetEncryption();
- void setMacType(int macType);
void startMac(const u_char *sessionkey);
void resetMac();
@@ -130,8 +128,6 @@ class FQTermSSHPacketReceiver: public QObject {
int cipher_type_;
bool is_mac_;
- int mac_type_;
- FQTermSSHMac *mac_;
bool is_compressed_;
diff --git a/src/protocol/internal/ssh_mac.c b/src/protocol/internal/ssh_mac.c
new file mode 100644
index 0000000..2062cff
--- /dev/null
+++ b/src/protocol/internal/ssh_mac.c
@@ -0,0 +1,82 @@
+/*
+ * ssh_mac.c: the MAC algorithms used in SSH
+ * Copyright (C) 2018 Iru Cai <mytbk920423@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ssh_mac.h"
+#include "ssh_crypto_common.h"
+#include <stdlib.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+static struct ssh_mac_t *new_evp_mac(const struct ssh_mac_t *t)
+{
+ struct ssh_mac_t *m = (struct ssh_mac_t *)malloc(sizeof(struct ssh_mac_t));
+ const EVP_MD *evp_md = ((const EVP_MD *(*)(void))(t->priv))();
+ *m = *t;
+ m->priv = evp_md;
+ return m;
+}
+
+static void free_evp_mac(struct ssh_mac_t *m)
+{
+ free(m);
+}
+
+static void get_evp_digest(SSH_MAC *my, const unsigned char *d, int len, unsigned char *dgst)
+{
+ unsigned int tmp;
+ HMAC((const EVP_MD *)(my->priv), my->key, my->keySize, d, len, dgst, &tmp);
+}
+
+/* RFC 6668 */
+struct ssh_mac_t hmac_sha2_256 = {
+ .name = "hmac-sha2-256",
+ .priv = (void*)EVP_sha256,
+ .new_mac = new_evp_mac,
+ .cleanup = free_evp_mac,
+ .getmac = get_evp_digest,
+ .dgstSize = 32,
+ .keySize = 32
+};
+
+struct ssh_mac_t hmac_sha1 = {
+ .name = "hmac-sha1",
+ .priv = (void*)EVP_sha1,
+ .new_mac = new_evp_mac,
+ .cleanup = free_evp_mac,
+ .getmac = get_evp_digest,
+ .dgstSize = 20,
+ .keySize = 20
+};
+
+static name_list all_macs = {
+ { "hmac-sha2-256", &hmac_sha2_256 },
+ { "hmac-sha1", &hmac_sha1 },
+ { NULL, NULL }
+};
+
+const struct ssh_mac_t * search_mac(const char *s)
+{
+ int i = search_name(all_macs, s);
+ if (i!=-1)
+ return all_macs[i].f;
+ else
+ return NULL;
+}
+
+const char all_macs_list[] = "hmac-sha2-256,hmac-sha1";
diff --git a/src/protocol/internal/ssh_mac.h b/src/protocol/internal/ssh_mac.h
new file mode 100644
index 0000000..507a9cd
--- /dev/null
+++ b/src/protocol/internal/ssh_mac.h
@@ -0,0 +1,55 @@
+/*
+ * ssh_mac.h: the MAC algorithms used in SSH
+ * Copyright (C) 2018 Iru Cai <mytbk920423@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SSH_MAC_H
+#define SSH_MAC_H
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <openssl/evp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ typedef struct ssh_mac_t SSH_MAC;
+ typedef SSH_MAC* (*create_t)(const SSH_MAC*);
+ typedef void (*mac_cleanup_t)(SSH_MAC*);
+ typedef void (*mac_t)(SSH_MAC*, const unsigned char*, int, unsigned char*);
+
+ struct ssh_mac_t
+ {
+ const char *name;
+ void *priv;
+ create_t new_mac;
+ mac_cleanup_t cleanup;
+ mac_t getmac;
+ unsigned char key[32];
+ size_t dgstSize;
+ size_t keySize;
+ };
+
+ const struct ssh_mac_t *search_mac(const char *s);
+ extern const char all_macs_list[];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif