summaryrefslogtreecommitdiff
path: root/src/protocol/internal/fqterm_ssh_kex.cpp
diff options
context:
space:
mode:
authoriroul <iroul@iroul-VirtualBox.(none)>2014-04-04 07:35:14 -0700
committeriroul <iroul@iroul-VirtualBox.(none)>2014-04-04 07:35:14 -0700
commitafd34f2893a06a3aecf17e8e83b1df6ed2ae91a2 (patch)
tree851102abc55d91a1b76e63e9e89f9a7733da95b5 /src/protocol/internal/fqterm_ssh_kex.cpp
parentc4b028ad53f7b362a864de24828d7cc39ff67b0a (diff)
downloadfqterm-afd34f2893a06a3aecf17e8e83b1df6ed2ae91a2.tar.xz
move to my github.
Diffstat (limited to 'src/protocol/internal/fqterm_ssh_kex.cpp')
-rw-r--r--src/protocol/internal/fqterm_ssh_kex.cpp210
1 files changed, 210 insertions, 0 deletions
diff --git a/src/protocol/internal/fqterm_ssh_kex.cpp b/src/protocol/internal/fqterm_ssh_kex.cpp
new file mode 100644
index 0000000..d27bf14
--- /dev/null
+++ b/src/protocol/internal/fqterm_ssh_kex.cpp
@@ -0,0 +1,210 @@
+/***************************************************************************
+ * 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 "fqterm_ssh_kex.h"
+#include "fqterm_ssh_md5.h"
+#include "fqterm_trace.h"
+
+namespace FQTerm {
+
+FQTermSSHKex::FQTermSSHKex(const char *V_C, const char *V_S) {
+ V_C_ = new char[strlen(V_C) + 1];
+ V_S_ = new char[strlen(V_S) + 1];
+
+ strcpy(V_C_, V_C);
+ strcpy(V_S_, V_S);
+}
+
+FQTermSSHKex::~FQTermSSHKex() {
+ delete[] V_C_;
+ delete[] V_S_;
+}
+
+
+//==============================================================================
+//FQTermSSH1Kex
+//==============================================================================
+
+FQTermSSH1Kex::FQTermSSH1Kex(const char *V_C, const char *V_S)
+ : FQTermSSHKex(V_C, V_S) {
+ is_first_kex_ = true;
+ kex_state_ = FQTermSSH1Kex::BEFORE_PUBLICKEY;
+}
+
+FQTermSSH1Kex::~FQTermSSH1Kex(){}
+
+void FQTermSSH1Kex::initKex(FQTermSSHPacketReceiver *packetReceiver,
+ FQTermSSHPacketSender *packetSender) {
+ packet_receiver_ = packetReceiver;
+ packet_sender_ = packetSender;
+ packet_receiver_->disconnect(this);
+ FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)),
+ this, SLOT(handlePacket(int))));
+ kex_state_ = FQTermSSH1Kex::BEFORE_PUBLICKEY;
+ emit reKex();
+}
+
+void FQTermSSH1Kex::handlePacket(int type) {
+ switch (kex_state_) {
+ case FQTermSSH1Kex::BEFORE_PUBLICKEY:
+ makeSessionKey();
+ kex_state_ = FQTermSSH1Kex::SESSIONKEY_SENT;
+ break;
+ case FQTermSSH1Kex::SESSIONKEY_SENT:
+ if (type != SSH1_SMSG_SUCCESS) {
+ emit kexError(tr("Kex exchange failed!"));
+ break;
+ }
+ emit kexOK();
+ kex_state_ = FQTermSSH1Kex::KEYEX_OK;
+ break;
+ case FQTermSSH1Kex::KEYEX_OK:
+ break;
+ }
+}
+
+void FQTermSSH1Kex::makeSessionKey() {
+ int i;
+ BIGNUM *key;
+ u_int32_t rand_val;
+ int bits;
+ int rbits;
+
+ if (packet_receiver_->packetType() != SSH1_SMSG_PUBLIC_KEY) {
+ emit kexError(tr("startKex: First packet is not public key"));
+ return ;
+ }
+ packet_receiver_->getRawData((char*)cookie_, 8);
+
+ // Get the public key.
+ server_key_ = new FQTermSSHRSA;
+ bits = packet_receiver_->getInt();
+ packet_receiver_->getBN(server_key_->d_rsa->e);
+ packet_receiver_->getBN(server_key_->d_rsa->n);
+
+ rbits = BN_num_bits(server_key_->d_rsa->n);
+ if (bits != rbits) {
+ FQ_TRACE("sshkex", 0) << "Warning: Server lies about "
+ << "size of server public key: "
+ << "actual size: " << rbits
+ << " vs. anounced: " << bits;
+ FQ_TRACE("sshkex", 0) << "Warning: This may be due to "
+ << "an old implementation of ssh.";
+ }
+
+ // Get the host key.
+ host_key_ = new FQTermSSHRSA;
+ bits = packet_receiver_->getInt();
+ packet_receiver_->getBN(host_key_->d_rsa->e);
+ packet_receiver_->getBN(host_key_->d_rsa->n);
+
+ rbits = BN_num_bits(host_key_->d_rsa->n);
+ if (bits != rbits) {
+ FQ_TRACE("sshkex", 0) << "Warning: Server lies about "
+ << "size of server public key: "
+ << "actual size: " << rbits
+ << " vs. anounced: " << bits;
+ FQ_TRACE("sshkex", 0) << "Warning: This may be due to "
+ << "an old implementation of ssh.";
+ }
+
+ // Get protocol flags.
+ server_flag_ = packet_receiver_->getInt();
+ ciphers_ = packet_receiver_->getInt();
+ auth_ = packet_receiver_->getInt();
+
+ if ((ciphers_ &(1 << SSH_CIPHER_3DES)) == 0) {
+ FQ_VERIFY(false); // server do not support my cipher
+ }
+
+ makeSessionId();
+
+ // Generate an encryption key for the session. The key is a 256 bit
+ // random number, interpreted as a 32-byte key, with the least
+ // significant 8 bits being the first byte of the key.
+
+ for (i = 0; i < 32; i++) {
+ if (i % 4 == 0) {
+ rand_val = rand();
+ }
+
+ session_key_[i] = (rand_val &0xff);
+ rand_val >>= 8;
+ }
+
+ key = BN_new();
+
+ BN_set_word(key, 0);
+ for (i = 0; i < 32; i++) {
+ BN_lshift(key, key, 8);
+ if (i < 16) {
+ BN_add_word(key, session_key_[i] ^ session_id_[i]);
+ } else {
+ BN_add_word(key, session_key_[i]);
+ }
+ }
+
+ if (BN_cmp(server_key_->d_rsa->n, host_key_->d_rsa->n) < 0) {
+ server_key_->publicEncrypt(key, key);
+ host_key_->publicEncrypt(key, key);
+ } else {
+ host_key_->publicEncrypt(key, key);
+ server_key_->publicEncrypt(key, key);
+ }
+
+ delete host_key_;
+ delete server_key_;
+
+ packet_sender_->startPacket(SSH1_CMSG_SESSION_KEY);
+ packet_sender_->putByte(SSH_CIPHER_3DES);
+ packet_sender_->putRawData((const char*)cookie_, 8);
+ packet_sender_->putBN(key);
+
+ BN_free(key);
+
+ packet_sender_->putInt(1);
+ packet_sender_->write();
+
+ emit startEncryption(session_key_);
+}
+
+void FQTermSSH1Kex::makeSessionId() {
+ u_char *p;
+ FQTermSSHMD5 *md5;
+ int servlen, hostlen;
+
+ md5 = new FQTermSSHMD5;
+ servlen = BN_num_bytes(server_key_->d_rsa->n);
+ hostlen = BN_num_bytes(host_key_->d_rsa->n);
+
+ p = new u_char[servlen + hostlen];
+
+ BN_bn2bin(host_key_->d_rsa->n, p);
+ BN_bn2bin(server_key_->d_rsa->n, p + hostlen);
+ md5->update(p, servlen + hostlen);
+ md5->update(cookie_, 8);
+ md5->final(session_id_);
+ delete md5;
+ delete [] p;
+}
+
+} // namespace FQTerm
+
+#include "fqterm_ssh_kex.moc"