/**
   * Writes 6 files: router.info (standard RI format), router.keys.dat, and 4 individual key files
   * under keyBackup/
   *
   * <p>router.keys.dat file format: This is the same "eepPriv.dat" format used by the client code,
   * as documented in PrivateKeyFile.
   *
   * <p>Old router.keys file format: Note that this is NOT the same "eepPriv.dat" format used by the
   * client code.
   *
   * <pre>
   *   - Private key (256 bytes)
   *   - Signing Private key (20 bytes)
   *   - Public key (256 bytes)
   *   - Signing Public key (128 bytes)
   *  Total 660 bytes
   * </pre>
   *
   * Caller must hold Router.routerInfoFileLock.
   */
  RouterInfo createRouterInfo() {
    SigType type = getSigTypeConfig(getContext());
    RouterInfo info = new RouterInfo();
    OutputStream fos1 = null;
    try {
      info.setAddresses(getContext().commSystem().createAddresses());
      // not necessary, in constructor
      // info.setPeers(new HashSet());
      info.setPublished(getCurrentPublishDate(getContext()));
      Object keypair[] = getContext().keyGenerator().generatePKIKeypair();
      PublicKey pubkey = (PublicKey) keypair[0];
      PrivateKey privkey = (PrivateKey) keypair[1];
      SimpleDataStructure signingKeypair[] = getContext().keyGenerator().generateSigningKeys(type);
      SigningPublicKey signingPubKey = (SigningPublicKey) signingKeypair[0];
      SigningPrivateKey signingPrivKey = (SigningPrivateKey) signingKeypair[1];
      RouterIdentity ident = new RouterIdentity();
      Certificate cert = createCertificate(getContext(), signingPubKey);
      ident.setCertificate(cert);
      ident.setPublicKey(pubkey);
      ident.setSigningPublicKey(signingPubKey);
      byte[] padding;
      int padLen = SigningPublicKey.KEYSIZE_BYTES - signingPubKey.length();
      if (padLen > 0) {
        padding = new byte[padLen];
        getContext().random().nextBytes(padding);
        ident.setPadding(padding);
      } else {
        padding = null;
      }
      info.setIdentity(ident);
      Properties stats = getContext().statPublisher().publishStatistics(ident.getHash());
      info.setOptions(stats);

      info.sign(signingPrivKey);

      if (!info.isValid())
        throw new DataFormatException("RouterInfo we just built is invalid: " + info);

      // remove router.keys
      (new File(getContext().getRouterDir(), KEYS_FILENAME)).delete();

      // write router.info
      File ifile = new File(getContext().getRouterDir(), INFO_FILENAME);
      fos1 = new BufferedOutputStream(new SecureFileOutputStream(ifile));
      info.writeBytes(fos1);

      // write router.keys.dat
      File kfile = new File(getContext().getRouterDir(), KEYS2_FILENAME);
      PrivateKeyFile pkf =
          new PrivateKeyFile(kfile, pubkey, signingPubKey, cert, privkey, signingPrivKey, padding);
      pkf.write();

      getContext().keyManager().setKeys(pubkey, privkey, signingPubKey, signingPrivKey);

      if (_log.shouldLog(Log.INFO))
        _log.info(
            "Router info created and stored at "
                + ifile.getAbsolutePath()
                + " with private keys stored at "
                + kfile.getAbsolutePath()
                + " ["
                + info
                + "]");
      getContext().router().eventLog().addEvent(EventLog.REKEYED, ident.calculateHash().toBase64());
    } catch (GeneralSecurityException gse) {
      _log.log(Log.CRIT, "Error building the new router information", gse);
    } catch (DataFormatException dfe) {
      _log.log(Log.CRIT, "Error building the new router information", dfe);
    } catch (IOException ioe) {
      _log.log(Log.CRIT, "Error writing out the new router information", ioe);
    } finally {
      if (fos1 != null)
        try {
          fos1.close();
        } catch (IOException ioe) {
        }
    }
    return info;
  }