Matthias Urlichs wrote:
> Hello,
>
> I need to sign files remotely. They're moderately large, so
> transmitting them back to my firewalled-off laptop (I'm usually
> behind a slow line), where the secret key lives, isn't a good idea.
>
> Ideas?

I'currenty working on a patch for gnupg that enables remote signatures.

see attachment for an ALPHA version (working but unsafe code)

Thomas

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
NotDashEscaped: You need GnuPG to verify this message


Remote Signatures for GnuPG

WARNING: DON'T USE THE PATCH ON PRODUCTION SYSTEMS
(lot's of ugly, unsafe code and missing guardians)

Apply the patch to the gnupg-1.4.2 sources and follow the usual instructions to 
build gnupg

--print-seed algo file
======================

algo: MD5 SHA1 RIPEMD160 (SHA256 SHA384 SHA512)
file: the file file that should be signed

sample: gpg --print-seed SHA1 ./NEWS
> algo=SHA1&sig_type=0&block=1119&state=%DE%7C%02Qtt%E1Y%98%C5%BA%12e
> %3F%9Erl%BB%ED%F6&length=432&buffer=%20MERCHANTABILITY%20or%20FITNE
> SS%20FOR%20A%20PARTICULAR%20PURPOSE%2E%0A

--sign-seed seed
================

seed: a seed generated by --print-seed

sample: gpg  --sign-seed algo=SHA1&sig_[...]2E%0A
> -----BEGIN PGP SIGNATURE-----
> 
> iQIVAwUAQ/jWkjOg8GEoPYU1AQI6kBAAsPYDJfIbSjMyovbWqNNiF2ueD6y9K66o
> By0BDlwt4A5VpmZU5wWcqnIAcKcc6OcAwrt+BDyjdnDHF/0MB8li64x3/LIrV4Vd
> V0VsAFV8SBnBmG0KVFNHyHhr/KI4mSTF7RyH5K+Xhw5B0jauKcH1JZEONPziWzOn
> yIVHCEuEKR7SImE3b+pIwdK1V89NAqEtnMvsN9fGosXTDraCZVAf702XbkANown+
> nw8uGxd8FpQYB0tmA6KOBYlj0XnaL1p5iFP6JnHS2wNJxGtZJEWl3kywsJ0dj4wg
> nmN5okMHvkJ/NjYXyk2w5RAtbM2kSL+bfyLk4oV4s4q/jfRjTL4y/qrmBu5R9+Sf
> CAWdhph1WM1Z1Vnujgo9tsBKR80yL/1r0C+kDylsGbUYBQ23DLdYTQILIKovSjab
> xePA1Q11PHPPQvwtwxMdDU+1LNHu/lcjzxkKoR3Xcq6+jdTZxrvXMAm2vmXFXtcO
> ECr2o9ckBFAqHjeQggdsAXTG5d2ZPzcpP42UECRMD3Eg0JCLbxq5yxTCTe5MRRaj
> xyuq7xnlXo3LErmZGrPdm9w4xMcHvVFXuHNRt7/FWyGUxrrpy0kFnyHerIKKw/bn
> 4oZQI2EVO8MqFb9QMCON5QsjAiQsYyC3e39g1IpE3/d3vXijaidRSy+vPRMhSiVQ
> WiUe2+IQqpY=
> =1MFy
> -----END PGP SIGNATURE-----


License: GPL
Copyright: 2006 Thomas Kuehne <[EMAIL PROTECTED]> 

Thomas


diff -urBbN gnupg-1.4.2/cipher/algorithms.h 
gnupg-1.4.2-md-seed-1/cipher/algorithms.h
--- gnupg-1.4.2/cipher/algorithms.h     2005-05-31 08:29:54.000000000 +0200
+++ gnupg-1.4.2-md-seed-1/cipher/algorithms.h   2006-02-18 18:56:37.000000000 
+0100
@@ -21,6 +21,10 @@
 #ifndef GNUPG_ALGORITHMS_H
 #define GNUPG_ALGORITHMS_H 1
 
+#ifdef ENABLE_MD_SEED
+#include "md_seed.h"
+#endif
+
 const char *dynload_enum_module_names (int seq);
 
 const char *
@@ -30,6 +34,10 @@
               void (**r_write)( void *c, byte *buf, size_t nbytes ),
               void (**r_final)( void *c ),
               byte *(**r_read)( void *c )
+#ifdef ENABLE_MD_SEED
+              , void (**r_read_seed)( void *c, MD_SEED seed),
+              void (**r_write_seed)( void *c, MD_SEED seed)
+#endif
               );
 
 
@@ -40,6 +48,10 @@
                  void (**r_write)( void *c, byte *buf, size_t nbytes ),
                  void (**r_final)( void *c ),
                  byte *(**r_read)( void *c )
+#ifdef ENABLE_MD_SEED
+              , void (**r_read_seed)( void *c, MD_SEED seed),
+              void (**r_write_seed)( void *c, MD_SEED seed)
+#endif
                  );
 
 const char *
@@ -49,6 +61,10 @@
               void (**r_write)( void *c, byte *buf, size_t nbytes ),
               void (**r_final)( void *c ),
               byte *(**r_read)( void *c )
+#ifdef ENABLE_MD_SEED
+              , void (**r_read_seed)( void *c, MD_SEED seed),
+              void (**r_write_seed)( void *c, MD_SEED seed)
+#endif
                );
 
 const char *
@@ -58,6 +74,10 @@
                 void (**r_write)( void *c, byte *buf, size_t nbytes ),
                 void (**r_final)( void *c ),
                 byte *(**r_read)( void *c )
+#ifdef ENABLE_MD_SEED
+              , void (**r_read_seed)( void *c, MD_SEED seed),
+              void (**r_write_seed)( void *c, MD_SEED seed)
+#endif
                 );
 
 const char *
@@ -67,6 +87,10 @@
                 void (**r_write)( void *c, byte *buf, size_t nbytes ),
                 void (**r_final)( void *c ),
                 byte *(**r_read)( void *c )
+#ifdef ENABLE_MD_SEED
+              , void (**r_read_seed)( void *c, MD_SEED seed),
+              void (**r_write_seed)( void *c, MD_SEED seed)
+#endif
                 );
 
 const char *
@@ -76,6 +100,10 @@
                 void (**r_write)( void *c, byte *buf, size_t nbytes ),
                 void (**r_final)( void *c ),
                 byte *(**r_read)( void *c )
+#ifdef ENABLE_MD_SEED
+              , void (**r_read_seed)( void *c, MD_SEED seed),
+              void (**r_write_seed)( void *c, MD_SEED seed)
+#endif
                 );
 
 const char *
diff -urBbN gnupg-1.4.2/cipher/md.c gnupg-1.4.2-md-seed-1/cipher/md.c
--- gnupg-1.4.2/cipher/md.c     2005-05-31 08:29:54.000000000 +0200
+++ gnupg-1.4.2-md-seed-1/cipher/md.c   2006-02-19 17:57:54.000000000 +0100
@@ -31,6 +31,10 @@
 #include "algorithms.h"
 #include "i18n.h"
 
+#ifdef ENABLE_MD_SEED
+#include "md_seed.h"
+#endif
+
 /****************
  * This structure is used for the list of available algorithms
  * and for the list of algorithms in MD_HANDLE.
@@ -46,6 +50,10 @@
     void (*write)( void *c, byte *buf, size_t nbytes );
     void (*final)( void *c );
     byte *(*read)( void *c );
+#ifdef ENABLE_MD_SEED
+    void (*read_seed)( void *c , MD_SEED seed);
+    void (*write_seed)( void *c , MD_SEED seed);
+#endif
     size_t contextsize; /* allocate this amount of context */
     PROPERLY_ALIGNED_TYPE context;
 };
@@ -58,7 +66,12 @@
               const char *(*get_info)( int, size_t*,byte**, int*, int*,
                                       void (**)(void*),
                                       void (**)(void*,byte*,size_t),
-                                      void (**)(void*),byte *(**)(void*)))
+                                      void (**)(void*),byte *(**)(void*)
+#ifdef ENABLE_MD_SEED
+                                      ,void (**)(void*, MD_SEED),
+                                      void (**)(void*, MD_SEED)
+#endif  
+                                      ))
 {
   struct md_digest_list_s *r;
 
@@ -66,7 +79,13 @@
   r->algo = algo;
   r->name = (*get_info)( algo, &r->contextsize,
                          &r->asnoid, &r->asnlen, &r->mdlen,
-                         &r->init, &r->write, &r->final, &r->read );
+                         &r->init, &r->write, &r->final, &r->read
+#ifdef ENABLE_MD_SEED
+                        ,&r->read_seed, &r->write_seed
+#endif                  
+                        );
+  
+
   if (!r->name ) 
     {
       m_free(r);
@@ -526,3 +547,39 @@
     }
 #endif
 }
+
+#ifdef ENABLE_MD_SEED
+void
+md_write_seed( MD_HANDLE a, MD_SEED seed)
+{
+    struct md_digest_list_s *r;
+
+    r=a->list;
+    if(! r)
+           BUG();
+
+
+       (*r->write_seed)( &r->context.c, seed);
+
+
+}
+
+MD_HANDLE
+md_read_seed( MD_SEED seed, int secure )
+{
+       MD_HANDLE md = md_open( seed->algo, secure );
+       if( ! md_get_algo( md ) )
+               BUG();
+
+       struct md_digest_list_s *r;
+               r=md->list;
+
+       (*r->read_seed)( &r->context.c, seed);
+
+       return md;
+}
+
+void debug_md (MD_HANDLE a){
+       sha1_debug(a->list->context.c);
+}
+#endif /* ENABLE_MD_SEED */
diff -urBbN gnupg-1.4.2/cipher/md5.c gnupg-1.4.2-md-seed-1/cipher/md5.c
--- gnupg-1.4.2/cipher/md5.c    2005-05-31 08:29:54.000000000 +0200
+++ gnupg-1.4.2-md-seed-1/cipher/md5.c  2006-02-19 18:19:52.000000000 +0100
@@ -331,6 +331,77 @@
     return hd->buf;
 }
 
+#if ENABLE_MD_SEED
+#include "md_seed.h"
+#include "i18n.h"
+
+void
+md5_write_seed( MD5_CONTEXT *hd, MD_SEED seed )
+{
+       u32 t;
+
+       md5_write(hd, NULL, 0); /* flush */;
+        
+       seed->algo = DIGEST_ALGO_MD5;
+
+       seed->buffer = m_alloc(hd->count); 
+       memcpy(seed->buffer, hd->buf, hd->count);
+       seed->buffer_length = hd->count * 8; 
+
+       seed->block_count = hd->nblocks;
+
+       seed->state_length = 4 * sizeof(u32);
+       seed->state = m_alloc(seed->state_length);
+
+       /* slow but struct alignment save */
+       t = hton_32(hd->A);
+       memcpy(seed->state + 0 * sizeof(u32), &t, sizeof(u32)); 
+       t = hton_32(hd->B);
+       memcpy(seed->state + 1 * sizeof(u32), &t, sizeof(u32)); 
+       t = hton_32(hd->C);
+       memcpy(seed->state + 2 * sizeof(u32), &t, sizeof(u32)); 
+       t = hton_32(hd->D);
+       memcpy(seed->state + 3 * sizeof(u32), &t, sizeof(u32)); 
+}
+
+void
+md5_read_seed( MD5_CONTEXT *hd, MD_SEED seed )
+{
+       u32 len = seed->buffer_length;
+
+       if( seed->algo != DIGEST_ALGO_MD5)
+               BUG();
+
+       if(len % 8)
+               g10_log_error("%s\n", _("this MD5 implementation doesn't 
support non-byte aligned buffers"));
+       else
+               len = len / 8;
+
+       if(sizeof(hd->buf) < len)
+               g10_log_error("%s\n", _("excessive length of seed's buffer"));
+
+       if(4 * sizeof(u32) != seed->state_length)
+               g10_log_error("%s\n", _("unexpected length of state data"));
+
+       if( (u64)((u32) seed->block_count) != seed->block_count )
+               g10_log_error("%s\n", _("excessive block count"));
+
+       if( log_get_errorcount(0) )
+               return;
+
+       memcpy(hd->buf, seed->buffer, len);
+       hd->count = len;
+
+       hd->nblocks = seed->block_count;
+
+       /* slow but struct alignment save */
+       hd->A = hton_32(*((u32*) (seed->state + 0 * sizeof(u32))));
+       hd->B = hton_32(*((u32*) (seed->state + 1 * sizeof(u32))));
+       hd->C = hton_32(*((u32*) (seed->state + 2 * sizeof(u32))));
+       hd->D = hton_32(*((u32*) (seed->state + 3 * sizeof(u32))));
+}
+#endif /* ENABLE_MD_SEED */
+
 /****************
  * Return some information about the algorithm.  We need algo here to
  * distinguish different flavors of the algorithm.
@@ -344,6 +415,10 @@
               void (**r_write)( void *c, byte *buf, size_t nbytes ),
               void (**r_final)( void *c ),
               byte *(**r_read)( void *c )
+#ifdef ENABLE_MD_SEED
+              , void (**r_read_seed)( void *c, MD_SEED seed),
+              void (**r_write_seed)( void *c, MD_SEED seed)
+#endif
             )
 {
     static byte asn[18] = /* Object ID is 1.2.840.113549.2.5 */
@@ -362,5 +437,10 @@
     *(void  (**)(MD5_CONTEXT *))r_final               = md5_final;
     *(byte *(**)(MD5_CONTEXT *))r_read                = md5_read;
 
+#ifdef ENABLE_MD_SEED
+    *(void  (**)(MD5_CONTEXT *, MD_SEED))r_read_seed  = md5_read_seed;
+    *(void  (**)(MD5_CONTEXT *, MD_SEED))r_write_seed  = md5_write_seed;
+#endif
     return "MD5";
 }
+
diff -urBbN gnupg-1.4.2/cipher/rmd160.c gnupg-1.4.2-md-seed-1/cipher/rmd160.c
--- gnupg-1.4.2/cipher/rmd160.c 2005-05-31 08:29:54.000000000 +0200
+++ gnupg-1.4.2-md-seed-1/cipher/rmd160.c       2006-02-19 18:13:14.000000000 
+0100
@@ -552,6 +552,79 @@
     memcpy( outbuf, hd.buf, 20 );
 }
 
+#if ENABLE_MD_SEED
+#include "md_seed.h"
+#include "i18n.h"
+
+static void
+rmd160_write_seed( RMD160_CONTEXT *hd, MD_SEED seed )
+{
+       u32 t;
+
+       rmd160_write(hd, NULL, 0); /* flush */;
+        
+       seed->algo = DIGEST_ALGO_RMD160;
+
+       seed->buffer = m_alloc(hd->count); 
+       memcpy(seed->buffer, hd->buf, hd->count);
+       seed->buffer_length = hd->count * 8; 
+
+       seed->block_count = hd->nblocks;
+
+       seed->state_length = 5 * sizeof(u32);
+       seed->state = m_alloc(seed->state_length);
+
+       /* slow but struct alignment save */
+       t = hton_32(hd->h0);
+       memcpy(seed->state, &t, 4); 
+       t = hton_32(hd->h1);
+       memcpy(seed->state+4, &t, 4); 
+       t = hton_32(hd->h2);
+       memcpy(seed->state+8, &t, 4); 
+       t = hton_32(hd->h3);
+       memcpy(seed->state+12, &t, 4); 
+       t = hton_32(hd->h4);
+       memcpy(seed->state+16, &t, 4); 
+}
+
+static void
+rmd160_read_seed( RMD160_CONTEXT *hd, const MD_SEED seed )
+{
+       u32 len = seed->buffer_length;
+
+       if( seed->algo != DIGEST_ALGO_RMD160)
+               BUG();
+
+       if(len % 8)
+               g10_log_error("%s\n", _("this RIPEMD160 implementation doesn't 
support non-byte aligned buffers"));
+       else
+               len = len / 8;
+
+       if(sizeof(hd->buf) < len)
+               g10_log_error("%s\n", _("excessive length of seed's buffer"));
+
+       if(5 * sizeof(u32) != seed->state_length)
+               g10_log_error("%s\n", _("unexpected length of state data"));
+
+       if( (u64)((u32) seed->block_count) != seed->block_count )
+               g10_log_error("%s\n", _("excessive block count"));
+
+       if( log_get_errorcount(0) )
+               return;
+
+       memcpy(hd->buf, seed->buffer, len);
+       hd->count = len;
+
+       hd->nblocks = seed->block_count;
+
+       /* slow but struct alignment save */
+       hd->h0 = hton_32(*((u32*) (seed->state + 0 * sizeof(u32))));
+       hd->h1 = hton_32(*((u32*) (seed->state + 1 * sizeof(u32))));
+       hd->h2 = hton_32(*((u32*) (seed->state + 2 * sizeof(u32))));
+       hd->h3 = hton_32(*((u32*) (seed->state + 3 * sizeof(u32))));
+       hd->h4 = hton_32(*((u32*) (seed->state + 4 * sizeof(u32))));
+}
+#endif
 
 /****************
  * Return some information about the algorithm.  We need algo here to
@@ -566,6 +639,10 @@
               void (**r_write)( void *c, byte *buf, size_t nbytes ),
               void (**r_final)( void *c ),
               byte *(**r_read)( void *c )
+#ifdef ENABLE_MD_SEED
+              , void (**r_read_seed)( void *c, MD_SEED seed),
+              void (**r_write_seed)( void *c, MD_SEED seed)
+#endif
             )
 {
     static byte asn[15] = /* Object ID is 1.3.36.3.2.1 */
@@ -584,5 +661,11 @@
     *(void  (**)(RMD160_CONTEXT *))r_final               = rmd160_final;
     *(byte *(**)(RMD160_CONTEXT *))r_read                = rmd160_read;
 
+#ifdef ENABLE_MD_SEED
+    *(void  (**)(RMD160_CONTEXT *, MD_SEED ))r_read_seed  = rmd160_read_seed;
+    *(void  (**)(RMD160_CONTEXT *, MD_SEED ))r_write_seed = rmd160_write_seed;
+#endif
+
     return "RIPEMD160";
 }
+
diff -urBbN gnupg-1.4.2/cipher/sha1.c gnupg-1.4.2-md-seed-1/cipher/sha1.c
--- gnupg-1.4.2/cipher/sha1.c   2005-05-31 08:29:54.000000000 +0200
+++ gnupg-1.4.2-md-seed-1/cipher/sha1.c 2006-02-19 18:17:30.000000000 +0100
@@ -62,6 +61,15 @@
 }
 
 
+void sha1_debug(SHA1_CONTEXT* hd){
+       fprintf(stderr, "h0: %i\nh1: %i\nh2: %i\nh3: %i\nh4: %i\nnblocks: 
%i\ncount: %i\n",
+                       hd->h0, hd->h1, hd->h2, hd->h3, hd->h4, hd->nblocks, 
hd->count);
+       int i;
+       for(i = 0; i < sizeof(hd->buf); i++){
+               fprintf(stderr, "[%i] %2X %c\n", i, hd->buf[i], hd->buf[i]);
+       }
+}
+
 void
 sha1_init( SHA1_CONTEXT *hd )
 {
@@ -325,6 +333,79 @@
     return hd->buf;
 }
 
+#if ENABLE_MD_SEED
+#include "md_seed.h"
+#include "i18n.h"
+
+static void
+sha1_write_seed( SHA1_CONTEXT *hd, MD_SEED seed )
+{
+       u32 t;
+       
+       seed->algo = DIGEST_ALGO_SHA1;
+
+       seed->buffer = m_alloc(hd->count); 
+       memcpy(seed->buffer, hd->buf, hd->count);
+       seed->buffer_length = hd->count * 8; 
+
+       seed->block_count = hd->nblocks;
+
+       seed->state_length = 5 * sizeof(u32);
+       seed->state = m_alloc(seed->state_length);
+
+
+       /* slow but struct alignment save */
+       t = hton_32(hd->h0);
+       memcpy(seed->state + 0 * sizeof(u32), &t, sizeof(u32)); 
+       t = hton_32(hd->h1);
+       memcpy(seed->state + 1 * sizeof(u32), &t, sizeof(u32)); 
+       t = hton_32(hd->h2);
+       memcpy(seed->state + 2 * sizeof(u32), &t, sizeof(u32)); 
+       t = hton_32(hd->h3);
+       memcpy(seed->state + 3 * sizeof(u32), &t, sizeof(u32)); 
+       t = hton_32(hd->h4);
+       memcpy(seed->state + 4 * sizeof(u32), &t, sizeof(u32)); 
+}
+
+static void
+sha1_read_seed( SHA1_CONTEXT *hd, MD_SEED seed )
+{
+       u32 len = seed->buffer_length;
+
+       if( seed->algo != DIGEST_ALGO_SHA1)
+               BUG();
+
+       if(len % 8)
+               g10_log_error("%s\n", _("this SHA1 implementation doesn't 
support non-byte aligned buffers"));
+       else
+               len = len / 8;
+
+       if(sizeof(hd->buf) < len)
+               g10_log_error("%s\n", _("excessive length of seed's buffer"));
+
+       if(5 * sizeof(u32) != seed->state_length)
+               g10_log_error("%s\n", _("unexpected length of state data"));
+
+       if( (u64)((u32) seed->block_count) != seed->block_count )
+               g10_log_error("%s\n", _("excessive block count"));
+
+       if( log_get_errorcount(0) )
+               return;
+
+       memcpy(hd->buf, seed->buffer, len);
+       hd->count = len;
+
+       hd->nblocks = seed->block_count;
+
+       /* slow but struct alignment save */
+       hd->h0 = hton_32(*((u32*) (seed->state + 0 * sizeof(u32))));
+       hd->h1 = hton_32(*((u32*) (seed->state + 1 * sizeof(u32))));
+       hd->h2 = hton_32(*((u32*) (seed->state + 2 * sizeof(u32))));
+       hd->h3 = hton_32(*((u32*) (seed->state + 3 * sizeof(u32))));
+       hd->h4 = hton_32(*((u32*) (seed->state + 4 * sizeof(u32))));
+}
+#endif
+
 /****************
  * Return some information about the algorithm.  We need algo here to
  * distinguish different flavors of the algorithm.
@@ -338,6 +419,10 @@
               void (**r_write)( void *c, byte *buf, size_t nbytes ),
               void (**r_final)( void *c ),
               byte *(**r_read)( void *c )
+#ifdef ENABLE_MD_SEED
+              , void (**r_read_seed)( void *c, MD_SEED seed),
+              void (**r_write_seed)( void *c, MD_SEED seed)
+#endif
             )
 {
     static byte asn[15] = /* Object ID is 1.3.14.3.2.26 */
@@ -355,5 +440,10 @@
     *(void  (**)(SHA1_CONTEXT *))r_final               = sha1_final;
     *(byte *(**)(SHA1_CONTEXT *))r_read                = sha1_read;
 
+#ifdef ENABLE_MD_SEED
+    *(void (**)(SHA1_CONTEXT *, MD_SEED))r_write_seed = sha1_write_seed;
+    *(void (**)(SHA1_CONTEXT *, MD_SEED))r_read_seed = sha1_read_seed;
+#endif
     return "SHA1";
 }
+
diff -urBbN gnupg-1.4.2/cipher/sha256.c gnupg-1.4.2-md-seed-1/cipher/sha256.c
--- gnupg-1.4.2/cipher/sha256.c 2005-05-31 08:29:54.000000000 +0200
+++ gnupg-1.4.2-md-seed-1/cipher/sha256.c       2006-02-19 18:21:54.000000000 
+0100
@@ -280,6 +280,83 @@
     return hd->buf;
 }
 
+#if ENABLE_MD_SEED
+#include "md_seed.h"
+#include "i18n.h"
+
+static void
+sha256_write_seed( SHA256_CONTEXT *hd, MD_SEED seed )
+{
+       u32 t;
+        
+       seed->algo = DIGEST_ALGO_SHA256;
+
+       seed->buffer = m_alloc(hd->count); 
+       memcpy(seed->buffer, hd->buf, hd->count);
+       seed->buffer_length = hd->count * 8; 
+
+       seed->block_count = hd->nblocks;
+
+       seed->state_length = 8 * sizeof(u32);
+       seed->state = m_alloc(seed->state_length);
+
+       /* slow but struct alignment save */
+       t = hton_32(hd->h0);
+       memcpy(seed->state + (0 * sizeof(u32)), &t, sizeof(u32)); 
+       t = hton_32(hd->h1);
+       memcpy(seed->state + (1 * sizeof(u32)), &t, sizeof(u32)); 
+       t = hton_32(hd->h2);
+       memcpy(seed->state + (2 * sizeof(u32)), &t, sizeof(u32)); 
+       t = hton_32(hd->h3);
+       memcpy(seed->state + (3 * sizeof(u32)), &t, sizeof(u32)); 
+       t = hton_32(hd->h4);
+       memcpy(seed->state + (4 * sizeof(u32)), &t, sizeof(u32)); 
+       t = hton_32(hd->h5);
+       memcpy(seed->state + (5 * sizeof(u32)), &t, sizeof(u32)); 
+       t = hton_32(hd->h6);
+       memcpy(seed->state + (6 * sizeof(u32)), &t, sizeof(u32)); 
+       t = hton_32(hd->h7);
+       memcpy(seed->state + (7 * sizeof(u32)), &t, sizeof(u32)); 
+}
+
+static void
+sha256_read_seed( SHA256_CONTEXT *hd, MD_SEED seed )
+{
+       u32 len = seed->buffer_length;
+
+       if( seed->algo != DIGEST_ALGO_SHA256 )
+               BUG();
+
+       if( len % 8 )
+               g10_log_error("%s\n", _("this SHA256 implementation doesn't 
support non-byte aligned buffers"));
+       else
+               len = len / 8;
+
+       if( sizeof(hd->buf) < len )
+               g10_log_error("%s\n", _("excessive length of seed's buffer"));
+
+       if( 8 * sizeof(u32) != seed->state_length )
+               g10_log_error("%s\n", _("unexpected length of seed's state 
data"));
+
+       if( log_get_errorcount(0) )
+               return;
+
+       memcpy( hd->buf, seed->buffer, len );
+       hd->count = len;
+
+       hd->nblocks = seed->block_count;
+
+       hd->h0 = hton_32(*((u32*) (seed->state + 0 * sizeof(u32))));
+       hd->h1 = hton_32(*((u32*) (seed->state + 1 * sizeof(u32))));
+       hd->h2 = hton_32(*((u32*) (seed->state + 2 * sizeof(u32))));
+       hd->h3 = hton_32(*((u32*) (seed->state + 3 * sizeof(u32))));
+       hd->h4 = hton_32(*((u32*) (seed->state + 4 * sizeof(u32))));
+       hd->h5 = hton_32(*((u32*) (seed->state + 5 * sizeof(u32))));
+       hd->h6 = hton_32(*((u32*) (seed->state + 6 * sizeof(u32))));
+       hd->h7 = hton_32(*((u32*) (seed->state + 7 * sizeof(u32))));
+}
+#endif
+
 /****************
  * Return some information about the algorithm.  We need algo here to
  * distinguish different flavors of the algorithm.
@@ -293,6 +370,10 @@
                 void (**r_write)( void *c, byte *buf, size_t nbytes ),
                 void (**r_final)( void *c ),
                 byte *(**r_read)( void *c )
+#ifdef ENABLE_MD_SEED
+              , void (**r_read_seed)( void *c, MD_SEED seed),
+              void (**r_write_seed)( void *c, MD_SEED seed)
+#endif
                 )
 {
     static byte asn[] = /* Object ID is 2.16.840.1.101.3.4.2.1 */
@@ -314,5 +395,11 @@
     *(void  (**)(SHA256_CONTEXT *))r_final               = sha256_final;
     *(byte *(**)(SHA256_CONTEXT *))r_read                = sha256_read;
 
+#ifdef ENABLE_MD_SEED
+    *(void  (**)(SHA256_CONTEXT *, MD_SEED ))r_read_seed  = sha256_read_seed;
+    *(void  (**)(SHA256_CONTEXT *, MD_SEED ))r_write_seed = sha256_write_seed;
+#endif
+    
     return "SHA256";
 }
+
diff -urBbN gnupg-1.4.2/cipher/sha512.c gnupg-1.4.2-md-seed-1/cipher/sha512.c
--- gnupg-1.4.2/cipher/sha512.c 2005-05-31 08:29:54.000000000 +0200
+++ gnupg-1.4.2-md-seed-1/cipher/sha512.c       2006-02-19 19:17:57.000000000 
+0100
@@ -359,6 +359,110 @@
   return hd->buf;
 }
 
+#ifdef ENABLE_MD_SEED
+#include "md_seed.h"
+#include "i18n.h"
+
+static void
+sha512_write_seed( SHA512_CONTEXT *hd, MD_SEED seed )
+{
+       u64 t;
+
+       sha512_write(hd, NULL, 0); /* flush */;
+        
+       seed->algo = DIGEST_ALGO_SHA512;
+
+       seed->buffer = m_alloc(hd->count); 
+       memcpy(seed->buffer, hd->buf, hd->count);
+       seed->buffer_length = hd->count * 8; 
+
+       seed->block_count = hd->nblocks;
+
+       seed->state_length = 8 * sizeof(u64);
+       seed->state = m_alloc(seed->state_length);
+
+       t = hton_64(hd->h0);
+       memcpy(seed->state + (0 * sizeof(u64)), &t, sizeof(u64)); 
+       t = hton_64(hd->h1);
+       memcpy(seed->state + (1 * sizeof(u64)), &t, sizeof(u64)); 
+       t = hton_64(hd->h2);
+       memcpy(seed->state + (2 * sizeof(u64)), &t, sizeof(u64)); 
+       t = hton_64(hd->h3);
+       memcpy(seed->state + (3 * sizeof(u64)), &t, sizeof(u64)); 
+       t = hton_64(hd->h4);
+       memcpy(seed->state + (4 * sizeof(u64)), &t, sizeof(u64)); 
+       t = hton_64(hd->h5);
+       memcpy(seed->state + (5 * sizeof(u64)), &t, sizeof(u64)); 
+       t = hton_64(hd->h6);
+       memcpy(seed->state + (6 * sizeof(u64)), &t, sizeof(u64)); 
+       t = hton_64(hd->h7);
+       memcpy(seed->state + (7 * sizeof(u64)), &t, sizeof(u64)); 
+}
+
+static void
+sha512_read_Xseed( SHA512_CONTEXT *hd, MD_SEED seed )
+{
+       u32 len = seed->buffer_length;
+
+       if( (seed->algo != DIGEST_ALGO_SHA512) && (seed->algo != 
DIGEST_ALGO_SHA384) )
+               BUG();
+
+       if( len % 8 )
+               g10_log_error("%s\n", _("this SHA512/SHA384 implementation 
doesn't support non-byte aligned buffers"));
+       else
+               len = len / 8;
+
+       if( sizeof(hd->buf) < len )
+               g10_log_error("%s\n", _("excessive length of seed's buffer"));
+
+       if( 8 * sizeof(u64) != seed->state_length )
+               g10_log_error("%s\n", _("unexpected length of seed's state 
data"));
+
+       if( log_get_errorcount(0) )
+               return;
+
+       memcpy( hd->buf, seed->buffer, len );
+       hd->count = len;
+
+       hd->nblocks = seed->block_count;
+
+       hd->h0 = hton_64(*((u64*) (seed->state + 0 * sizeof(u64))));
+       hd->h1 = hton_64(*((u64*) (seed->state + 1 * sizeof(u64))));
+       hd->h2 = hton_64(*((u64*) (seed->state + 2 * sizeof(u64))));
+       hd->h3 = hton_64(*((u64*) (seed->state + 3 * sizeof(u64))));
+       hd->h4 = hton_64(*((u64*) (seed->state + 4 * sizeof(u64))));
+       hd->h5 = hton_64(*((u64*) (seed->state + 5 * sizeof(u64))));
+       hd->h6 = hton_64(*((u64*) (seed->state + 6 * sizeof(u64))));
+       hd->h7 = hton_64(*((u64*) (seed->state + 7 * sizeof(u64))));
+}
+
+static void
+sha512_read_seed( SHA512_CONTEXT *hd, MD_SEED seed )
+{
+       if( seed->algo != DIGEST_ALGO_SHA512 )
+               BUG();
+
+       sha512_read_Xseed(hd, seed);
+}
+
+static void
+sha384_write_seed( SHA512_CONTEXT *hd, MD_SEED seed )
+{
+       sha512_write_seed(hd, seed);
+       seed->algo = DIGEST_ALGO_SHA384;
+}
+
+static void
+sha384_read_seed( SHA512_CONTEXT *hd, MD_SEED seed )
+{
+       if( seed->algo != DIGEST_ALGO_SHA384 )
+               BUG();
+
+       sha512_read_Xseed(hd, seed);
+}
+
+#endif
+
 /****************
  * Return some information about the algorithm.  We need algo here to
  * distinguish different flavors of the algorithm.
@@ -372,6 +476,10 @@
                 void (**r_write)( void *c, byte *buf, size_t nbytes ),
                 void (**r_final)( void *c ),
                 byte *(**r_read)( void *c )
+#ifdef ENABLE_MD_SEED
+              , void (**r_read_seed)( void *c, MD_SEED seed),
+              void (**r_write_seed)( void *c, MD_SEED seed)
+#endif
                 )
 {
   static byte asn[] = /* Object ID is 2.16.840.1.101.3.4.2.3 */
@@ -393,6 +501,11 @@
     *(void  (**)(SHA512_CONTEXT *))r_final               = sha512_final;
     *(byte *(**)(SHA512_CONTEXT *))r_read                = sha512_read;
 
+#ifdef ENABLE_MD_SEED
+    *(void  (**)(SHA512_CONTEXT *, MD_SEED ))r_read_seed  = sha512_read_seed;
+    *(void  (**)(SHA512_CONTEXT *, MD_SEED ))r_write_seed = sha512_write_seed;
+#endif
+
     return "SHA512";
 }
 
@@ -405,6 +518,10 @@
                 void (**r_write)( void *c, byte *buf, size_t nbytes ),
                 void (**r_final)( void *c ),
                 byte *(**r_read)( void *c )
+#ifdef ENABLE_MD_SEED
+              , void (**r_read_seed)( void *c, MD_SEED seed),
+              void (**r_write_seed)( void *c, MD_SEED seed)
+#endif
                 )
 {
   static byte asn[] = /* Object ID is 2.16.840.1.101.3.4.2.2 */
@@ -426,5 +543,12 @@
     *(void  (**)(SHA512_CONTEXT *))r_final               = sha512_final;
     *(byte *(**)(SHA512_CONTEXT *))r_read                = sha512_read;
 
+#ifdef ENABLE_MD_SEED
+    *(void  (**)(SHA512_CONTEXT *, MD_SEED ))r_read_seed  = sha384_read_seed;
+    *(void  (**)(SHA512_CONTEXT *, MD_SEED ))r_write_seed = sha384_write_seed;
+#endif
+
     return "SHA384";
 }
+
+
diff -urBbN gnupg-1.4.2/config.h.in gnupg-1.4.2-md-seed-1/config.h.in
--- gnupg-1.4.2/config.h.in     2005-07-26 18:08:19.000000000 +0200
+++ gnupg-1.4.2-md-seed-1/config.h.in   2006-02-18 23:57:49.000000000 +0100
@@ -41,6 +41,9 @@
 /* Define to include OpenPGP card support */
 #undef ENABLE_CARD_SUPPORT
 
+/* Define to enable remote signatures */
+#undef ENABLE_MD_SEED
+
 /* Define to 1 if translation of program messages to the user's native
    language is requested. */
 #undef ENABLE_NLS
diff -urBbN gnupg-1.4.2/configure gnupg-1.4.2-md-seed-1/configure
--- gnupg-1.4.2/configure       2005-07-26 17:54:43.000000000 +0200
+++ gnupg-1.4.2-md-seed-1/configure     2006-02-18 23:55:32.000000000 +0100
@@ -865,6 +865,7 @@
   --enable-minimal        build the smallest gpg binary possible
   --disable-card-support  disable OpenPGP card support
   --disable-agent-support disable gpg-agent support
+  --disable-md-seed       disable remote signatures
   --disable-rsa           disable the RSA public key algorithm
   --disable-idea          disable the IDEA cipher
   --disable-cast5         disable the CAST5 cipher
@@ -1021,7 +1022,7 @@
     else
       echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
     fi
-    cd "$ac_popdir"
+    cd $ac_popdir
   done
 fi
 
@@ -2048,6 +2049,7 @@
 card_support=yes
 agent_support=yes
 disable_keyserver_path=no
+use_mdseed=yes
 
 # Check whether --enable-minimal or --disable-minimal was given.
 if test "${enable_minimal+set}" = set; then
@@ -2064,6 +2066,7 @@
    use_exec=no
    card_support=no
    agent_support=no
+   use_mdseed=no
 fi;
 
 
@@ -2089,6 +2093,22 @@
 echo "$as_me:$LINENO: result: $agent_support" >&5
 echo "${ECHO_T}$agent_support" >&6
 
+echo "$as_me:$LINENO: checking whether to enable remote signatures" >&5
+echo $ECHO_N "checking whether to enable remote signatures... $ECHO_C" >&6
+# Check whether --enable-md-seed or --disable-md-seed was given.
+if test "${enable_md_seed+set}" = set; then
+  enableval="$enable_md_seed"
+  use_mdseed=$enableval
+fi;
+echo "$as_me:$LINENO: result: $use_mdseed" >&5
+echo "${ECHO_T}$use_mdseed" >&6
+if test x"$use_mdseed" = xyes ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define ENABLE_MD_SEED 1
+_ACEOF
+
+fi
 
 echo "$as_me:$LINENO: checking whether to enable the RSA public key algorithm" 
>&5
 echo $ECHO_N "checking whether to enable the RSA public key algorithm... 
$ECHO_C" >&6
diff -urBbN gnupg-1.4.2/configure.ac gnupg-1.4.2-md-seed-1/configure.ac
--- gnupg-1.4.2/configure.ac    2005-07-26 17:17:46.000000000 +0200
+++ gnupg-1.4.2-md-seed-1/configure.ac  2006-02-18 23:55:08.000000000 +0100
@@ -154,6 +154,7 @@
 card_support=yes
 agent_support=yes
 disable_keyserver_path=no
+use_mdseed=yes
 
 AC_ARG_ENABLE(minimal,
    AC_HELP_STRING([--enable-minimal],[build the smallest gpg binary possible]),
@@ -168,7 +169,9 @@
    use_bzip2=no
    use_exec=no
    card_support=no
-   agent_support=no)
+   agent_support=no
+   use_mdseed=no)
+   
 
 
 AC_MSG_CHECKING([whether OpenPGP card support is requested])
@@ -187,6 +190,14 @@
               agent_support=$enableval)
 AC_MSG_RESULT($agent_support)
 
+AC_MSG_CHECKING([whether to enable remote signatures])
+AC_ARG_ENABLE(md-seed,
+   AC_HELP_STRING([--disable-md-seed],[disable remote signatures]),
+   use_mdseed=$enableval)
+AC_MSG_RESULT($use_mdseed)
+if test x"$use_mdseed" = xyes ; then
+   AC_DEFINE(ENABLE_MD_SEED,1,[Define to enable remote signatures])
+fi
 
 AC_MSG_CHECKING([whether to enable the RSA public key algorithm])
 AC_ARG_ENABLE(rsa,
diff -urBbN gnupg-1.4.2/g10/g10.c gnupg-1.4.2-md-seed-1/g10/g10.c
--- gnupg-1.4.2/g10/g10.c       2005-07-22 17:58:08.000000000 +0200
+++ gnupg-1.4.2-md-seed-1/g10/g10.c     2006-02-19 16:17:18.000000000 +0100
@@ -58,6 +58,9 @@
 #ifdef ENABLE_CARD_SUPPORT
 #include "ccid-driver.h"
 #endif
+#ifdef ENABLE_MD_SEED
+#include "md_seed.h"
+#endif
 
 #if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
 #define MY_O_BINARY  O_BINARY
@@ -354,6 +357,10 @@
     opcscDriver,
     oDisableCCID,
 
+#ifdef ENABLE_MD_SEED
+    aPrintSeed,
+    aSignSeed,
+#endif
     oNoop
   };
 
@@ -688,6 +695,11 @@
     { oDebugCCIDDriver, "debug-ccid-driver", 0, "@"},
 #endif
 
+#ifdef ENABLE_MD_SEED
+    { aPrintSeed, "print-seed", 256, N_("|algo file| generate md seed")},
+    { aSignSeed, "sign-seed", 256, N_("|seed| sign seed")},
+#endif
+
     {0,NULL,0,NULL}
 };
 
@@ -1683,6 +1695,7 @@
     opt.def_sig_expire="0";
     opt.def_cert_expire="0";
     set_homedir ( default_homedir () );
+    opt.outfile = NULL;
 
 #ifdef ENABLE_CARD_SUPPORT
 # ifdef _WIN32
@@ -2553,7 +2566,10 @@
          case oLimitCardInsertTries: 
             opt.limit_card_insert_tries = pargs.r.ret_int; 
             break;
-
+#ifdef ENABLE_MD_SEED
+         case aPrintSeed: set_cmd( &cmd, aPrintSeed); break;
+         case aSignSeed: set_cmd( &cmd, aSignSeed); break;
+#endif
   
          case oNoop: break;
 
@@ -3008,6 +3024,9 @@
       case aDeArmor:
       case aEnArmor:
       case aFixTrustDB:
+#ifdef ENABLE_MD_SEED
+      case aPrintSeed:
+#endif
        break;
       case aExportOwnerTrust: rc = setup_trustdb( 0, trustdb_name ); break;
       case aListTrustDB: rc = setup_trustdb( argc? 1:0, trustdb_name ); break;
@@ -3024,6 +3043,7 @@
       case aSign: 
       case aSignSym: 
       case aClearsign: 
+      case aSignSeed:
         if (!opt.quiet && any_explicit_recipient)
           log_info (_("WARNING: recipients (-r) given "
                       "without using public key encryption\n"));
@@ -3598,7 +3618,26 @@
          m_free(str);
        }
        break;
+#ifdef ENABLE_MD_SEED
+      case aPrintSeed: 
+       if( (argc < 1) || (2 < argc))
+           wrong_args("--print-seed algo [file]");
+       {
+           int algo = string_to_digest_algo(argv[0]);
 
+           if( !algo )
+               log_error(_("invalid hash algorithm `%s'\n"), argv[0] );
+           else
+               print_seed(argc>1 ? argv[1] : NULL, algo, opt.outfile);
+       }
+       break;
+      case aSignSeed: 
+       if( argc != 1)
+           wrong_args("--sign-seed seed");
+       else
+           sign_seed(argv[0], opt.outfile ? opt.outfile : "-", locusr);
+       break;
+#endif
       case aListPackets:
        opt.list_packets=2;
       default:
diff -urBbN gnupg-1.4.2/g10/sign.c gnupg-1.4.2-md-seed-1/g10/sign.c
--- gnupg-1.4.2/g10/sign.c      2005-05-31 08:29:59.000000000 +0200
+++ gnupg-1.4.2-md-seed-1/g10/sign.c    2006-02-19 21:08:57.000000000 +0100
@@ -43,6 +43,10 @@
 #include "i18n.h"
 #include "cardglue.h"
 
+#ifdef ENABLE_MD_SEED
+#include "md_seed.h"
+#include "http.h"
+#endif
 
 #ifdef HAVE_DOSISH_SYSTEM
 #define LF "\r\n"
@@ -1506,3 +1510,494 @@
        *ret_sig = sig;
     return rc;
 }
+
+#ifdef ENABLE_MD_SEED
+/****************
+ * Remove all %xx escapes; this is done inplace.
+ * Returns: new length of the string.
+ */
+int
+remove_escapes( byte *string )
+{
+    int n = 0;
+    byte *p, *s;
+
+    for(p=s=string; *s ; s++ ) {
+       if( *s == '%' ) {
+           if( s[1] && s[2] && isxdigit(s[1]) && isxdigit(s[2]) ) {
+               s++;
+               *p  = *s >= '0' && *s <= '9' ? *s - '0' :
+                     *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10 ;
+               *p <<= 4;
+               s++;
+               *p |= *s >= '0' && *s <= '9' ? *s - '0' :
+                     *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10 ;
+               p++;
+               n++;
+           }
+           else {
+               *p++ = *s++;
+               if( *s )
+                  *p++ = *s++;
+               if( *s )
+                  *p++ = *s++;
+               if( *s )
+                  *p = 0;
+               return -1; /* bad URI */
+           }
+       }
+       else
+       {
+           *p++ = *s;
+           n++;
+       }
+    }
+    *p = 0; /* always keep a string terminator */
+    return n;
+}
+
+URI_TUPLE
+read_tuple(char* source)
+{
+       URI_TUPLE tuple = m_alloc(sizeof(struct uri_tuple));
+       tuple->next = NULL;
+       tuple->name = NULL;
+       tuple->value = NULL;
+       tuple->valuelen = 0;
+
+       char* start = source;
+       char* end = start;
+
+       if( end == NULL)
+               BUG();
+
+       // name
+       while(1){
+               if(*end == 0){
+                       tuple->name = start;
+                       remove_escapes(tuple->name);
+                       return tuple;
+               }else if(*end == '='){
+                       *end++ = 0;
+                       tuple->name = start;
+                       break;
+               }else if(*end == '&'){
+                       *end++ = 0;
+                       tuple->name = start;
+                       remove_escapes(tuple->name);
+                       tuple->next = read_tuple(end);
+                       return tuple;
+               }
+               end++;
+       }
+
+       start = end;
+
+       while(1){
+               if(*end == 0){
+                       tuple->value = start;
+                       tuple->valuelen = remove_escapes(tuple->value);
+                       return tuple;
+               }else if(*end == '='){
+                       BUG();
+               }else if(*end == '&'){
+                       *end++ = 0;
+                       tuple->value = start;
+                       tuple->valuelen = remove_escapes(tuple->value);
+                       tuple->next = read_tuple(end);
+                       return tuple;
+               }
+               end++;
+       }
+}
+
+void
+write_tuple(URI_TUPLE tuple, FILE* output)
+{
+
+       const byte * s = tuple->name;
+       byte c = *s;
+       while(c){
+               if((('A' <= c) && (c <= 'Z')) 
+                               || (('a' <= c) && (c <= 'z'))
+                               || (('0' <= c) && (c <= '9'))
+                               || (c == '_') || (c == '-'))
+               {
+                       if(EOF == fputc(c, output)){
+                               fprintf(stderr, "! -%c-\n", c);
+                               BUG();
+                       }
+               } else {
+                       fprintf(output, "%%%02X", c);
+               }
+               c = *(++s);     
+       }
+
+       size_t len = tuple->valuelen;
+               
+       if(len > 0)
+       {
+               if(EOF == fputc('=', output))
+                       BUG();
+
+               s = tuple->value;
+
+               while(len-- > 0)
+               {
+                       byte c = *(s++);
+
+                       if((('A' <= c) && (c <= 'Z')) 
+                                       || (('a' <= c) && (c <= 'z'))
+                                       || (('0' <= c) && (c <= '9')))
+                       {
+                               if(EOF == fputc(c, output))
+                                       BUG();
+                       } else {
+                               fprintf(output, "%%%02X", c);
+                       }
+               }
+               if(tuple->next != NULL){
+                       if(EOF == fputc('&', output))
+                               BUG();
+                       write_tuple(tuple->next, output);
+               }
+       }else if(tuple->next != NULL){
+               if(EOF == fputc('=', output))
+                       BUG();
+               write_tuple(tuple->next, output);
+       }
+}
+
+MD_SEED
+tuple2seed(URI_TUPLE tuple)
+{
+       URI_TUPLE current = tuple;
+       MD_SEED seed = m_alloc(sizeof(struct md_seed));
+       seed->algo = 0;
+       seed->state = 0;
+       seed->state_length = 0;
+       seed->buffer = 0;
+       seed->buffer_length = 0;
+       seed->sig_type = 0;
+
+       char* buffer = NULL;
+       size_t buffer_enc_len = 0;
+       int had_block = 0;
+       int had_state = 0;
+       int had_length = 0;
+       int had_type = 0;
+       int had_algo = 0;
+
+       while(current){
+               if(0 == strcmp("algo", current->name)){
+                       seed->algo = string_to_digest_algo( current->value );
+                       had_algo = 1;
+               }else if(0 == strcmp("sig_type", current->name)){
+                       char* tmp;
+                       long int x = strtol(current->value, &tmp, 10);
+                       if(current->value + current->valuelen != tmp)
+                               BUG();
+
+                       if(x < 0)
+                               BUG();
+
+                       seed->sig_type = x;
+                       had_type = 1;
+               }else if(0 == strcmp("block", current->name)){
+                       char* tmp;
+                       long int x = strtol(current->value, &tmp, 10);
+                       if(current->value + current->valuelen != tmp)
+                               BUG();
+
+                       if(x < 0)
+                               BUG();
+
+                       seed->block_count = x;
+                       had_block = 1;
+               }else if(0 == strcmp("state", current->name)){
+                       seed->state = current->value;
+                       seed->state_length = current->valuelen;
+                       had_state = 1;
+               }else if(0 == strcmp("length", current->name)){
+                       char* tmp;
+                       long int x = strtol(current->value, &tmp, 10);
+                       if(current->value + current->valuelen != tmp)
+                               BUG();
+                       
+                       if(x < 0)
+                               BUG();
+
+                       seed->buffer_length = x;
+                       had_length = 1;
+               }else if(0 == strcmp("buffer", current->name)){
+                       buffer = current->value;
+                       buffer_enc_len = current->valuelen;
+               }else{
+                       // ignore unknown keys
+               }
+               current = current->next;
+       }
+
+       seed->buffer = buffer;
+
+       if( ! had_algo )
+               log_error(_("missing algorithm data\n"));
+
+       if( ! had_type )
+               log_error(_("missing signature type data\n"));
+
+       if( ! had_block )
+               log_error(_("missing block count data\n"));
+
+       if( ! had_state )
+               log_error(_("missing state data\n"));
+
+       if( ! had_length )
+               log_error(_("missing buffer length data\n"));
+       
+       if( log_get_errorcount(0) )
+               return NULL;
+       else
+               return seed;
+}
+
+URI_TUPLE
+seed2tuple(MD_SEED seed)
+{
+       char* tmp;
+       
+       URI_TUPLE root = m_alloc(sizeof(struct uri_tuple)); 
+       URI_TUPLE current = root;
+
+       if( seed->algo == 0 )
+               BUG();
+
+       current->name = "algo";
+       current->value = digest_algo_to_string(seed->algo); 
+       current->valuelen = strlen(current->value);
+
+       current->next = m_alloc(sizeof(struct uri_tuple));
+       current = current->next;
+
+       current->name = "sig_type";
+       tmp = m_alloc(64);
+       snprintf(tmp, 64, "%hhu", seed->sig_type);
+       current->value = tmp;
+
+       current->valuelen = strlen(current->value);
+       current->next = m_alloc(sizeof(struct uri_tuple));
+       current = current->next;
+
+       current->name = "block";
+       tmp = m_alloc(64);
+       snprintf(tmp, 64, "%zu", seed->block_count);
+       current->value = tmp;
+
+       current->valuelen = strlen(current->value);
+       current->next = m_alloc(sizeof(struct uri_tuple));
+       current = current->next;
+
+       current->name = "state";
+       current->value = seed->state;
+       current->valuelen = seed->state_length;
+
+       current->next = m_alloc(sizeof(struct uri_tuple));
+       current = current->next;
+
+       current->name = "length";
+       tmp = m_alloc(64);
+       snprintf(tmp, 64, "%zu", seed->buffer_length);
+       current->value = tmp;
+       current->valuelen = strlen(current->value);
+
+       if(seed->buffer_length > 0){
+               current->next = m_alloc(sizeof(struct uri_tuple));
+               current = current->next;
+
+               current->name = "buffer";
+               current->value = seed->buffer;
+               current->valuelen = seed->buffer_length / 8;
+
+               if( seed->buffer_length % 8 )
+                       current->valuelen += 1;
+       }
+
+       current->next = NULL;
+
+       return root;
+}
+
+void
+sign_seed( const char *seed_source , const char *outfile, STRLIST locusr)
+{
+       URI_TUPLE tuple;
+       tuple = read_tuple(seed_source);
+
+       if( !tuple )
+               BUG();
+       
+       MD_SEED seed =  tuple2seed(tuple);
+
+       if( !seed )
+               BUG();
+
+       MD_HANDLE md = md_read_seed(seed, 0);
+       if( !md )
+               BUG();
+
+    PK_LIST pk_list = NULL;
+    SK_LIST sk_list = NULL;
+    int rc = 0;
+    u32 duration=0;
+    IOBUF out = NULL;
+
+    armor_filter_context_t afx;
+    memset( &afx, 0, sizeof afx);
+
+    PACKET pkt;
+    init_packet( &pkt );
+
+    if(!opt.force_v3_sigs && !RFC1991)
+      {
+       if(opt.ask_sig_expire && !opt.batch)
+         duration=ask_expire_interval(1,opt.def_sig_expire);
+       else
+         duration=parse_expire_string(opt.def_sig_expire);
+      }
+
+    if( (rc = open_outfile( outfile, opt.armor ? 1 : 2, &out )))
+       BUG();
+
+    if( !RFC1991 )
+       afx.what = 2;
+
+    if( opt.armor )
+       iobuf_push_filter( out, armor_filter, &afx );
+
+
+    if( (rc=build_sk_list( locusr, &sk_list, 1, PUBKEY_USAGE_SIG )) )
+       BUG();
+
+    opt.def_digest_algo = md_get_algo(md);
+
+           if(!opt.expert &&
+              select_algo_from_prefs(pk_list,PREFTYPE_HASH,
+                                     opt.def_digest_algo,
+                                     NULL)!=opt.def_digest_algo)
+         log_info(_("WARNING: forcing digest algorithm %s (%d)"
+                    " violates recipient preferences\n"),
+                  digest_algo_to_string(opt.def_digest_algo),
+                  opt.def_digest_algo);
+
+           recipient_digest_algo = opt.def_digest_algo;
+
+    /* write the signatures */
+    rc = write_signature_packets (sk_list, out, md,
+                                  seed->sig_type,
+                                 0, duration, 'D');
+
+
+    if( rc )
+       iobuf_cancel(out);
+    else {
+       iobuf_close(out);
+    }
+    md_close( md );
+    release_sk_list( sk_list );
+    release_pk_list( pk_list );
+    recipient_digest_algo=0;
+}
+
+void
+print_seed( const char *fname, int algo , const char *outfile )
+{
+    FILE *fp;
+    FILE *output;
+
+    char buf[1024];
+    size_t n;
+    MD_HANDLE md;
+
+    if( opt.textmode )
+       {
+         log_error(_("textmode isn't yet implemented for md seeds\n"));
+         return;
+       }
+
+
+    if( !outfile )
+       output = stdout;
+    else {
+       output = fopen( outfile, "w" );
+        if (fp && is_secured_file (fileno (fp)))
+          {
+            fclose (fp);
+            fp = NULL;
+            errno = EPERM;
+          }
+    }
+
+    if( !output ) {
+       log_error("%s: %s\n", outfile , strerror(errno) );
+       return;
+    }
+
+    if( !fname ) {
+       fp = stdin;
+#ifdef HAVE_DOSISH_SYSTEM
+       setmode ( fileno(fp) , O_BINARY );
+#endif
+    }
+    else {
+       fp = fopen( fname, "rb" );
+        if (fp && is_secured_file (fileno (fp)))
+          {
+            fclose (fp);
+            fp = NULL;
+            errno = EPERM;
+          }
+    }
+    if( !fp ) {
+       log_error("%s: %s\n", fname?fname:"[stdin]", strerror(errno) );
+       return;
+    }
+
+    if( algo )
+        md = md_open( algo, 0 );
+    else
+       BUG();
+
+    if( ! md ){
+           printf("algo: %i\n", algo);
+           BUG();
+    }
+
+    while( (n=fread( buf, 1, DIM(buf), fp )) )
+       md_write( md, buf, n );
+
+
+    if( ferror(fp) )
+       log_error("%s: %s\n", fname?fname:"[stdin]", strerror(errno) );
+    else {
+       MD_SEED seed;
+       seed = m_alloc( sizeof(struct md_seed) );
+       md_write_seed( md, seed );
+       
+       seed->sig_type = 0; // @todo@ handle text mode
+       
+       URI_TUPLE tuple = seed2tuple( seed );
+       write_tuple(tuple, output);
+       fputc('\n', output);
+    }
+
+    md_close(md);
+
+    if( fp != stdin )
+       fclose(fp);
+
+    if( output != stdout ) {
+       fflush( output );
+       fclose( output );
+    }
+}
+#endif /* ENABLE_MD_SEED */
diff -urBbN gnupg-1.4.2/include/md_seed.h 
gnupg-1.4.2-md-seed-1/include/md_seed.h
--- gnupg-1.4.2/include/md_seed.h       1970-01-01 01:00:00.000000000 +0100
+++ gnupg-1.4.2-md-seed-1/include/md_seed.h     2006-02-19 15:44:13.000000000 
+0100
@@ -0,0 +1,44 @@
+#ifndef MD_SEED_H
+#define MD_SEED_H
+
+#ifdef ENABLE_MD_SEED
+#include <byteswap.h>
+#include "types.h"
+#include "cipher.h"
+
+struct md_seed {
+       size_t buffer_length; // number of _bits_ yet to be hashed
+       byte * buffer;
+       
+       size_t state_length; // number of _bytes_ in the state buffer
+       byte * state;
+
+       size_t block_count;
+
+       byte algo;
+       byte sig_type;
+};
+
+typedef struct md_seed* MD_SEED;
+
+MD_HANDLE md_read_seed(MD_SEED seed, int secure);
+void md_write_seed(MD_HANDLE md, MD_SEED seed);
+
+void print_seed( const char *fname, int algo, const char *outfile);
+void sign_seed( const char *seed_source , const char *outfile, STRLIST locusr);
+
+#ifdef BIG_ENDIAN_HOST
+#define hton_32(x) (x)
+#define ntoh_32(x) (x)
+#define hton_64(x) (x)
+#define ntoh_64(x) (x)
+#else
+#define hton_32(x) (bswap_32(x))
+#define ntoh_32(x) (bswap_32(x))
+#define hton_64(x) (bswap_64(x))
+#define ntoh_64(x) (bswap_64(x))
+#endif /* BIG_ENDIAN_HOST */
+
+#endif /* ENABLE_MD_SEED */
+
+#endif /* MD_SEED_H */
-----BEGIN PGP SIGNATURE-----

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
jCshk85xvtQ=
=mlWI
-----END PGP SIGNATURE-----

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Gnupg-users mailing list
Gnupg-users@gnupg.org
http://lists.gnupg.org/mailman/listinfo/gnupg-users

Reply via email to