Index: libgcrypt.c
===================================================================
--- libgcrypt.c	(revision 4)
+++ libgcrypt.c	(working copy)
@@ -572,4 +572,16 @@
     return ret;
 }
 
+int
+gen_publickey_from_private_keyfile(LIBSSH2_SESSION *session,
+                                   unsigned char **method,
+                                   unsigned long *method_len,
+                                   unsigned char **pubkeydata,
+                                   unsigned long *pubkeydata_len,
+                                   const char *privatekey,
+                                   const char *passphrase)
+{
+    return -1; /* not yet supported; interpreted by userauth.c to call libssh2_error */
+}
+
 #endif /* LIBSSH2_LIBGCRYPT */
Index: libgcrypt.h
===================================================================
--- libgcrypt.h	(revision 4)
+++ libgcrypt.h	(working copy)
@@ -207,3 +207,11 @@
 #define _libssh2_bn_bytes(bn) (gcry_mpi_get_nbits (bn) / 8 + ((gcry_mpi_get_nbits (bn) % 8 == 0) ? 0 : 1))
 #define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn)
 #define _libssh2_bn_free(bn) gcry_mpi_release(bn)
+
+int gen_publickey_from_private_keyfile(LIBSSH2_SESSION *session,
+                                       unsigned char **method,
+                                       unsigned long *method_len,
+                                       unsigned char **pubkeydata,
+                                       unsigned long *pubkeydata_len,
+                                       const char *privatekey,
+                                       const char *passphrase);
Index: openssl.c
===================================================================
--- openssl.c	(revision 4)
+++ openssl.c	(working copy)
@@ -514,5 +514,274 @@
     EVP_DigestUpdate(&ctx, message, len);
     EVP_DigestFinal(&ctx, out, NULL);
 }
+
+static unsigned char *
+write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes)
+{
+    unsigned char *p = buf;
+
+    /* Left space for bn size which will be written below. */
+    p += 4;
+
+    *p = 0;
+    BN_bn2bin(bn, p + 1);
+    if (!(*(p + 1) & 0x80)) {
+       memmove(p, p + 1, --bn_bytes);
+    }
+    _libssh2_htonu32(p - 4, bn_bytes);  /* Post write bn size. */
+
+    return p + bn_bytes;
+}
+
+static unsigned char *
+gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa,
+                       unsigned long *key_len)
+{
+    int            e_bytes, n_bytes;
+    unsigned long  len;
+    unsigned char* key;
+    unsigned char* p;
+
+    e_bytes = BN_num_bytes(rsa->e) + 1;
+    n_bytes = BN_num_bytes(rsa->n) + 1;
+
+    /* Key form is "ssh-rsa" + e + n. */
+    len = 4 + 7 + 4 + e_bytes + 4 + n_bytes;
+
+    key = LIBSSH2_ALLOC(session, len);
+    if (key == NULL) {
+       return NULL;
+    }
+
+    /* Process key encoding. */
+    p = key;
+
+    _libssh2_htonu32(p, 7);  /* Key type. */
+    p += 4;
+    memcpy(p, "ssh-rsa", 7);
+    p += 7;
+
+    p = write_bn(p, rsa->e, e_bytes);
+    p = write_bn(p, rsa->n, n_bytes);
+
+    *key_len = (unsigned long)(p - key);
+    return key;
+}
+
+static unsigned char *
+gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa,
+                       unsigned long *key_len)
+{
+    int            p_bytes, q_bytes, g_bytes, k_bytes;
+    unsigned long  len;
+    unsigned char* key;
+    unsigned char* p;
+
+    p_bytes = BN_num_bytes(dsa->p) + 1;
+    q_bytes = BN_num_bytes(dsa->q) + 1;
+    g_bytes = BN_num_bytes(dsa->g) + 1;
+    k_bytes = BN_num_bytes(dsa->pub_key) + 1;
+
+    /* Key form is "ssh-dss" + p + q + g + pub_key. */
+    len = 4 + 7 + 4 + p_bytes + 4 + q_bytes + 4 + g_bytes + 4 + k_bytes;
+
+    key = LIBSSH2_ALLOC(session, len);
+    if (key == NULL) {
+       return NULL;
+    }
+
+    /* Process key encoding. */
+    p = key;
+
+    _libssh2_htonu32(p, 7);  /* Key type. */
+    p += 4;
+    memcpy(p, "ssh-dss", 7);
+    p += 7;
+
+    p = write_bn(p, dsa->p, p_bytes);
+    p = write_bn(p, dsa->q, q_bytes);
+    p = write_bn(p, dsa->g, g_bytes);
+    p = write_bn(p, dsa->pub_key, k_bytes);
+
+    *key_len = (unsigned long)(p - key);
+    return key;
+}
+
+static int
+gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session,
+                           unsigned char **method,
+                           unsigned long *method_len,
+                           unsigned char **pubkeydata,
+                           unsigned long *pubkeydata_len,
+                           EVP_PKEY *pk)
+{
+    RSA*           rsa = NULL;
+    unsigned char* key;
+    unsigned char* method_buf = NULL;
+    unsigned long  key_len;
+
+    _libssh2_debug(session,
+                   LIBSSH2_TRACE_AUTH,
+                   "Computing public key from RSA private key envelop");
+
+    rsa = EVP_PKEY_get1_RSA(pk);
+    if (rsa == NULL) {
+        /* Assume memory allocation error... what else could it be ? */
+       goto __alloc_error;
+    }
+
+    method_buf = LIBSSH2_ALLOC(session, 7);  /* ssh-rsa. */
+    if (method_buf == NULL) {
+       goto __alloc_error;
+    }
+
+    key = gen_publickey_from_rsa(session, rsa, &key_len);
+    if (key == NULL) {
+       goto __alloc_error;
+    }
+    RSA_free(rsa);
+
+    memcpy(method_buf, "ssh-rsa", 7);
+    *method         = method_buf;
+    *method_len     = 7;
+    *pubkeydata     = key;
+    *pubkeydata_len = key_len;
+    return 0;
+
+__alloc_error:
+    if (rsa != NULL) {
+       RSA_free(rsa);
+    }
+    if (method_buf != NULL) {
+        LIBSSH2_FREE(session, method_buf);
+    }
+
+    _libssh2_error(session,
+                  LIBSSH2_ERROR_ALLOC,
+                  "Unable to allocate memory for private key data");
+    return -1;
+}
+
+static int
+gen_publickey_from_dsa_evp(LIBSSH2_SESSION *session,
+                           unsigned char **method,
+                           unsigned long *method_len,
+                           unsigned char **pubkeydata,
+                           unsigned long *pubkeydata_len,
+                           EVP_PKEY *pk)
+{
+    DSA*           dsa = NULL;
+    unsigned char* key;
+    unsigned char* method_buf = NULL;
+    unsigned long  key_len;
+
+    _libssh2_debug(session,
+                   LIBSSH2_TRACE_AUTH,
+                   "Computing public key from DSA private key envelop");
+
+    dsa = EVP_PKEY_get1_DSA(pk);
+    if (dsa == NULL) {
+        /* Assume memory allocation error... what else could it be ? */
+       goto __alloc_error;
+    }
+
+    method_buf = LIBSSH2_ALLOC(session, 7);  /* ssh-dss. */
+    if (method_buf == NULL) {
+       goto __alloc_error;
+    }
+
+    key = gen_publickey_from_dsa(session, dsa, &key_len);
+    if (key == NULL) {
+       goto __alloc_error;
+    }
+    DSA_free(dsa);
+
+    memcpy(method_buf, "ssh-dss", 7);
+    *method         = method_buf;
+    *method_len     = 7;
+    *pubkeydata     = key;
+    *pubkeydata_len = key_len;
+    return 0;
+
+__alloc_error:
+    if (dsa != NULL) {
+       DSA_free(dsa);
+    }
+    if (method_buf != NULL) {
+        LIBSSH2_FREE(session, method_buf);
+    }
+
+    _libssh2_error(session,
+                  LIBSSH2_ERROR_ALLOC,
+                  "Unable to allocate memory for private key data");
+    return -1;
+}
+
+int
+gen_publickey_from_private_keyfile(LIBSSH2_SESSION *session,
+                                   unsigned char **method,
+                                   unsigned long *method_len,
+                                   unsigned char **pubkeydata,
+                                   unsigned long *pubkeydata_len,
+                                   const char *privatekey,
+                                   const char *passphrase)
+{
+    int       st;
+    BIO*	  bp;
+    EVP_PKEY* pk;
+
+    _libssh2_debug(session,
+                   LIBSSH2_TRACE_AUTH,
+                   "Computing public key from private key file: %s",
+                   privatekey);
+
+    bp = BIO_new_file(privatekey, "r");
+    if (bp == NULL) {
+        _libssh2_error(session,
+                      LIBSSH2_ERROR_FILE,
+                      "Unable to open private key file");
+        return -1;
+    }
+    if (!EVP_get_cipherbyname("des")) {
+/* If this cipher isn't loaded it's a pretty good indication that none are.
+ * I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
+ * Someone buy me an OpenSSL manual and I'll read up on it.
+ */
+        OpenSSL_add_all_ciphers();
+    }
+	BIO_reset(bp);
+    pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void*)passphrase);
+    BIO_free(bp);
+
+    if (pk == NULL) {
+        _libssh2_error(session,
+                      LIBSSH2_ERROR_FILE,
+                      "Wrong passphrase or invalid/unrecognized "
+                      "private key file format");
+        return -1;
+    }
+
+    switch (pk->type) {
+    case EVP_PKEY_RSA :
+        st = gen_publickey_from_rsa_evp(
+                 session, method, method_len, pubkeydata, pubkeydata_len, pk);
+        break;
+
+    case EVP_PKEY_DSA :
+        st = gen_publickey_from_dsa_evp(
+                 session, method, method_len, pubkeydata, pubkeydata_len, pk);
+        break;
+
+    default :
+        st = -1;
+        _libssh2_error(session,
+                      LIBSSH2_ERROR_FILE,
+                      "Unsupported private key file format");
+        break;
+    }
+
+    EVP_PKEY_free(pk);
+    return st;
+}
 
 #endif /* !LIBSSH2_LIBGCRYPT */
Index: openssl.h
===================================================================
--- openssl.h	(revision 4)
+++ openssl.h	(working copy)
@@ -241,3 +241,11 @@
 const EVP_CIPHER *_libssh2_EVP_aes_128_ctr(void);
 const EVP_CIPHER *_libssh2_EVP_aes_192_ctr(void);
 const EVP_CIPHER *_libssh2_EVP_aes_256_ctr(void);
+
+int gen_publickey_from_private_keyfile(LIBSSH2_SESSION *session,
+                                       unsigned char **method,
+                                       unsigned long *method_len,
+                                       unsigned char **pubkeydata,
+                                       unsigned long *pubkeydata_len,
+                                       const char *privatekey,
+                                       const char *passphrase);
Index: userauth.c
===================================================================
--- userauth.c	(revision 4)
+++ userauth.c	(working copy)
@@ -655,13 +655,22 @@
         memset(&session->userauth_host_packet_requirev_state, 0,
                sizeof(session->userauth_host_packet_requirev_state));
 
-        rc = file_read_publickey(session, &session->userauth_host_method,
-                                 &session->userauth_host_method_len,
-                                 &pubkeydata, &pubkeydata_len,
-                                 publickey);
-        if(rc)
-            /* Note: file_read_publickey() calls _libssh2_error() */
-            return rc;
+        if (publickey != NULL) {
+            rc = file_read_publickey(session, &session->userauth_host_method,
+                                     &session->userauth_host_method_len,
+                                     &pubkeydata, &pubkeydata_len, publickey);
+            if(rc)
+                /* Note: file_read_publickey() calls _libssh2_error() */
+                return rc;
+        }
+        else {
+            /* Compute public key from private key. */
+            if (gen_publickey_from_private_keyfile(session, &session->userauth_host_method,
+                    &session->userauth_host_method_len,
+                    &pubkeydata, &pubkeydata_len, privatekey, passphrase))
+                return _libssh2_error(session, LIBSSH2_ERROR_FILE,
+                                     "Unable to extract public key from private key file");
+        }
 
         /*
          * 52 = packet_type(1) + username_len(4) + servicename_len(4) +
@@ -1221,11 +1230,21 @@
     privkey_file.passphrase = passphrase;
 
     if (session->userauth_pblc_state == libssh2_NB_state_idle) {
-        rc = file_read_publickey(session, &session->userauth_pblc_method,
-                                 &session->userauth_pblc_method_len,
-                                 &pubkeydata, &pubkeydata_len, publickey);
-        if(rc)
-            return rc;
+        if (publickey != NULL) {
+            rc = file_read_publickey(session, &session->userauth_pblc_method,
+                                     &session->userauth_pblc_method_len,
+                                     &pubkeydata, &pubkeydata_len,publickey);
+            if(rc)
+                return rc;
+        }
+        else {
+            /* Compute public key from private key. */
+            if (gen_publickey_from_private_keyfile(session, &session->userauth_pblc_method,
+                    &session->userauth_pblc_method_len,
+                    &pubkeydata, &pubkeydata_len, privatekey, passphrase))
+                return _libssh2_error(session, LIBSSH2_ERROR_FILE,
+                                     "Unable to extract public key from private key file");
+        }
     }
 
     rc = _libssh2_userauth_publickey(session, username, username_len,

