diff --git a/router/java/src/net/i2p/router/StatisticsManager.java b/router/java/src/net/i2p/router/StatisticsManager.java
index 50b4eb0bde20c4337164bbab2e7c4c9cb72431bc..b1ed027426e0137a2d9cf07ae4b12890631735d5 100644
--- a/router/java/src/net/i2p/router/StatisticsManager.java
+++ b/router/java/src/net/i2p/router/StatisticsManager.java
@@ -188,24 +188,29 @@ public class StatisticsManager {
         if (family != null) {
             stats.setProperty(FamilyKeyCrypto.OPT_NAME, family);
             String sig = null;
+            String key = null;
             RouterInfo oldRI = _context.router().getRouterInfo();
             if (oldRI != null) {
                 // don't do it if family changed
                 if (family.equals(oldRI.getOption(FamilyKeyCrypto.OPT_NAME))) {
-                    // copy over the signature
+                    // copy over the pubkey and signature
+                    key = oldRI.getOption(FamilyKeyCrypto.OPT_KEY);
+                    if (key != null)
+                        stats.setProperty(FamilyKeyCrypto.OPT_KEY, key);
                     sig = oldRI.getOption(FamilyKeyCrypto.OPT_SIG);
                     if (sig != null)
                         stats.setProperty(FamilyKeyCrypto.OPT_SIG, sig);
                 }
             }
-            if (sig == null) {
+            if (sig == null || key == null) {
                 FamilyKeyCrypto fkc = _context.router().getFamilyKeyCrypto();
                 if (fkc != null) {
                     try {
-                        sig = fkc.sign(family, h);
-                        stats.setProperty(FamilyKeyCrypto.OPT_SIG, sig);
+                        stats.putAll(fkc.sign(family, h));
                     } catch (GeneralSecurityException gse) {
                         _log.error("Failed to sign router family", gse);
+                        stats.remove(FamilyKeyCrypto.OPT_KEY);
+                        stats.remove(FamilyKeyCrypto.OPT_SIG);
                     }
                 }
             }
diff --git a/router/java/src/net/i2p/router/crypto/FamilyKeyCrypto.java b/router/java/src/net/i2p/router/crypto/FamilyKeyCrypto.java
index 8af392f1c698523c06e311e4761408d227e12ca7..2bb6038c546789247e01d8fad04a582772fbbef0 100644
--- a/router/java/src/net/i2p/router/crypto/FamilyKeyCrypto.java
+++ b/router/java/src/net/i2p/router/crypto/FamilyKeyCrypto.java
@@ -54,7 +54,7 @@ public class FamilyKeyCrypto {
     private static final String KEYSTORE_PREFIX = "family-";
     private static final String KEYSTORE_SUFFIX = ".ks";
     private static final int DEFAULT_KEY_VALID_DAYS = 3652;  // 10 years
-    // Note that we can't use RSA here, as the b64 sig would exceed the 256 char limit for a Mapping
+    // Note that we can't use RSA here, as the b64 sig would exceed the 255 char limit for a Mapping
     // Note that we can't use EdDSA here, as keystore doesn't know how, and encoding/decoding is unimplemented
     private static final String DEFAULT_KEY_ALGORITHM = SigType.ECDSA_SHA256_P256.isAvailable() ? "EC" : "DSA";
     private static final int DEFAULT_KEY_SIZE = SigType.ECDSA_SHA256_P256.isAvailable() ? 256 : 1024;
@@ -62,6 +62,7 @@ public class FamilyKeyCrypto {
     private static final String CERT_DIR = "certificates/family";
     public static final String OPT_NAME = "family";
     public static final String OPT_SIG = "family.sig";
+    public static final String OPT_KEY = "family.key";
 
 
     /** 
@@ -109,16 +110,20 @@ public class FamilyKeyCrypto {
      *
      *  @param family non-null, must match that we were initialized with or will throw GSE
      *  @param h non-null
-     *  @return non-null base 64 signature string to be added to the RI
+     *  @return non-null options to be added to the RI
      *  @throws GeneralSecurityException on null hash, null or changed family, or signing error
      */
-    public String sign(String family, Hash h) throws GeneralSecurityException {
-        if (_privkey == null)
-            throw new GeneralSecurityException("family name set, must restart router");
+    public Map<String, String> sign(String family, Hash h) throws GeneralSecurityException {
+        if (_privkey == null) {
+            _log.logAlways(Log.WARN, "family name now set, must restart router to generate or load keys");
+            throw new GeneralSecurityException("family name now set, must restart router to generate or load keys");
+        }
         if (h == null)
             throw new GeneralSecurityException("null router hash");
-        if (!_fname.equals(family))
-            throw new GeneralSecurityException("family name changed, must restart router");
+        if (!_fname.equals(family)) {
+            _log.logAlways(Log.WARN, "family name changed, must restart router to generate or load new keys");
+            throw new GeneralSecurityException("family name changed, must restart router to generate or load new keys");
+        }
         byte[] nb = DataHelper.getUTF8(_fname);
         int len = nb.length + Hash.HASH_LENGTH;
         byte[] b = new byte[len];
@@ -127,7 +132,11 @@ public class FamilyKeyCrypto {
         Signature sig = _context.dsa().sign(b, _privkey);
         if (sig == null)
             throw new GeneralSecurityException("sig failed");
-        return sig.toBase64();
+        Map<String, String> rv = new HashMap<String, String>(3);
+        rv.put(OPT_NAME, family);
+        rv.put(OPT_KEY, _pubkey.getType().getCode() + ";" + _pubkey.toBase64());
+        rv.put(OPT_SIG, sig.toBase64());
+        return rv;
     }
 
     /** 
@@ -162,12 +171,46 @@ public class FamilyKeyCrypto {
                 return false;
             spk = loadCert(name);
             if (spk == null) {
-                _negativeCache.add(h);
-                if (_log.shouldInfo())
-                    _log.info("No cert for " + h + ' ' + name);
-                return false;
+                // look for a b64 key in the RI
+                String skey = ri.getOption(OPT_KEY);
+                if (skey != null) {
+                    int semi = skey.indexOf(";");
+                    if (semi > 0) {
+                        try {
+                            int code = Integer.parseInt(skey.substring(0, semi));
+                            SigType type = SigType.getByCode(code);
+                            if (type != null) {
+                                byte[] bkey = Base64.decode(skey.substring(semi + 1));
+                                if (bkey != null) {
+                                    spk = new SigningPublicKey(type, bkey);
+                                }
+                            }
+                        } catch (NumberFormatException e) {
+                            if (_log.shouldInfo())
+                                _log.info("Bad b64 family key: " + ri, e);
+                        } catch (IllegalArgumentException e) {
+                            if (_log.shouldInfo())
+                                _log.info("Bad b64 family key: " + ri, e);
+                        } catch (ArrayIndexOutOfBoundsException e) {
+                            if (_log.shouldInfo())
+                                _log.info("Bad b64 family key: " + ri, e);
+                        }
+                    }
+                }
+                if (spk == null) {
+                    _negativeCache.add(h);
+                    if (_log.shouldInfo())
+                        _log.info("No cert or valid key for " + h + ' ' + name);
+                    return false;
+                }
             }
         }
+        if (!spk.getType().isAvailable()) {
+            _negativeCache.add(h);
+            if (_log.shouldInfo())
+                _log.info("Unsupported crypto for sig for " + h);
+            return false;
+        }
         byte[] bsig = Base64.decode(ssig);
         if (bsig == null) {
             _negativeCache.add(h);