summaryrefslogtreecommitdiff
path: root/src/protocol/internal/ssh_packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/protocol/internal/ssh_packet.c')
-rw-r--r--src/protocol/internal/ssh_packet.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/protocol/internal/ssh_packet.c b/src/protocol/internal/ssh_packet.c
new file mode 100644
index 0000000..6aad6d9
--- /dev/null
+++ b/src/protocol/internal/ssh_packet.c
@@ -0,0 +1,142 @@
+/*
+ * ssh_packet.c: SSH packet maker
+ * 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_packet.h"
+#include "crc32.h"
+#include "ssh_error.h"
+
+//==============================================================================
+//
+// SSH1 Packet Structure:
+// --------------------------------------------------------------------------
+// | length | padding | type | data | crc32 |
+// --------------------------------------------------------------------------
+// | uint32 | 1-7bytes | uchar | | 4bytes|
+// --------------------------------------------------------------------------
+// encrypt = padding + type + data + crc32
+// length = type + data + crc32
+//
+//==============================================================================
+void make_ssh1_packet(buffer *orig_data, buffer *data_to_send,
+ SSH_CIPHER *cipher)
+{
+ int len, padding_len;
+ uint32_t padding[2];
+ uint8_t *data = buffer_data(orig_data);
+ size_t data_len = buffer_len(orig_data);
+
+ len = data_len + 4; //CRC32
+ padding_len = 8 - (len % 8);
+ padding[0] = rand();
+ padding[1] = rand();
+
+ buffer_clear(data_to_send);
+ buffer_append_be32(data_to_send, len);
+ buffer_append(data_to_send, (const uint8_t *)padding, padding_len);
+ buffer_append(data_to_send, data, data_len);
+ buffer_append_be32(data_to_send,
+ ssh_crc32(buffer_data(data_to_send) + 4,
+ buffer_len(data_to_send) - 4));
+
+ if (cipher->started) {
+ cipher->crypt(cipher, buffer_data(data_to_send) + 4,
+ buffer_data(data_to_send) + 4,
+ buffer_len(data_to_send) - 4);
+ }
+}
+
+//==============================================================================
+// SSH2 Packet Structure:
+// uint32 packet_length
+// byte padding_length
+// byte[n1] payload; n1 = packet_length - padding_length - 1
+// byte[n2] random padding; n2 = padding_length
+// byte[m] mac (Message Authentication Code - MAC); m = mac_length
+//==============================================================================
+int make_ssh2_packet(buffer *orig_data, buffer *data_to_send,
+ SSH_CIPHER *cipher, SSH_MAC *mac, bool is_mac_,
+ uint32_t *seq)
+{
+ // 1. compute the padding length for padding.
+ int non_padding_len = 4 + 1 + buffer_len(orig_data);
+
+ int padding_block_len = 8;
+ if (cipher->started && cipher->blkSize > padding_block_len)
+ padding_block_len = cipher->blkSize;
+
+ int padding_len =
+ padding_block_len - (non_padding_len % padding_block_len);
+ if (padding_len < 4)
+ padding_len += padding_block_len;
+
+ // 2. renew the output buffer.
+ int total_len = non_padding_len + padding_len;
+ if (is_mac_)
+ total_len += mac->dgstSize;
+
+ buffer_clear(data_to_send);
+
+ // 3. Fill the output buffer.
+ int packet_len = 1 + buffer_len(orig_data) + padding_len;
+
+ buffer_append_be32(data_to_send, packet_len);
+ buffer_append_byte(data_to_send, padding_len);
+ buffer_append(data_to_send, buffer_data(orig_data),
+ buffer_len(orig_data));
+
+ uint32_t padding[8]; /* padding at most 256 bits */
+ for (int i = 0; i < 8; i++)
+ padding[i] = rand();
+ buffer_append(data_to_send, (const uint8_t *)padding, padding_len);
+
+ // 4. Add MAC on the entire unencrypted packet,
+ // including two length fields, 'payload' and 'random padding'.
+ if (is_mac_) {
+ const unsigned char *packet = buffer_data(data_to_send);
+ int len = buffer_len(data_to_send);
+
+ uint8_t digest[MAX_DGSTLEN];
+
+ buffer mbuffer;
+ buffer_init(&mbuffer);
+ buffer_append_be32(&mbuffer, *seq);
+ buffer_append(&mbuffer, packet, len);
+ mac->getmac(mac, buffer_data(&mbuffer), buffer_len(&mbuffer),
+ digest);
+ buffer_deinit(&mbuffer);
+
+ buffer_append(data_to_send, digest, mac->dgstSize);
+ }
+
+ if (cipher->started) {
+ // as RFC 4253:
+ // When encryption is in effect, the packet length, padding
+ // length, payload, and padding fields of each packet MUST be encrypted
+ // with the given algorithm.
+
+ uint8_t *data = buffer_data(data_to_send);
+ int len = buffer_len(data_to_send) - mac->dgstSize;
+
+ if (cipher->crypt(cipher, data, data, len) != 1)
+ return -ECRYPT;
+ }
+
+ *seq = *seq + 1;
+ return 0;
+}