diff --git a/ChangeLog b/ChangeLog
index 7eaf8338041b6a5fdb834f7e40d81bf18db27921..d4fc6aaf2b5531d3080027b431893583cb2e6078 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+Sun Dec 20 20:11:02 1998    <nisse@puck>
+
+	* server.c (do_line): Accept client version 1.99, if
+	DATAFELLOWS_SSH2_GREETING_WORKAROUND is defined.
+
+	* randomness.c (make_poor_random): Allow NULL init string. Use pid
+	for seeding.
+	(make_device_random): New function.
+	(make_reasonably_random): New function.
+
+	* bignum.c (bignum_write): New function.
+	(bignum_random_size): New function.
+	(bignum_small_factor): New function.
+	(bignum_next_prime): New function.
+
+	* Makefile.am.in (noinst_LIBRARIES): Collect most object files
+	into liblsh.a.
+
 Fri Dec 18 01:53:22 1998    <nisse@puck>
 
 	* server.c (do_eof): Consider closing (if CHANNEL_SENT_EOF and
diff --git a/src/.cvsignore b/src/.cvsignore
index 1c17114eeebecc11e63f4ee2f6dfc96469046d73..ade86d1abe7e4ed99a840db6f667ab7b77753148 100644
--- a/src/.cvsignore
+++ b/src/.cvsignore
@@ -17,6 +17,9 @@ config.status
 configure
 configure.scan
 lsh
+lsh_keygen
 lshd
+prime_table
+prime_table.h
 stamp-h
 stamp-h.in
diff --git a/src/.gitignore b/src/.gitignore
index 3b8e6d02509174ce35106925baebeb3aab91ac06..7abceee308380c04d4114be447bf1ad84ebea0e6 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -17,6 +17,9 @@
 /configure
 /configure.scan
 /lsh
+/lsh_keygen
 /lshd
+/prime_table
+/prime_table.h
 /stamp-h
 /stamp-h.in
diff --git a/src/lsh.c b/src/lsh.c
index c0ee03e11a333bab18e3bb086a561bb56f71101c..bcff3b3f42d9971dc9547ed6ef9d0adafed1e20b 100644
--- a/src/lsh.c
+++ b/src/lsh.c
@@ -102,7 +102,6 @@ int main(int argc, char **argv)
 
   NEW(io_backend, backend);
 
-  struct lsh_string *random_seed;
   struct randomness *r;
   struct diffie_hellman_method *dh;
   struct keyexchange_algorithm *kex;
@@ -164,8 +163,7 @@ int main(int argc, char **argv)
 
   init_backend(backend);
   
-  random_seed = ssh_format("%z", "gazonk");
-  r = make_poor_random(&sha_algorithm, random_seed);
+  r = make_reasonably_random();
   dh = make_dh1(r);
   /* No randomness is needed for verifying signatures */
   lookup = make_fake_host_db(make_dss_algorithm(NULL)); 
@@ -229,8 +227,6 @@ int main(int argc, char **argv)
       return 1;
     }
   
-  lsh_string_free(random_seed);
-
   /* Exit code if no session is established */
   lsh_exit_code = 17;
   
diff --git a/src/lshd.c b/src/lshd.c
index 22d30dda40635751309943704a83219578164ab3..6ca54b5146c75cd0e3943b4109352393515906b1 100644
--- a/src/lshd.c
+++ b/src/lshd.c
@@ -131,7 +131,6 @@ int main(int argc, char **argv)
 
   struct reap *reaper;
   
-  struct lsh_string *random_seed;
   struct randomness *r;
   struct diffie_hellman_method *dh;
   struct keyexchange_algorithm *kex;
@@ -178,9 +177,8 @@ int main(int argc, char **argv)
 
   init_backend(backend);
   reaper = make_reaper();
-  random_seed = ssh_format("%z", "foobar");
 
-  r = make_poor_random(&sha_algorithm, random_seed);
+  r = make_reasonably_random();
   dh = make_dh1(r);
   init_host_key(r); /* Initializes public_key and secret_key */
   kex = make_dh_server(dh, public_key, secret_key);
diff --git a/src/sexp.h b/src/sexp.h
new file mode 100644
index 0000000000000000000000000000000000000000..f0bc9ac5f00f3c4b5603378c9fc104a6559de37e
--- /dev/null
+++ b/src/sexp.h
@@ -0,0 +1,112 @@
+/* sexp.h
+ *
+ * An implementation of Ron Rivest's S-expressions, used in spki.
+ *
+ * $Id$ */
+
+/* lsh, an implementation of the ssh protocol
+ *
+ * Copyright (C) 1998 Niels M�ller
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef LSH_SEXP_H_INCLUDED
+#define LSH_SEXP_H_INCLUDED
+
+#include "abstract_io.h"
+
+/* CLASS:
+   (class
+     (name sexp)
+     (vars
+       (output method int "int style" "struct abstract_write output")))
+*/
+
+/* CLASS:
+   (class
+     (name sexp_string)
+     (super sexp)
+     (vars
+       (display string)
+       (contents string)))
+*/
+
+/* CLASS:
+   (class
+     (name sexp_atom)
+     (super sexp)
+     (vars
+       (atom . int)))
+*/
+
+/* CLASS:
+   (class
+     (name "sexp_cons")
+     (super sexp)
+     (vars
+       (car object sexp)
+       (cdr object sex_cons)))
+*/
+
+/* Creating sexps */
+/* atom->sexp */
+struct sexp *sexp_a(int a);
+
+/* cstring->sexp */
+struct sexp *sexp_z(char *s);
+
+/* mpz->atom */
+struct sexp *sexp_n(mpz_t n);
+struct sexp *sexp_sn(mpz_t n);
+
+/* cons */
+struct sexp *sexp_c(struct sexp *car, struct sexp_cons *cdr);
+
+/* list */
+struct sexp *sexp_l(unsigned n, ...);
+
+/* Extracting information from sexp. These functions accept NULL
+ * arguments, and return NULL if the conversion is not possible */
+
+int *sexp_consp(struct sexp *e);
+
+/* For lists */
+struct sexp *sexp_car(struct sexp *e);
+struct sexp *sexp_cdr(struct sexp *e);
+
+int sexp *sexp_null_cdr(struct sexp *e);
+
+struct lsh_string *sexp_contents(struct sexp *e);
+struct lsh_string *sexp_display(struct sexp *e);
+int sexp_atom(struct sexp *e);
+int sexp_bignum_u(struct sexp *e, mpz_t n);
+int sexp_bignum_s(struct sexp *e, mpz_t n);
+
+
+/* Parsing sexp */
+
+/* CLASS:
+   (class
+     (name sexp_handler)
+     (vars
+       (method int "struct sexp *e")))
+*/
+
+struct read_handler make_read_sexp(struct sexp_handler *h)
+
+#endif /* LSH_SEXP_H_INCLUDED */
+
+