1
/***************************************************************************
2
* fqterm, a terminal emulator for both BBS and *nix. *
3
* Copyright (C) 2008 fqterm development group. *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License as published by *
7
* the Free Software Foundation; either version 2 of the License, or *
8
* (at your option) any later version. *
10
* This program is distributed in the hope that it will be useful, *
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13
* GNU General Public License for more details. *
15
* You should have received a copy of the GNU General Public License *
16
* along with this program; if not, write to the *
17
* Free Software Foundation, Inc., *
18
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. *
19
***************************************************************************/
21
#include "fqterm_ssh_kex.h"
22
#include "fqterm_ssh_md5.h"
23
#include "fqterm_trace.h"
27
FQTermSSHKex::FQTermSSHKex(const char *V_C, const char *V_S) {
28
V_C_ = new char[strlen(V_C) + 1];
29
V_S_ = new char[strlen(V_S) + 1];
35
FQTermSSHKex::~FQTermSSHKex() {
41
//==============================================================================
43
//==============================================================================
45
FQTermSSH1Kex::FQTermSSH1Kex(const char *V_C, const char *V_S)
46
: FQTermSSHKex(V_C, V_S) {
48
kex_state_ = FQTermSSH1Kex::BEFORE_PUBLICKEY;
51
FQTermSSH1Kex::~FQTermSSH1Kex(){}
53
void FQTermSSH1Kex::initKex(FQTermSSHPacketReceiver *packetReceiver,
54
FQTermSSHPacketSender *packetSender) {
55
packet_receiver_ = packetReceiver;
56
packet_sender_ = packetSender;
57
packet_receiver_->disconnect(this);
58
FQ_VERIFY(connect(packet_receiver_, SIGNAL(packetAvaliable(int)),
59
this, SLOT(handlePacket(int))));
60
kex_state_ = FQTermSSH1Kex::BEFORE_PUBLICKEY;
64
void FQTermSSH1Kex::handlePacket(int type) {
66
case FQTermSSH1Kex::BEFORE_PUBLICKEY:
68
kex_state_ = FQTermSSH1Kex::SESSIONKEY_SENT;
70
case FQTermSSH1Kex::SESSIONKEY_SENT:
71
if (type != SSH1_SMSG_SUCCESS) {
72
emit kexError("Kex exchange failed!");
76
kex_state_ = FQTermSSH1Kex::KEYEX_OK;
78
case FQTermSSH1Kex::KEYEX_OK:
83
void FQTermSSH1Kex::makeSessionKey() {
90
if (packet_receiver_->packetType() != SSH1_SMSG_PUBLIC_KEY) {
91
emit kexError("startKex: First packet is not public key");
94
packet_receiver_->getRawData((char*)cookie_, 8);
96
// Get the public key.
97
server_key_ = new FQTermSSHRSA;
98
bits = packet_receiver_->getInt();
99
packet_receiver_->getBN(server_key_->d_rsa->e);
100
packet_receiver_->getBN(server_key_->d_rsa->n);
102
rbits = BN_num_bits(server_key_->d_rsa->n);
104
FQ_TRACE("sshkex", 0) << "Warning: Server lies about "
105
<< "size of server public key: "
106
<< "actual size: " << rbits
107
<< " vs. anounced: " << bits;
108
FQ_TRACE("sshkex", 0) << "Warning: This may be due to "
109
<< "an old implementation of ssh.";
113
host_key_ = new FQTermSSHRSA;
114
bits = packet_receiver_->getInt();
115
packet_receiver_->getBN(host_key_->d_rsa->e);
116
packet_receiver_->getBN(host_key_->d_rsa->n);
118
rbits = BN_num_bits(host_key_->d_rsa->n);
120
FQ_TRACE("sshkex", 0) << "Warning: Server lies about "
121
<< "size of server public key: "
122
<< "actual size: " << rbits
123
<< " vs. anounced: " << bits;
124
FQ_TRACE("sshkex", 0) << "Warning: This may be due to "
125
<< "an old implementation of ssh.";
128
// Get protocol flags.
129
server_flag_ = packet_receiver_->getInt();
130
ciphers_ = packet_receiver_->getInt();
131
auth_ = packet_receiver_->getInt();
133
if ((ciphers_ &(1 << SSH_CIPHER_3DES)) == 0) {
134
FQ_VERIFY(false); // server do not support my cipher
139
// Generate an encryption key for the session. The key is a 256 bit
140
// random number, interpreted as a 32-byte key, with the least
141
// significant 8 bits being the first byte of the key.
143
for (i = 0; i < 32; i++) {
148
session_key_[i] = (rand_val &0xff);
155
for (i = 0; i < 32; i++) {
156
BN_lshift(key, key, 8);
158
BN_add_word(key, session_key_[i] ^ session_id_[i]);
160
BN_add_word(key, session_key_[i]);
164
if (BN_cmp(server_key_->d_rsa->n, host_key_->d_rsa->n) < 0) {
165
server_key_->publicEncrypt(key, key);
166
host_key_->publicEncrypt(key, key);
168
host_key_->publicEncrypt(key, key);
169
server_key_->publicEncrypt(key, key);
175
packet_sender_->startPacket(SSH1_CMSG_SESSION_KEY);
176
packet_sender_->putByte(SSH_CIPHER_3DES);
177
packet_sender_->putRawData((const char*)cookie_, 8);
178
packet_sender_->putBN(key);
182
packet_sender_->putInt(1);
183
packet_sender_->write();
185
emit startEncryption(session_key_);
188
void FQTermSSH1Kex::makeSessionId() {
191
int servlen, hostlen;
193
md5 = new FQTermSSHMD5;
194
servlen = BN_num_bytes(server_key_->d_rsa->n);
195
hostlen = BN_num_bytes(host_key_->d_rsa->n);
197
p = new u_char[servlen + hostlen];
199
BN_bn2bin(host_key_->d_rsa->n, p);
200
BN_bn2bin(server_key_->d_rsa->n, p + hostlen);
201
md5->update(p, servlen + hostlen);
202
md5->update(cookie_, 8);
203
md5->final(session_id_);
208
} // namespace FQTerm
210
#include "fqterm_ssh_kex.moc"