void crypto_free(struct ssh_crypto_struct *crypto){ if (crypto == NULL) { return; } SAFE_FREE(crypto->server_pubkey); cipher_free(crypto->in_cipher); cipher_free(crypto->out_cipher); bignum_free(crypto->e); bignum_free(crypto->f); bignum_free(crypto->x); bignum_free(crypto->y); bignum_free(crypto->k); /* lot of other things */ #ifdef WITH_LIBZ if (crypto->compress_out_ctx && (deflateEnd(crypto->compress_out_ctx) != 0)) { inflateEnd(crypto->compress_out_ctx); } if (crypto->compress_in_ctx && (deflateEnd(crypto->compress_in_ctx) != 0)) { inflateEnd(crypto->compress_in_ctx); } #endif /* i'm lost in my own code. good work */ memset(crypto,0,sizeof(*crypto)); SAFE_FREE(crypto); }
void bignum_init_base_convert(size_t size, int base) { bignum multiplier; bignum_init(&multiplier); bignum_from_int(&multiplier, 1); mul_lut = malloc(size * sizeof(bignum)); mul_lut_size = size; for (int i = 0; i < size; ++i) { bignum_init(&mul_lut[i]); bignum_copy(&mul_lut[i], &multiplier); bignum_mul_int(&multiplier, base); } bignum_free(&multiplier); bignum sum; bignum_init(&sum); for (int i = 0; i < SUMSZ; ++i) { for (int j = 0; j < 256; ++j) { int m = i*8; bignum_from_int(&sum, 0); for (uint8_t mask = 1; mask != 0; mask <<= 1) { if (j & mask) { bignum_add(&sum, &mul_lut[m]); } ++m; } bignum_init(&sum_lut[i][j]); bignum_copy(&sum_lut[i][j], &sum); } } bignum_free(&sum); }
/* returns 1 if the modulus of k1 is < than the one of k2 */ static int modulus_smaller(ssh_public_key k1, ssh_public_key k2){ bignum n1; bignum n2; int res; #ifdef HAVE_LIBGCRYPT gcry_sexp_t sexp; sexp=gcry_sexp_find_token(k1->rsa_pub,"n",0); n1=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG); gcry_sexp_release(sexp); sexp=gcry_sexp_find_token(k2->rsa_pub,"n",0); n2=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG); gcry_sexp_release(sexp); #elif defined HAVE_LIBCRYPTO n1=k1->rsa_pub->n; n2=k2->rsa_pub->n; #endif if(bignum_cmp(n1,n2)<0) res=1; else res=0; #ifdef HAVE_LIBGCRYPT bignum_free(n1); bignum_free(n2); #endif return res; }
char *my_gcry_bn2dec(bignum bn) { bignum bndup, num, ten; char *ret; int count, count2; int size, rsize; char decnum; size = gcry_mpi_get_nbits(bn) * 3; rsize = size / 10 + size / 1000 + 2; ret = malloc(rsize + 1); if (ret == NULL) { return NULL; } if (!gcry_mpi_cmp_ui(bn, 0)) { strcpy(ret, "0"); } else { ten = bignum_new(); if (ten == NULL) { SAFE_FREE(ret); return NULL; } num = bignum_new(); if (num == NULL) { SAFE_FREE(ret); bignum_free(ten); return NULL; } for (bndup = gcry_mpi_copy(bn), bignum_set_word(ten, 10), count = rsize; count; count--) { gcry_mpi_div(bndup, num, bndup, ten, 0); for (decnum = 0, count2 = gcry_mpi_get_nbits(num); count2; decnum *= 2, decnum += (gcry_mpi_test_bit(num, count2 - 1) ? 1 : 0), count2--) ; ret[count - 1] = decnum + '0'; } for (count = 0; count < rsize && ret[count] == '0'; count++) ; for (count2 = 0; count2 < rsize - count; ++count2) { ret[count2] = ret[count2 + count]; } ret[count2] = 0; bignum_free(num); bignum_free(bndup); bignum_free(ten); } return ret; }
void bignum_free_base_convert_lut() { for (int i = 0; i < mul_lut_size; ++i) { bignum_free(&mul_lut[i]); } free(mul_lut); mul_lut = NULL; mul_lut_size = 0; for (int i = 0; i < SUMSZ; ++i) { for (int j = 0; j < 256; ++j) { bignum_free(&sum_lut[i][j]); } } }
void ssh_crypto_finalize(void) { if (ssh_crypto_initialized) { bignum_free(g); g = NULL; bignum_free(p); p = NULL; #ifdef HAVE_LIBGCRYPT gcry_control(GCRYCTL_TERM_SECMEM); #elif defined HAVE_LIBCRYPTO EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); #endif ssh_crypto_initialized=0; } }
static int base58_decode(mrb_state *mrb, char *dst, const char *data, int length, const char *chars) { int leading_zero = 0; int i; Bignum *result = bignum_alloc_char(mrb, 0); Bignum *base = bignum_alloc_char(mrb, 1); int b_length; for (i = 0; i < length; ++i) { if (data[i] == chars[0]) { leading_zero++; } else { break; } } memset(dst, 0, leading_zero); for (i = length - 1; i > leading_zero - 1; --i) { Bignum *f = bignum_alloc_char(mrb, 0); int j, c = -1; for (j = 0; j < 58; ++j) { if (data[i] == chars[j]) { c = j; break; } } if (c == -1) return -1; for (j = 0; j < c; ++j) bignum_add(result, base); for (j = 0; j < 58; ++j) bignum_add(f, base); bignum_free(base); base = f; } bignum_free(base); b_length = bignum_length(result); memcpy(dst + leading_zero, result->data + result->len - b_length , b_length); bignum_free(result); return leading_zero + b_length; }
// a %= b void bignum_mod(bignum *a, bignum *b) { bignum tmp; bignum_init(&tmp); bignum_div_mod(a, b, &tmp); bignum_copy(a, &tmp); bignum_free(&tmp); }
// a *= b void bignum_mul_int(bignum *a, unsigned int b) { bignum tmp; bignum_init(&tmp); uint8_t b_bytes[] = { b & 0x000000ff, (b & 0x0000ff00) >> 8, (b & 0x00ff0000) >> 16, (b & 0xff000000) >> 24, }; int b_size = 3; while (b_size > 1 && b_bytes[b_size] == 0) --b_size; for (int bi = 0; bi < b_size; ++bi) { int carry = 0; for (int ai = 0; ai < a->size; ++ai) { int prod = carry + a->data[ai] * b_bytes[bi]; carry = prod / 256; tmp.data[ai + bi] = prod % 256; } tmp.data[bi + a->size] = carry; } tmp.size = a->size + b_size; while (tmp.size > 0 && tmp.data[tmp.size - 1] == 0) { --tmp.size; } if (tmp.size == 0) { tmp.size = 1; } bignum_copy(a, &tmp); bignum_free(&tmp); }
// a *= b void bignum_mul_int_silly_loop(bignum *a, unsigned int b) { bignum tmp; bignum_init(&tmp); bignum_copy(&tmp, a); --b; // XXX: this loop is probably quite inefficient, think of something better while (b > 0) { bignum_add(a, &tmp); --b; } bignum_free(&tmp); }
void crypto_free(CRYPTO *crypto){ if (crypto == NULL) { return; } SAFE_FREE(crypto->server_pubkey); cipher_free(crypto->in_cipher); cipher_free(crypto->out_cipher); bignum_free(crypto->e); bignum_free(crypto->f); bignum_free(crypto->x); bignum_free(crypto->y); bignum_free(crypto->k); /* lot of other things */ /* i'm lost in my own code. good work */ memset(crypto,0,sizeof(*crypto)); SAFE_FREE(crypto); }
/* * This inits the values g and p which are used for DH key agreement * FIXME: Make the function thread safe by adding a semaphore or mutex. */ int ssh_crypto_init(void) { if (ssh_crypto_initialized == 0) { #ifdef HAVE_LIBGCRYPT gcry_check_version(NULL); if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P,0)) { gcry_control(GCRYCTL_INIT_SECMEM, 4096); gcry_control(GCRYCTL_INITIALIZATION_FINISHED,0); } #endif g = bignum_new(); if (g == NULL) { return -1; } bignum_set_word(g,g_int); #ifdef HAVE_LIBGCRYPT bignum_bin2bn(p_group1_value, P_GROUP1_LEN, &p_group1); if (p_group1 == NULL) { bignum_free(g); g = NULL; return -1; } bignum_bin2bn(p_group14_value, P_GROUP14_LEN, &p_group14); if (p_group14 == NULL) { bignum_free(g); bignum_free(p_group1); g = NULL; p_group1 = NULL; return -1; } #elif defined HAVE_LIBCRYPTO p_group1 = bignum_new(); if (p_group1 == NULL) { bignum_free(g); g = NULL; return -1; } bignum_bin2bn(p_group1_value, P_GROUP1_LEN, p_group1); p_group14 = bignum_new(); if (p_group14 == NULL) { bignum_free(g); bignum_free(p_group1); g = NULL; p_group1 = NULL; return -1; } bignum_bin2bn(p_group14_value, P_GROUP14_LEN, p_group14); OpenSSL_add_all_algorithms(); #endif ssh_crypto_initialized = 1; } return 0; }
/* Examples: 82000 (base 3) = 11011111001 = 1*3**0 + 0*3**1 + 0*3**2 + 1*3**3 +3**4 +3**5 +3**6 +3**7 +0*3**8 +3**9 +3**10 82000 (base 5) = 10111000 = 0*5**0 + 0*5**1 + 0*5**2 + 1*5**3 + 1*5**4 + 1*5**5 + 0*5**6 + 1*5**7 */ void bignum_from_string_binary(bignum *n, char const* s, size_t base) { char const *end_of_s = s + strlen(s) - 1; bignum_from_int(n, 0); bignum multiplier; bignum_init(&multiplier); bignum_from_int(&multiplier, 1); while (end_of_s != s) { assert((*end_of_s == '1') || (*end_of_s == '0')); if (*end_of_s == '1') { bignum_add(n, &multiplier); } bignum_mul_int(&multiplier, base); --end_of_s; } bignum_add(n, &multiplier); bignum_free(&multiplier); }
static int base58_encode_reverse(mrb_state *mrb, char *dst, const char *data, int length, const char *chars) { Bignum *b = bignum_alloc(mrb, data, length); int index = 0; int i; do { dst[index] = chars[bignum_div(b, 58)]; index++; } while (!bignum_is_zero(b)); for (i = 0; i < length; ++i) { if (data[i] == 0) { dst[index] = chars[0]; index++; } else { break; } } bignum_free(b); return index; }
void crypto_free(struct ssh_crypto_struct *crypto){ int i; if (crypto == NULL) { return; } SAFE_FREE(crypto->server_pubkey); cipher_free(crypto->in_cipher); cipher_free(crypto->out_cipher); bignum_free(crypto->e); bignum_free(crypto->f); bignum_free(crypto->x); bignum_free(crypto->y); bignum_free(crypto->k); #ifdef HAVE_ECDH SAFE_FREE(crypto->ecdh_client_pubkey); SAFE_FREE(crypto->ecdh_server_pubkey); #endif if(crypto->session_id != NULL){ memset(crypto->session_id, '\0', crypto->digest_len); SAFE_FREE(crypto->session_id); } #ifdef WITH_ZLIB if (crypto->compress_out_ctx && (deflateEnd(crypto->compress_out_ctx) != 0)) { inflateEnd(crypto->compress_out_ctx); } if (crypto->compress_in_ctx && (deflateEnd(crypto->compress_in_ctx) != 0)) { inflateEnd(crypto->compress_in_ctx); } #endif /* WITH_ZLIB */ if(crypto->encryptIV) SAFE_FREE(crypto->encryptIV); if(crypto->decryptIV) SAFE_FREE(crypto->decryptIV); if(crypto->encryptMAC) SAFE_FREE(crypto->encryptMAC); if(crypto->decryptMAC) SAFE_FREE(crypto->decryptMAC); if(crypto->encryptkey){ memset(crypto->encryptkey, 0, crypto->digest_len); SAFE_FREE(crypto->encryptkey); } if(crypto->decryptkey){ memset(crypto->decryptkey, 0, crypto->digest_len); SAFE_FREE(crypto->decryptkey); } for (i = 0; i < SSH_KEX_METHODS; i++) { SAFE_FREE(crypto->client_kex.methods[i]); SAFE_FREE(crypto->server_kex.methods[i]); SAFE_FREE(crypto->kex_methods[i]); } memset(crypto,0,sizeof(*crypto)); SAFE_FREE(crypto); }
/** * @brief Write the current server as known in the known hosts file. * * This will create the known hosts file if it does not exist. You generaly use * it when ssh_is_server_known() answered SSH_SERVER_NOT_KNOWN. * * @param[in] session The ssh session to use. * * @return SSH_OK on success, SSH_ERROR on error. */ int ssh_write_knownhost(ssh_session session) { ssh_string pubkey; unsigned char *pubkey_64; char buffer[4096] = {0}; FILE *file; char *dir; char *host; char *hostport; size_t len = 0; if (session->host == NULL) { ssh_set_error(session, SSH_FATAL, "Can't write host in known hosts if the hostname isn't known"); return SSH_ERROR; } host = ssh_lowercase(session->host); /* If using a nonstandard port, save the host in the [host]:port format */ if(session->port != 22){ hostport = ssh_hostport(host,session->port); SAFE_FREE(host); host=hostport; hostport=NULL; } if (session->knownhosts == NULL) { if (ssh_options_apply(session) < 0) { ssh_set_error(session, SSH_FATAL, "Can't find a known_hosts file"); return SSH_ERROR; } } if(session->current_crypto==NULL) { ssh_set_error(session, SSH_FATAL, "No current crypto context"); return SSH_ERROR; } pubkey = session->current_crypto->server_pubkey; if(pubkey == NULL){ ssh_set_error(session, SSH_FATAL, "No public key present"); return SSH_ERROR; } /* Check if ~/.ssh exists and create it if not */ dir = ssh_dirname(session->knownhosts); if (dir == NULL) { ssh_set_error(session, SSH_FATAL, "%s", strerror(errno)); return -1; } if (! ssh_file_readaccess_ok(dir)) { if (ssh_mkdir(dir, 0700) < 0) { ssh_set_error(session, SSH_FATAL, "Cannot create %s directory.", dir); SAFE_FREE(dir); return -1; } } SAFE_FREE(dir); file = fopen(session->knownhosts, "a"); if (file == NULL) { ssh_set_error(session, SSH_FATAL, "Couldn't open known_hosts file %s for appending: %s", session->knownhosts, strerror(errno)); SAFE_FREE(host); return -1; } if (strcmp(session->current_crypto->server_pubkey_type, "ssh-rsa1") == 0) { /* openssh uses a different format for ssh-rsa1 keys. Be compatible --kv */ ssh_public_key key; char *e_string = NULL; char *n_string = NULL; bignum e = NULL; bignum n = NULL; int rsa_size; #ifdef HAVE_LIBGCRYPT gcry_sexp_t sexp; #endif key = publickey_from_string(session, pubkey); if (key == NULL) { fclose(file); SAFE_FREE(host); return -1; } #ifdef HAVE_LIBGCRYPT sexp = gcry_sexp_find_token(key->rsa_pub, "e", 0); if (sexp == NULL) { publickey_free(key); fclose(file); SAFE_FREE(host); return -1; } e = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG); gcry_sexp_release(sexp); if (e == NULL) { publickey_free(key); fclose(file); SAFE_FREE(host); return -1; } sexp = gcry_sexp_find_token(key->rsa_pub, "n", 0); if (sexp == NULL) { publickey_free(key); bignum_free(e); fclose(file); SAFE_FREE(host); return -1; } n = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG); gcry_sexp_release(sexp); if (n == NULL) { publickey_free(key); bignum_free(e); fclose(file); SAFE_FREE(host); return -1; } rsa_size = (gcry_pk_get_nbits(key->rsa_pub) + 7) / 8; #elif defined HAVE_LIBCRYPTO e = key->rsa_pub->e; n = key->rsa_pub->n; rsa_size = RSA_size(key->rsa_pub); #endif e_string = bignum_bn2dec(e); n_string = bignum_bn2dec(n); if (e_string == NULL || n_string == NULL) { #ifdef HAVE_LIBGCRYPT bignum_free(e); bignum_free(n); SAFE_FREE(e_string); SAFE_FREE(n_string); #elif defined HAVE_LIBCRYPTO OPENSSL_free(e_string); OPENSSL_free(n_string); #endif publickey_free(key); fclose(file); SAFE_FREE(host); return -1; } snprintf(buffer, sizeof(buffer), "%s %d %s %s\n", host, rsa_size << 3, e_string, n_string); #ifdef HAVE_LIBGCRYPT bignum_free(e); bignum_free(n); SAFE_FREE(e_string); SAFE_FREE(n_string); #elif defined HAVE_LIBCRYPTO OPENSSL_free(e_string); OPENSSL_free(n_string); #endif publickey_free(key); } else { pubkey_64 = bin_to_base64(pubkey->string, ssh_string_len(pubkey)); if (pubkey_64 == NULL) { fclose(file); SAFE_FREE(host); return -1; } snprintf(buffer, sizeof(buffer), "%s %s %s\n", host, session->current_crypto->server_pubkey_type, pubkey_64); SAFE_FREE(pubkey_64); } SAFE_FREE(host); len = strlen(buffer); if (fwrite(buffer, len, 1, file) != 1 || ferror(file)) { fclose(file); return -1; } fclose(file); return 0; }
/** * @brief Check the public key in the known host line matches the public key of * the currently connected server. * * @param[in] session The SSH session to use. * * @param[in] tokens A list of tokens in the known_hosts line. * * @returns 1 if the key matches, 0 if the key doesn't match and -1 * on error. */ static int check_public_key(ssh_session session, char **tokens) { ssh_string pubkey = session->current_crypto->server_pubkey; ssh_buffer pubkey_buffer; char *pubkey_64; /* ok we found some public key in known hosts file. now un-base64it */ if (alldigits(tokens[1])) { /* openssh rsa1 format */ bignum tmpbn; ssh_string tmpstring; unsigned int len; int i; pubkey_buffer = ssh_buffer_new(); if (pubkey_buffer == NULL) { return -1; } tmpstring = ssh_string_from_char("ssh-rsa1"); if (tmpstring == NULL) { ssh_buffer_free(pubkey_buffer); return -1; } if (buffer_add_ssh_string(pubkey_buffer, tmpstring) < 0) { ssh_buffer_free(pubkey_buffer); ssh_string_free(tmpstring); return -1; } ssh_string_free(tmpstring); for (i = 2; i < 4; i++) { /* e, then n */ tmpbn = NULL; bignum_dec2bn(tokens[i], &tmpbn); if (tmpbn == NULL) { ssh_buffer_free(pubkey_buffer); return -1; } /* for some reason, make_bignum_string does not work because of the padding which it does --kv */ /* tmpstring = make_bignum_string(tmpbn); */ /* do it manually instead */ len = bignum_num_bytes(tmpbn); tmpstring = malloc(4 + len); if (tmpstring == NULL) { ssh_buffer_free(pubkey_buffer); bignum_free(tmpbn); return -1; } /* TODO: fix the hardcoding */ tmpstring->size = htonl(len); #ifdef HAVE_LIBGCRYPT bignum_bn2bin(tmpbn, len, tmpstring->string); #elif defined HAVE_LIBCRYPTO bignum_bn2bin(tmpbn, tmpstring->string); #endif bignum_free(tmpbn); if (buffer_add_ssh_string(pubkey_buffer, tmpstring) < 0) { ssh_buffer_free(pubkey_buffer); ssh_string_free(tmpstring); bignum_free(tmpbn); return -1; } ssh_string_free(tmpstring); } } else { /* ssh-dss or ssh-rsa */ pubkey_64 = tokens[2]; pubkey_buffer = base64_to_bin(pubkey_64); } if (pubkey_buffer == NULL) { ssh_set_error(session, SSH_FATAL, "Verifying that server is a known host: base64 error"); return -1; } if (buffer_get_rest_len(pubkey_buffer) != ssh_string_len(pubkey)) { ssh_buffer_free(pubkey_buffer); return 0; } /* now test that they are identical */ if (memcmp(buffer_get_rest(pubkey_buffer), pubkey->string, buffer_get_rest_len(pubkey_buffer)) != 0) { ssh_buffer_free(pubkey_buffer); return 0; } ssh_buffer_free(pubkey_buffer); return 1; }