Changing format of secret key file.

This commit is contained in:
Jérôme HAMM 2021-12-07 21:44:57 +01:00 committed by A Wireshark GitLab Utility
parent 947d80c477
commit 2874b979ad
1 changed files with 234 additions and 178 deletions

View File

@ -78,20 +78,17 @@ void proto_reg_handoff_ssh(void);
typedef struct {
guint8 *data;
guint length;
} ssh_kex_key;
} ssh_bignum;
typedef struct {
guint8 *data;
guint length;
guint8 type;
} ssh_kex_pub_key;
#define SSH_KEX_CURVE25519 0x00010000
#define SSH_KEX_HASH_SHA256 2
typedef struct {
guint8 *data;
guint length;
} ssh_enc_key;
#define SSH_KEX_CURVE25519 1
#endif
struct ssh_peer_data {
@ -122,6 +119,10 @@ struct ssh_peer_data {
gchar* comp;
gint length_is_plaintext;
#ifdef SSH_DECRYPTION_SUPPORTED
ssh_bignum *bn_cookie;
#endif
};
struct ssh_flow_data {
@ -140,11 +141,22 @@ struct ssh_flow_data {
#ifdef SSH_DECRYPTION_SUPPORTED
gchar *session_id;
guint session_id_length;
ssh_kex_pub_key *kex_e;
ssh_bignum *kex_e;
ssh_bignum *kex_f;
ssh_bignum *secret;
wmem_array_t *kex_client_version;
wmem_array_t *kex_server_version;
wmem_array_t *kex_client_key_exchange_init;
wmem_array_t *kex_server_key_exchange_init;
wmem_array_t *kex_server_host_key_blob;
wmem_array_t *kex_shared_secret;
gboolean do_decrypt;
wmem_array_t *kex_hash_buffer;
#endif
};
static GHashTable * ssh_master_key_map = NULL;
static int proto_ssh = -1;
/* Version exchange */
@ -253,7 +265,6 @@ static dissector_handle_t ssh_handle;
#ifdef SSH_DECRYPTION_SUPPORTED
static const char *pref_keylog_file;
static FILE *ssh_keylog_file;
static wmem_map_t *ssh_kex_keys;
#endif
// 29418/tcp: Gerrit Code Review
@ -421,27 +432,26 @@ static void ssh_set_kex_specific_dissector(struct ssh_flow_data *global_data);
#ifdef SSH_DECRYPTION_SUPPORTED
static void ssh_keylog_read_file(void);
static void ssh_keylog_process_line(char *line);
static void ssh_keylog_process_line(const char *line);
static void ssh_keylog_reset(void);
static void ssh_keylog_add_keys(guint8 *priv, guint priv_length,
gchar *type_string);
static ssh_kex_key *ssh_kex_make_key(guint8 *data, guint length);
static ssh_kex_pub_key *ssh_kex_make_pub_key(guint8 *data, guint length,
gchar type);
static ssh_bignum *ssh_kex_make_bignum(const guint8 *data, guint length);
static void ssh_read_e(tvbuff_t *tvb, int offset,
struct ssh_flow_data *global_data);
static void ssh_keylog_compute_hash(tvbuff_t *tvb, int offset,
static void ssh_read_f(tvbuff_t *tvb, int offset,
struct ssh_flow_data *global_data);
static ssh_kex_key *ssh_kex_shared_secret(ssh_kex_pub_key *pub, ssh_kex_key *priv);
static void ssh_keylog_hash_write_secret(tvbuff_t *tvb, int offset,
struct ssh_flow_data *global_data);
static ssh_bignum *ssh_kex_shared_secret(gint kex_type, ssh_bignum *pub, ssh_bignum *priv);
static void ssh_hash_buffer_put_string(wmem_array_t *buffer, const gchar *string,
guint len);
static gchar *ssh_string(const gchar *string, guint len);
static void ssh_derive_symmetric_keys(ssh_kex_key *shared_secret,
static void ssh_derive_symmetric_keys(ssh_bignum *shared_secret,
gchar *exchange_hash, guint hash_length,
struct ssh_flow_data *global_data);
static void ssh_derive_symmetric_key(ssh_kex_key *shared_secret,
static void ssh_derive_symmetric_key(ssh_bignum *shared_secret,
gchar *exchange_hash, guint hash_length, gchar id,
ssh_enc_key *result_key, struct ssh_flow_data *global_data);
#endif
static int
@ -470,6 +480,15 @@ dissect_ssh(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
global_data->peer_data[SERVER_PEER_DATA].mac_length = -1;
#ifdef SSH_DECRYPTION_SUPPORTED
global_data->kex_hash_buffer = wmem_array_new(wmem_file_scope(), 1);
global_data->peer_data[CLIENT_PEER_DATA].bn_cookie = NULL;
global_data->peer_data[SERVER_PEER_DATA].bn_cookie = NULL;
global_data->kex_client_version = wmem_array_new(wmem_file_scope(), 1);
global_data->kex_server_version = wmem_array_new(wmem_file_scope(), 1);
global_data->kex_client_key_exchange_init = wmem_array_new(wmem_file_scope(), 1);
global_data->kex_server_key_exchange_init = wmem_array_new(wmem_file_scope(), 1);
global_data->kex_server_host_key_blob = wmem_array_new(wmem_file_scope(), 1);
global_data->kex_shared_secret = wmem_array_new(wmem_file_scope(), 1);
global_data->do_decrypt = TRUE;
#endif
conversation_add_proto_data(conversation, proto_ssh, global_data);
@ -776,7 +795,7 @@ ssh_tree_add_hostkey(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
// server host key (K_S / Q)
#ifdef SSH_DECRYPTION_SUPPORTED
gchar *data = (gchar *)tvb_memdup(wmem_packet_scope(), tvb, last_offset + 4, key_len);
ssh_hash_buffer_put_string(global_data->kex_hash_buffer, data, key_len);
ssh_hash_buffer_put_string(global_data->kex_server_host_key_blob, data, key_len);
#else
// ignore unused parameter complaint
(void)global_data;
@ -984,8 +1003,11 @@ static int ssh_dissect_kex_dh(guint8 msg_code, tvbuff_t *tvb,
ett_key_exchange_host_key, global_data);
#ifdef SSH_DECRYPTION_SUPPORTED
// f (server ephemeral key public part), K_S (host key)
ssh_keylog_compute_hash(tvb, offset, global_data);
if (!PINFO_FD_VISITED(pinfo)) {
// f (server ephemeral key public part), K_S (host key)
ssh_read_f(tvb, offset, global_data);
ssh_keylog_hash_write_secret(tvb, offset, global_data);
}
#endif
offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_dh_f);
@ -1067,7 +1089,10 @@ ssh_dissect_kex_ecdh(guint8 msg_code, tvbuff_t *tvb,
ett_key_exchange_host_key, global_data);
#ifdef SSH_DECRYPTION_SUPPORTED
ssh_keylog_compute_hash(tvb, offset, global_data);
if (!PINFO_FD_VISITED(pinfo)) {
ssh_read_f(tvb, offset, global_data);
ssh_keylog_hash_write_secret(tvb, offset, global_data);
}
#endif
offset += ssh_tree_add_string(tvb, offset, tree, hf_ssh_ecdh_q_s, hf_ssh_ecdh_q_s_length);
@ -1317,6 +1342,7 @@ ssh_dissect_key_init(tvbuff_t *tvb, int offset, proto_tree *tree,
struct ssh_peer_data *peer_data = &global_data->peer_data[is_response];
key_init_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_key_init, &tf, "Algorithms");
peer_data->bn_cookie = ssh_kex_make_bignum(tvb_get_ptr(tvb, offset, 16), 16);
proto_tree_add_item(key_init_tree, hf_ssh_cookie,
tvb, offset, 16, ENC_NA);
offset += 16;
@ -1457,15 +1483,26 @@ ssh_keylog_read_file(void)
}
}
/* File format: each line follows the format "<type> <key>".
* For available <type>s, see below. <key> is the hex-encoded key (64
* characters).
/* File format: each line follows the format "<cookie> <key>".
* <cookie> is the hex-encoded (client or server) 16 bytes cookie
* (32 characters) found in the SSH_MSG_KEXINIT of the endpoint whose
* private random is disclosed.
* <key> is the private random number that is used to generate the DH
* negotiation (length depends on algorithm). In RFC4253 it is called
* x for the client and y for the server.
* For openssh and DH group exchange, it can be retrieved using
* DH_get0_key(kex->dh, NULL, &server_random)
* for groupN in file kexdh.c function kex_dh_compute_key
* for custom group in file kexgexs.c function input_kex_dh_gex_init
* For openssh and curve25519, it can be found in function kex_c25519_enc
* in variable server_key.
*
* Example:
* curve25519 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
* 90d886612f9c35903db5bb30d11f23c2 DEF830C22F6C927E31972FFB20B46C96D0A5F2D5E7BE5A3A8804D6BFC431619ED10AF589EEDFF4750DEA00EFD7AFDB814B6F3528729692B1F2482041521AE9DC
*/
for (;;) {
char buf[512];
buf[0] = 0;
if (!fgets(buf, sizeof(buf), ssh_keylog_file)) {
if (ferror(ssh_keylog_file)) {
@ -1475,18 +1512,21 @@ ssh_keylog_read_file(void)
break;
}
size_t len = strlen(buf);
while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n')){len-=1;buf[len]=0;}
ssh_keylog_process_line(buf);
}
}
static void
ssh_keylog_process_line(char *line)
ssh_keylog_process_line(const char *line)
{
ws_debug("ssh: process line: %s", line);
gchar **split = g_strsplit(line, " ", 2);
gchar *key, *value;
int key_len;
gchar *cookie, *key;
size_t cookie_len, key_len;
if (g_strv_length(split) != 2) {
ws_debug("ssh keylog: invalid format");
@ -1494,37 +1534,60 @@ ssh_keylog_process_line(char *line)
return;
}
key = split[0];
value = split[1];
// [cookie of corresponding key] [key]
cookie = split[0];
key = split[1];
if (!strcmp(key, "curve25519")) {
key_len = 32;
} else {
ws_debug("ssh: key exchange method not supported");
key_len = strlen(key);
cookie_len = strlen(cookie);
if(key_len & 1){
ws_debug("ssh keylog: invalid format (key could at least be even!)");
g_strfreev(split);
return;
}
gchar hexbyte[3] = {0, 0, 0};
if(cookie_len & 1){
ws_debug("ssh keylog: invalid format (cookie could at least be even!)");
g_strfreev(split);
return;
}
ssh_bignum * bn_cookie = ssh_kex_make_bignum(NULL, cookie_len/2);
ssh_bignum * bn_priv = ssh_kex_make_bignum(NULL, key_len/2);
guint8 c;
guint8 *converted = g_new(guint8, key_len);
for (size_t i = 0; i < key_len/2; i ++) {
gchar v0 = key[i * 2];
gint8 h0 = (v0>='0' && v0<='9')?v0-'0':(v0>='a' && v0<='f')?v0-'a'+10:(v0>='A' && v0<='F')?v0-'A'+10:-1;
gchar v1 = key[i * 2 + 1];
gint8 h1 = (v1>='0' && v1<='9')?v1-'0':(v1>='a' && v1<='f')?v1-'a'+10:(v1>='A' && v1<='F')?v1-'A'+10:-1;
for (int i = 0; i < key_len; i ++) {
hexbyte[0] = value[i * 2];
hexbyte[1] = value[i * 2 + 1];
if (!ws_hexstrtou8(hexbyte, NULL, &c)) {
ws_debug("ssh: can't process key, invalid hex number: %s", hexbyte);
g_free(converted);
if (h0==-1 || h1==-1) {
ws_debug("ssh: can't process key, invalid hex number: %c%c", v0, v1);
g_strfreev(split);
return;
}
converted[i] = c;
c = (h0 << 4) | h1;
bn_priv->data[i] = c;
}
ssh_keylog_add_keys(converted, key_len, key);
g_free(converted);
for (size_t i = 0; i < cookie_len/2; i ++) {
gchar v0 = cookie[i * 2];
gint8 h0 = (v0>='0' && v0<='9')?v0-'0':(v0>='a' && v0<='f')?v0-'a'+10:(v0>='A' && v0<='F')?v0-'A'+10:-1;
gchar v1 = cookie[i * 2 + 1];
gint8 h1 = (v1>='0' && v1<='9')?v1-'0':(v1>='a' && v1<='f')?v1-'a'+10:(v1>='A' && v1<='F')?v1-'A'+10:-1;
if (h0==-1 || h1==-1) {
ws_debug("ssh: can't process cookie, invalid hex number: %c%c", v0, v1);
g_strfreev(split);
return;
}
c = (h0 << 4) | h1;
bn_cookie->data[i] = c;
}
g_hash_table_insert(ssh_master_key_map, bn_cookie, bn_priv);
g_strfreev(split);
}
@ -1547,90 +1610,55 @@ ssh_kex_type(char *type)
return 0;
}
static void
ssh_keylog_add_keys(guint8 *priv, guint priv_length, gchar *type_string)
static guint
ssh_kex_hash_type(gchar *type_string)
{
guint type = ssh_kex_type(type_string);
ssh_kex_pub_key *pub = ssh_kex_make_pub_key(NULL, priv_length, type);
if (SSH_KEX_CURVE25519 == type) {
if (crypto_scalarmult_curve25519_base(pub->data, priv)) {
ws_debug("cannot compute curve25519 public key");
return;
}
if (g_str_has_suffix(type_string, "sha256")) {
return SSH_KEX_HASH_SHA256;
} else {
ws_debug("key type %s not supported", type_string);
return;
}
if (!wmem_map_contains(ssh_kex_keys, pub)) {
ssh_kex_key *value = ssh_kex_make_key(NULL, priv_length);
if (!value) {
ws_debug("invalid key length %u", priv_length);
return;
}
memcpy(value->data, priv, priv_length);
wmem_map_insert(ssh_kex_keys, pub, value);
ws_debug("hash type %s not supported", type_string);
return 0;
}
}
// This was the largest valid value I (gcc) could find.
// https://github.com/openssh/openssh-portable/blob/0a4a5571ada76b1b012bec9cf6ad1203fc19ec8d/sshkey.c#L1589
#define MAX_SSH_KEY_BYTES 16384
static ssh_kex_key *
ssh_kex_make_key(guint8 *data, guint length)
static ssh_bignum *
ssh_kex_make_bignum(const guint8 *data, guint length)
{
if (length >= MAX_SSH_KEY_BYTES) {
return NULL;
}
ssh_kex_key *key = wmem_new0(wmem_file_scope(), ssh_kex_key);
key->data = (guint8 *)wmem_alloc0(wmem_file_scope(), length);
ssh_bignum *bn = wmem_new0(wmem_file_scope(), ssh_bignum);
bn->data = (guint8 *)wmem_alloc0(wmem_file_scope(), length);
if (data) {
memcpy(key->data, data, length);
memcpy(bn->data, data, length);
}
key->length = length;
return key;
}
static ssh_kex_pub_key *
ssh_kex_make_pub_key(guint8 *data, guint length, gchar type)
{
if (length >= MAX_SSH_KEY_BYTES) {
return NULL;
}
ssh_kex_pub_key *key = wmem_new0(wmem_file_scope(), ssh_kex_pub_key);
key->data = (guint8 *)wmem_alloc0(wmem_file_scope(), length);
if (data) {
memcpy(key->data, data, length);
}
key->length = length;
key->type = type;
return key;
bn->length = length;
return bn;
}
static void
ssh_read_e(tvbuff_t *tvb, int offset, struct ssh_flow_data *global_data)
{
// store the client's public part (e) for later usage
guint length = tvb_get_ntohl(tvb, offset);
guint type = ssh_kex_type(global_data->kex);
ssh_kex_pub_key *kex = ssh_kex_make_pub_key(NULL, length, type);
if (!kex) {
int length = tvb_get_ntohl(tvb, offset);
global_data->kex_e = ssh_kex_make_bignum(NULL, length);
if (!global_data->kex_e) {
ws_debug("invalid key length %u", length);
return;
}
global_data->kex_e = kex;
tvb_memcpy(tvb, global_data->kex_e->data, offset + 4, length);
}
static void
ssh_keylog_compute_hash(tvbuff_t *tvb, int offset,
ssh_read_f(tvbuff_t *tvb, int offset, struct ssh_flow_data *global_data)
{
// store the server's public part (f) for later usage
int length = tvb_get_ntohl(tvb, offset);
global_data->kex_f = ssh_kex_make_bignum(NULL, length);
tvb_memcpy(tvb, global_data->kex_f->data, offset + 4, length);
}
static void
ssh_keylog_hash_write_secret(tvbuff_t *tvb, int offset,
struct ssh_flow_data *global_data)
{
/*
@ -1641,90 +1669,95 @@ ssh_keylog_compute_hash(tvbuff_t *tvb, int offset,
* All key exchange methods:
* https://www.iana.org/assignments/ssh-parameters/ssh-parameters.xhtml#ssh-parameters-16
*/
if (global_data->kex_hash_buffer == NULL) {
return;
}
gcry_md_hd_t hd;
ssh_kex_key *secret, *priv;
ssh_kex_pub_key kex_f;
ssh_bignum *secret = NULL, *priv;
int length;
// TODO support other key exchange algorithms than curve25519-sha256
guint hash_len = 32;
ssh_keylog_read_file();
if (global_data->kex_e == NULL) {
return;
}
length = tvb_get_ntohl(tvb, offset);
kex_f.length = length;
kex_f.data = (gchar *)tvb_memdup(wmem_packet_scope(), tvb, offset + 4, length);
kex_f.type = global_data->kex_e->type;
priv = (ssh_kex_key *)wmem_map_lookup(ssh_kex_keys, global_data->kex_e);
guint kex_type = ssh_kex_type(global_data->kex);
guint kex_hash_type = ssh_kex_hash_type(global_data->kex);
if (!priv) {
priv = (ssh_kex_key *)wmem_map_lookup(ssh_kex_keys, &kex_f);
if (!priv) {
ws_debug("ssh decryption: private key not available");
return;
// we have the server's private key
} else {
secret = ssh_kex_shared_secret(global_data->kex_e, priv);
priv = (ssh_bignum *)g_hash_table_lookup(ssh_master_key_map, global_data->peer_data[SERVER_PEER_DATA].bn_cookie);
if(priv){
secret = ssh_kex_shared_secret(kex_type, global_data->kex_e, priv);
}else{
priv = (ssh_bignum *)g_hash_table_lookup(ssh_master_key_map, global_data->peer_data[CLIENT_PEER_DATA].bn_cookie);
if(priv){
secret = ssh_kex_shared_secret(kex_type, global_data->kex_f, priv);
}
// we have the client's private key
} else {
secret = ssh_kex_shared_secret(&kex_f, priv);
}
if (!secret) {
ws_debug("ssh decryption: no private key for this session");
global_data->do_decrypt = FALSE;
return;
}
ssh_hash_buffer_put_string(global_data->kex_hash_buffer,
global_data->kex_e->data, length);
ssh_hash_buffer_put_string(global_data->kex_hash_buffer, kex_f.data, length);
// shared secret data needs to be written as an mpint, and we need it later
if (secret->data[0] & 0x80) {
gchar *tmp = (gchar *)wmem_alloc0(wmem_packet_scope(), length + 1);
memcpy(tmp + 1, secret->data, length);
if (secret->data[0] & 0x80) { // Stored in Big endian
length = secret->length + 1;
gchar *tmp = (gchar *)wmem_alloc0(wmem_packet_scope(), length);
memcpy(tmp + 1, secret->data, secret->length);
tmp[0] = 0;
secret->data = tmp;
secret->length = length + 1;
ssh_hash_buffer_put_string(global_data->kex_hash_buffer, secret->data,
length + 1);
} else
ssh_hash_buffer_put_string(global_data->kex_hash_buffer, secret->data,
length);
secret->length = length;
}
ssh_hash_buffer_put_string(global_data->kex_shared_secret, secret->data, secret->length);
wmem_array_t * kex_e = wmem_array_new(wmem_packet_scope(), 1);
if(global_data->kex_e){ssh_hash_buffer_put_string(kex_e, global_data->kex_e->data, global_data->kex_e->length);}
wmem_array_t * kex_f = wmem_array_new(wmem_packet_scope(), 1);
if(global_data->kex_f){ssh_hash_buffer_put_string(kex_f, global_data->kex_f->data, global_data->kex_f->length);}
wmem_array_t * kex_hash_buffer = wmem_array_new(wmem_packet_scope(), 1);
wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_client_version), wmem_array_get_count(global_data->kex_client_version));
wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_server_version), wmem_array_get_count(global_data->kex_server_version));
wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_client_key_exchange_init), wmem_array_get_count(global_data->kex_client_key_exchange_init));
wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_server_key_exchange_init), wmem_array_get_count(global_data->kex_server_key_exchange_init));
wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_server_host_key_blob), wmem_array_get_count(global_data->kex_server_host_key_blob));
if(kex_type==SSH_KEX_CURVE25519){
wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_e), wmem_array_get_count(kex_e));
wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_f), wmem_array_get_count(kex_f));
}
wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_shared_secret), wmem_array_get_count(global_data->kex_shared_secret));
guint hash_len = 32;
if(kex_hash_type==SSH_KEX_HASH_SHA256){
gcry_md_open(&hd, GCRY_MD_SHA256, 0);
hash_len = 32;
} else {
ws_debug("kex_hash_type type %d not supported", kex_hash_type);
return;
}
gchar *exchange_hash = (gchar *)wmem_alloc0(wmem_file_scope(), hash_len);
gcry_md_open(&hd, GCRY_MD_SHA256, 0);
gcry_md_write(hd, wmem_array_get_raw(global_data->kex_hash_buffer),
wmem_array_get_count(global_data->kex_hash_buffer));
gcry_md_write(hd, wmem_array_get_raw(kex_hash_buffer), wmem_array_get_count(kex_hash_buffer));
memcpy(exchange_hash, gcry_md_read(hd, 0), hash_len);
gcry_md_close(hd);
global_data->kex_hash_buffer = NULL;
global_data->secret = secret;
ssh_derive_symmetric_keys(secret, exchange_hash, hash_len, global_data);
}
// the purpose of this function is to deal with all different kex methods
static ssh_kex_key *
ssh_kex_shared_secret(ssh_kex_pub_key *pub, ssh_kex_key *priv)
static ssh_bignum *
ssh_kex_shared_secret(gint kex_type, ssh_bignum *pub, ssh_bignum *priv)
{
ssh_kex_key *secret = ssh_kex_make_key(NULL, pub->length);
ssh_bignum *secret = ssh_kex_make_bignum(NULL, pub->length);
if (!secret) {
ws_debug("invalid key length %u", pub->length);
return NULL;
}
if (crypto_scalarmult_curve25519(secret->data, priv->data, pub->data)) {
ws_debug("curve25519: can't compute shared secret");
return NULL;
if(kex_type==SSH_KEX_CURVE25519){
if (crypto_scalarmult_curve25519(secret->data, priv->data, pub->data)) {
ws_debug("curve25519: can't compute shared secret");
return NULL;
}
} else {
ws_debug("kex_type type %d not supported", kex_type);
return 0;
}
return secret;
@ -1754,7 +1787,7 @@ ssh_hash_buffer_put_string(wmem_array_t *buffer, const gchar *string,
wmem_array_append(buffer, string_with_length, length + 4);
}
static void ssh_derive_symmetric_keys(ssh_kex_key *secret, gchar *exchange_hash,
static void ssh_derive_symmetric_keys(ssh_bignum *secret, gchar *exchange_hash,
guint hash_length, struct ssh_flow_data *global_data)
{
ssh_enc_key keys[6];
@ -1770,7 +1803,7 @@ static void ssh_derive_symmetric_keys(ssh_kex_key *secret, gchar *exchange_hash,
}
}
static void ssh_derive_symmetric_key(ssh_kex_key *secret, gchar *exchange_hash,
static void ssh_derive_symmetric_key(ssh_bignum *secret, gchar *exchange_hash,
guint hash_length, gchar id, ssh_enc_key *result_key,
struct ssh_flow_data *global_data)
{
@ -1807,21 +1840,46 @@ static void ssh_derive_symmetric_key(ssh_kex_key *secret, gchar *exchange_hash,
result_key->length = need;
}
static guint
ssh_kex_pub_key_hash(gconstpointer v1)
/* Functions for SSH random hashtables. {{{ */
static gint
ssh_equal (gconstpointer v, gconstpointer v2)
{
const ssh_kex_pub_key *key1 = (const ssh_kex_pub_key *)v1;
return wmem_strong_hash(key1->data, key1->length);
const ssh_bignum *val1;
const ssh_bignum *val2;
val1 = (const ssh_bignum *)v;
val2 = (const ssh_bignum *)v2;
if (val1->length == val2->length &&
!memcmp(val1->data, val2->data, val2->length)) {
return 1;
}
return 0;
}
static gboolean
ssh_kex_pub_key_equal(gconstpointer v1, gconstpointer v2)
static guint
ssh_hash (gconstpointer v)
{
const ssh_kex_pub_key *key1 = (const ssh_kex_pub_key *)v1;
const ssh_kex_pub_key *key2 = (const ssh_kex_pub_key *)v2;
return key1->type == key2->type && key1->length == key2->length &&
!memcmp(key1->data, key2->data, key1->length);
guint l,hash;
const ssh_bignum* id;
const guint* cur;
hash = 0;
id = (const ssh_bignum*) v;
/* id and id->data are mallocated in ssh_save_master_key(). As such 'data'
* should be aligned for any kind of access (for example as a guint as
* is done below). The intermediate void* cast is to prevent "cast
* increases required alignment of target type" warnings on CPUs (such
* as SPARCs) that do not allow misaligned memory accesses.
*/
cur = (const guint*)(void*) id->data;
for (l=4; (l < id->length); l+=4, cur++)
hash = hash ^ (*cur);
return hash;
}
/* Functions for SSH random hashtables. }}} */
#endif /* SSH_DECRYPTION_SUPPORTED */
void
@ -2214,14 +2272,12 @@ proto_register_ssh(void)
&ssh_desegment);
#ifdef SSH_DECRYPTION_SUPPORTED
ssh_master_key_map = g_hash_table_new(ssh_hash, ssh_equal);
prefs_register_filename_preference(ssh_module, "keylog_file", "Key log filename",
"The path to the file which contains a list of key exchange secrets in the following format:\n"
"\"<key-type> <hex-encoded-key>\" (without quotes or leading spaces).\n"
"<key-type> is one of: curve25519. ",
"\"<hex-encoded-cookie> <hex-encoded-key>\" (without quotes or leading spaces).\n",
&pref_keylog_file, FALSE);
ssh_kex_keys = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
ssh_kex_pub_key_hash, ssh_kex_pub_key_equal);
#endif
ssh_handle = register_dissector("ssh", dissect_ssh, proto_ssh);