/**
  * Not thread-safe. Blocking. Only used for external sockets. ClientWriterRunner thread is the
  * only caller. Others must use doSend().
  */
 void writeMessage(I2CPMessage msg) {
   // long before = _context.clock().now();
   try {
     // We don't need synchronization here, ClientWriterRunner is the only writer.
     // synchronized (_out) {
     msg.writeMessage(_out);
     _out.flush();
     // }
     // if (_log.shouldLog(Log.DEBUG))
     //    _log.debug("after writeMessage("+ msg.getClass().getName() + "): "
     //               + (_context.clock().now()-before) + "ms");
   } catch (I2CPMessageException ime) {
     _log.error("Error sending I2CP message to client", ime);
     stopRunning();
   } catch (EOFException eofe) {
     // only warn if client went away
     if (_log.shouldLog(Log.WARN))
       _log.warn("Error sending I2CP message - client went away", eofe);
     stopRunning();
   } catch (IOException ioe) {
     if (_log.shouldLog(Log.ERROR)) _log.error("IO Error sending I2CP message to client", ioe);
     stopRunning();
   } catch (Throwable t) {
     _log.log(Log.CRIT, "Unhandled exception sending I2CP message to client", t);
     stopRunning();
     // } finally {
     //    long after = _context.clock().now();
     //    long lag = after - before;
     //    if (lag > 300) {
     //        if (_log.shouldLog(Log.WARN))
     //            _log.warn("synchronization on the i2cp message send took too long (" + lag
     //                      + "ms): " + msg);
     //    }
   }
 }
Beispiel #2
0
 private static void log(I2PAppContext ctx, int level, String msg, Throwable t) {
   if (level >= Log.WARN && !ctx.isRouterContext()) {
     System.out.println(msg);
     if (t != null) t.printStackTrace();
   }
   Log l = ctx.logManager().getLog(KeyStoreUtil.class);
   l.log(level, msg, t);
 }
Beispiel #3
0
  /**
   * @param hash either a Hash or a SHA1Hash
   * @since 0.8.3
   */
  private boolean verifySig(
      Signature signature, SimpleDataStructure hash, SigningPublicKey verifyingKey) {
    long start = _context.clock().now();

    try {
      byte[] sigbytes = signature.getData();
      byte rbytes[] = new byte[20];
      byte sbytes[] = new byte[20];
      // System.arraycopy(sigbytes, 0, rbytes, 0, 20);
      // System.arraycopy(sigbytes, 20, sbytes, 0, 20);
      for (int x = 0; x < 40; x++) {
        if (x < 20) {
          rbytes[x] = sigbytes[x];
        } else {
          sbytes[x - 20] = sigbytes[x];
        }
      }

      BigInteger s = new NativeBigInteger(1, sbytes);
      BigInteger r = new NativeBigInteger(1, rbytes);
      BigInteger y = new NativeBigInteger(1, verifyingKey.getData());
      BigInteger w = null;
      try {
        w = s.modInverse(CryptoConstants.dsaq);
      } catch (ArithmeticException ae) {
        _log.warn("modInverse() error", ae);
        return false;
      }
      byte data[] = hash.getData();
      NativeBigInteger bi = new NativeBigInteger(1, data);
      BigInteger u1 = bi.multiply(w).mod(CryptoConstants.dsaq);
      BigInteger u2 = r.multiply(w).mod(CryptoConstants.dsaq);
      BigInteger modval = CryptoConstants.dsag.modPow(u1, CryptoConstants.dsap);
      BigInteger modmulval = modval.multiply(y.modPow(u2, CryptoConstants.dsap));
      BigInteger v = (modmulval).mod(CryptoConstants.dsap).mod(CryptoConstants.dsaq);

      boolean ok = v.compareTo(r) == 0;

      long diff = _context.clock().now() - start;
      if (diff > 1000) {
        if (_log.shouldLog(Log.WARN))
          _log.warn("Took too long to verify the signature (" + diff + "ms)");
      }
      return ok;
    } catch (Exception e) {
      _log.log(Log.CRIT, "Error verifying the signature", e);
      return false;
    }
  }
 /**
  * @param logLevel e.g. Log.WARN
  * @since 0.8.2
  */
 void disconnectClient(String reason, int logLevel) {
   if (_log.shouldLog(logLevel))
     _log.log(logLevel, "Disconnecting the client - " + reason + " config: " + _config);
   DisconnectMessage msg = new DisconnectMessage();
   msg.setReason(reason);
   try {
     doSend(msg);
   } catch (I2CPMessageException ime) {
     if (_log.shouldLog(Log.WARN)) _log.warn("Error writing out the disconnect message", ime);
   }
   // give it a little time to get sent out...
   // even better would be to have stopRunning() flush it?
   try {
     Thread.sleep(50);
   } catch (InterruptedException ie) {
   }
   stopRunning();
 }
Beispiel #5
0
  /**
   * Uses the given {@link net.i2p.data.SigningPrivateKey} to sign the given input file along with
   * its version string using DSA. The output will be a signed update file where the first 40 bytes
   * are the resulting DSA signature, the next 16 bytes are the input file's version string encoded
   * in UTF-8 (padded with trailing <code>0h</code> characters if necessary), and the remaining
   * bytes are the raw bytes of the input file.
   *
   * @param inputFile The file to be signed.
   * @param signedFile The signed update file to write.
   * @param signingPrivateKey An instance of <code>SigningPrivateKey</code> to sign <code>inputFile
   *     </code> with.
   * @param version The version string of the input file. If this is longer than 16 characters it
   *     will be truncated.
   * @return An instance of {@link net.i2p.data.Signature}, or <code>null</code> if there was an
   *     error.
   */
  public Signature sign(
      String inputFile, String signedFile, SigningPrivateKey signingPrivateKey, String version) {
    byte[] versionHeader = {
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00
    };
    byte[] versionRawBytes = null;

    if (version.length() > VERSION_BYTES) version = version.substring(0, VERSION_BYTES);

    try {
      versionRawBytes = version.getBytes("UTF-8");
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException("wtf, your JVM doesnt support utf-8? " + e.getMessage());
    }

    System.arraycopy(versionRawBytes, 0, versionHeader, 0, versionRawBytes.length);

    FileInputStream fileInputStream = null;
    Signature signature = null;
    SequenceInputStream bytesToSignInputStream = null;
    ByteArrayInputStream versionHeaderInputStream = null;

    try {
      fileInputStream = new FileInputStream(inputFile);
      versionHeaderInputStream = new ByteArrayInputStream(versionHeader);
      bytesToSignInputStream = new SequenceInputStream(versionHeaderInputStream, fileInputStream);
      signature = _context.dsa().sign(bytesToSignInputStream, signingPrivateKey);

    } catch (Exception e) {
      if (_log.shouldLog(Log.ERROR)) _log.error("Error signing", e);

      return null;
    } finally {
      if (bytesToSignInputStream != null)
        try {
          bytesToSignInputStream.close();
        } catch (IOException ioe) {
        }

      fileInputStream = null;
    }

    FileOutputStream fileOutputStream = null;

    try {
      fileOutputStream = new FileOutputStream(signedFile);
      fileOutputStream.write(signature.getData());
      fileOutputStream.write(versionHeader);
      fileInputStream = new FileInputStream(inputFile);
      byte[] buffer = new byte[1024];
      int bytesRead = 0;
      while ((bytesRead = fileInputStream.read(buffer)) != -1)
        fileOutputStream.write(buffer, 0, bytesRead);
      fileOutputStream.close();
    } catch (IOException ioe) {
      if (_log.shouldLog(Log.WARN))
        _log.log(Log.WARN, "Error writing signed file " + signedFile, ioe);

      return null;
    } finally {
      if (fileInputStream != null)
        try {
          fileInputStream.close();
        } catch (IOException ioe) {
        }

      if (fileOutputStream != null)
        try {
          fileOutputStream.close();
        } catch (IOException ioe) {
        }
    }

    return signature;
  }
  /**
   * 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;
  }
Beispiel #7
0
  /**
   * calculate and update the job timings if it was lagged too much or took too long to run, spit
   * out a warning (and if its really excessive, kill the router)
   */
  void updateStats(Job job, long doStart, long origStartAfter, long duration) {
    if (_context.router() == null) return;
    String key = job.getName();
    long lag = doStart - origStartAfter; // how long were we ready and waiting?
    MessageHistory hist = _context.messageHistory();
    long uptime = _context.router().getUptime();

    if (lag < 0) lag = 0;
    if (duration < 0) duration = 0;

    JobStats stats = _jobStats.get(key);
    if (stats == null) {
      stats = new JobStats(key);
      _jobStats.put(key, stats);
      // yes, if two runners finish the same job at the same time, this could
      // create an extra object.  but, who cares, its pushed out of the map
      // immediately anyway.
    }
    stats.jobRan(duration, lag);

    String dieMsg = null;

    if (lag > _lagWarning) {
      dieMsg =
          "Lag too long for job "
              + job.getName()
              + " ["
              + lag
              + "ms and a run time of "
              + duration
              + "ms]";
    } else if (duration > _runWarning) {
      dieMsg =
          "Job run too long for job "
              + job.getName()
              + " ["
              + lag
              + "ms lag and run time of "
              + duration
              + "ms]";
    }

    if (dieMsg != null) {
      if (_log.shouldLog(Log.WARN)) _log.warn(dieMsg);
      if (hist != null) hist.messageProcessingError(-1, JobQueue.class.getName(), dieMsg);
    }

    if ((lag > _lagFatal) && (uptime > _warmupTime)) {
      // this is fscking bad - the network at this size shouldn't have this much real contention
      // so we're going to DIE DIE DIE
      if (_log.shouldLog(Log.WARN))
        _log.log(
            Log.WARN,
            "The router is either incredibly overloaded or (more likely) there's an error.",
            new Exception("ttttooooo mmmuuuccccchhhh llllaaagggg"));
      // try { Thread.sleep(5000); } catch (InterruptedException ie) {}
      // Router.getInstance().shutdown();
      return;
    }

    if ((uptime > _warmupTime) && (duration > _runFatal)) {
      // slow CPUs can get hosed with ElGamal, but 10s is too much.
      if (_log.shouldLog(Log.WARN))
        _log.log(
            Log.WARN,
            "The router is incredibly overloaded - either you have a 386, or (more likely) there's an error. ",
            new Exception("ttttooooo sssllloooowww"));
      // try { Thread.sleep(5000); } catch (InterruptedException ie) {}
      // Router.getInstance().shutdown();
      return;
    }
  }