diff --git a/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java b/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java
index be74de990f2c65fd3d61ae5afbc042c0f1509598..6c95e2e19653f90dc31065232e50a297354ee1c8 100644
--- a/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java
+++ b/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java
@@ -25,9 +25,9 @@ import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
 import java.io.StringReader;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -35,6 +35,8 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
+import net.i2p.util.SecureFileOutputStream;
+
 /**
  * Utility class providing methods to parse and write files in config file
  * format, and subscription file format.
@@ -277,7 +279,7 @@ public class ConfigParser {
      */
     public static void write(Map map, File file) throws IOException {
         ConfigParser
-                .write(map, new BufferedWriter(new FileWriter(file, false)));
+                .write(map, new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(file), "UTF-8")));
     }
 
     /**
@@ -316,7 +318,7 @@ public class ConfigParser {
     public static void writeSubscriptions(List list, File file)
             throws IOException {
         ConfigParser.writeSubscriptions(list, new BufferedWriter(
-                new FileWriter(file, false)));
+                new OutputStreamWriter(new SecureFileOutputStream(file), "UTF-8")));
     }
 
 }
diff --git a/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java b/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java
index 077acdb7f02bbf7f1a8c13cd912cac599d994078..2588010118eb7156ba390464c942a1d3c4325174 100644
--- a/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java
+++ b/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java
@@ -29,6 +29,7 @@ import java.util.List;
 import java.util.Map;
 
 import net.i2p.I2PAppContext;
+import net.i2p.util.SecureDirectory;
 
 /**
  * Main class of addressbook.  Performs updates, and runs the main loop.
@@ -131,11 +132,11 @@ public class Daemon {
         String settingsLocation = "config.txt";
         File homeFile;
         if (args.length > 0) {
-            homeFile = new File(args[0]);
+            homeFile = new SecureDirectory(args[0]);
             if (!homeFile.isAbsolute())
-                homeFile = new File(I2PAppContext.getGlobalContext().getRouterDir(), args[0]);
+                homeFile = new SecureDirectory(I2PAppContext.getGlobalContext().getRouterDir(), args[0]);
         } else {
-            homeFile = new File(System.getProperty("user.dir"));
+            homeFile = new SecureDirectory(System.getProperty("user.dir"));
         }
         
         Map defaultSettings = new HashMap();
diff --git a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java
index 127a2bb19abfed633d7d79e440f590bff9a94e4b..b0e26bfe6acb2bb6a361e60b45224d9987031518 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java
@@ -26,6 +26,7 @@ import net.i2p.util.ConcurrentHashSet;
 import net.i2p.util.EepGet;
 import net.i2p.util.FileUtil;
 import net.i2p.util.Log;
+import net.i2p.util.SecureDirectory;
 import net.i2p.util.SimpleScheduler;
 import net.i2p.util.SimpleTimer;
 import net.i2p.util.Translate;
@@ -77,7 +78,7 @@ public class I2PSnarkUtil {
         // This is used for both announce replies and .torrent file downloads,
         // so it must be available even if not connected to I2CP.
         // so much for multiple instances
-        _tmpDir = new File(ctx.getTempDir(), "i2psnark");
+        _tmpDir = new SecureDirectory(ctx.getTempDir(), "i2psnark");
         FileUtil.rmdir(_tmpDir, false);
         _tmpDir.mkdirs();
     }
diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
index 59ab86a12920ec5d2e70ee86fa2fb9df887914e5..a1ddaf25db32235547b75090c73abd6f611ad3cb 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
@@ -21,6 +21,7 @@ import net.i2p.data.DataHelper;
 import net.i2p.util.I2PAppThread;
 import net.i2p.util.Log;
 import net.i2p.util.OrderedProperties;
+import net.i2p.util.SecureDirectory;
 
 /**
  * Manage multiple snarks
@@ -130,9 +131,9 @@ public class SnarkManager implements Snark.CompleteListener {
     }
     public File getDataDir() { 
         String dir = _config.getProperty(PROP_DIR, "i2psnark");
-        File f = new File(dir);
+        File f = new SecureDirectory(dir);
         if (!f.isAbsolute())
-            f = new File(_context.getAppDir(), dir);
+            f = new SecureDirectory(_context.getAppDir(), dir);
         return f; 
     }
     
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
index 7235507ba6f28c7a25a5b85c824ebbe9af0594a1..5b7fd3529bcd581b828f58bd6aa82ade6dd19c24 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
@@ -18,6 +18,7 @@ import net.i2p.data.Base32;
 import net.i2p.data.Destination;
 import net.i2p.util.I2PAppThread;
 import net.i2p.util.Log;
+import net.i2p.util.SecureFileOutputStream;
 
 /**
  * Coordinate the runtime operation and configuration of a tunnel.  
@@ -84,7 +85,7 @@ public class TunnelController implements Logging {
         }
         FileOutputStream fos = null;
         try {
-            fos = new FileOutputStream(keyFile);
+            fos = new SecureFileOutputStream(keyFile);
             Destination dest = client.createDestination(fos);
             String destStr = dest.toBase64();
             log("Private key created and saved in " + keyFile.getAbsolutePath());
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java
index 112f0d62f06544973445ce97c2e37f023a4a9d5e..7b0c67f707924a469e2f6111b6708a40a3fd38ec 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java
@@ -20,6 +20,7 @@ import net.i2p.client.I2PSessionException;
 import net.i2p.data.DataHelper;
 import net.i2p.util.I2PAppThread;
 import net.i2p.util.Log;
+import net.i2p.util.SecureFileOutputStream;
 
 /**
  * Coordinate a set of tunnels within the JVM, loading and storing their config
@@ -254,7 +255,7 @@ public class TunnelControllerGroup {
         
         FileOutputStream fos = null;
         try {
-            fos = new FileOutputStream(cfgFile);
+            fos = new SecureFileOutputStream(cfgFile);
             fos.write(buf.toString().getBytes("UTF-8"));
             if (_log.shouldLog(Log.INFO))
                 _log.info("Config written to " + cfgFile.getPath());
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java
index b17dfbdade4264f1b98a579c86586e9404b44288..6958b350e9b2f2ccaf2e4126758ab75137f659af 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java
@@ -563,7 +563,7 @@ public class PluginStarter implements Runnable {
     /**
      *  http://jimlife.wordpress.com/2007/12/19/java-adding-new-classpath-at-runtime/
      */
-    public static void addPath(URL u) throws Exception {
+    private static void addPath(URL u) throws Exception {
         URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
         Class urlClass = URLClassLoader.class;
         Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class});
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java
index 26d026a1694eb8bb62ced52827a31fb4b82c989f..38e8f28b00ef014aa859c54b13d40e39b0be6e13 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/PluginUpdateHandler.java
@@ -16,6 +16,7 @@ import net.i2p.util.FileUtil;
 import net.i2p.util.I2PAppThread;
 import net.i2p.util.Log;
 import net.i2p.util.OrderedProperties;
+import net.i2p.util.SecureDirectory;
 import net.i2p.util.SimpleScheduler;
 import net.i2p.util.SimpleTimer;
 import net.i2p.util.VersionComparator;
@@ -150,7 +151,7 @@ public class PluginUpdateHandler extends UpdateHandler {
         public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
             updateStatus("<b>" + _("Plugin downloaded") + "</b>");
             File f = new File(_updateFile);
-            File appDir = new File(_context.getConfigDir(), PLUGIN_DIR);
+            File appDir = new SecureDirectory(_context.getConfigDir(), PLUGIN_DIR);
             if ((!appDir.exists()) && (!appDir.mkdir())) {
                 f.delete();
                 statusDone("<b>" + _("Cannot create plugin directory {0}", appDir.getAbsolutePath()) + "</b>");
@@ -273,7 +274,7 @@ public class PluginUpdateHandler extends UpdateHandler {
                 return;
             }
 
-            File destDir = new File(appDir, appName);
+            File destDir = new SecureDirectory(appDir, appName);
             if (destDir.exists()) {
                 if (Boolean.valueOf(props.getProperty("install-only")).booleanValue()) {
                     to.delete();
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java
index 05bedee374fed8b931d06f3811739f9445e03bfa..68533f7ef63c19cfce8b1b4a7c384b4b90f1b309 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java
@@ -14,6 +14,7 @@ import net.i2p.data.DataHelper;
 import net.i2p.router.RouterContext;
 import net.i2p.util.FileUtil;
 import net.i2p.util.I2PAppThread;
+import net.i2p.util.SecureDirectory;
 
 import org.mortbay.http.DigestAuthenticator;
 import org.mortbay.http.HashUserRealm;
@@ -62,7 +63,7 @@ public class RouterConsoleRunner {
     }
     
     public void startConsole() {
-        File workDir = new File(I2PAppContext.getGlobalContext().getTempDir(), "jetty-work");
+        File workDir = new SecureDirectory(I2PAppContext.getGlobalContext().getTempDir(), "jetty-work");
         boolean workDirRemoved = FileUtil.rmdir(workDir, false);
         if (!workDirRemoved)
             System.err.println("ERROR: Unable to remove Jetty temporary work directory");
@@ -115,7 +116,7 @@ public class RouterConsoleRunner {
             }
             _server.setRootWebApp(ROUTERCONSOLE);
             WebApplicationContext wac = _server.addWebApplication("/", _webAppsDir + ROUTERCONSOLE + ".war");
-            File tmpdir = new File(workDir, ROUTERCONSOLE + "-" + _listenPort);
+            File tmpdir = new SecureDirectory(workDir, ROUTERCONSOLE + "-" + _listenPort);
             tmpdir.mkdir();
             wac.setTempDirectory(tmpdir);
             baseHandler = new LocaleWebAppHandler(I2PAppContext.getGlobalContext());
@@ -130,7 +131,7 @@ public class RouterConsoleRunner {
                         String enabled = props.getProperty(PREFIX + appName + ENABLED);
                         if (! "false".equals(enabled)) {
                             String path = new File(dir, fileNames[i]).getCanonicalPath();
-                            tmpdir = new File(workDir, appName + "-" + _listenPort);
+                            tmpdir = new SecureDirectory(workDir, appName + "-" + _listenPort);
                             WebAppStarter.addWebApp(I2PAppContext.getGlobalContext(), _server, appName, path, tmpdir);
 
                             if (enabled == null) {
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/WebAppStarter.java b/apps/routerconsole/java/src/net/i2p/router/web/WebAppStarter.java
index 0264d6307aa782147051ee26a3d7682e4850114d..1aac8ecc9fe7e3f70be3391c108a7c34666e7809 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/WebAppStarter.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/WebAppStarter.java
@@ -10,6 +10,7 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import net.i2p.I2PAppContext;
 import net.i2p.util.FileUtil;
+import net.i2p.util.SecureDirectory;
 
 import org.mortbay.http.HttpContext;
 import org.mortbay.http.HttpListener;
@@ -41,7 +42,7 @@ public class WebAppStarter {
      *  @throws just about anything, caller would be wise to catch Throwable
      */
     static void startWebApp(I2PAppContext ctx, Server server, String appName, String warPath) throws Exception {
-         File tmpdir = new File(ctx.getTempDir(), "jetty-work-" + appName + ctx.random().nextInt());
+         File tmpdir = new SecureDirectory(ctx.getTempDir(), "jetty-work-" + appName + ctx.random().nextInt());
          WebApplicationContext wac = addWebApp(ctx, server, appName, warPath, tmpdir);
          wac.start();
     }
@@ -73,7 +74,7 @@ public class WebAppStarter {
             warModTimes.put(warPath, new Long(newmod));
         } else if (oldmod.longValue() < newmod) {
             // copy war to temporary directory
-            File warTmpDir = new File(ctx.getTempDir(), "war-copy-" + appName + ctx.random().nextInt());
+            File warTmpDir = new SecureDirectory(ctx.getTempDir(), "war-copy-" + appName + ctx.random().nextInt());
             warTmpDir.mkdir();
             String tmpPath = (new File(warTmpDir, appName + ".war")).getAbsolutePath();
             if (!FileUtil.copy(warPath, tmpPath, true))
diff --git a/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java b/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java
index 63c4db85acb1f61c285ff7b7a2231ee927d552be..b6af8a12dada88fa0d30c0f359f158379d1fc681 100644
--- a/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java
+++ b/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java
@@ -38,6 +38,7 @@ import java.util.Properties;
 import net.i2p.data.DataFormatException;
 import net.i2p.data.DataHelper;
 import net.i2p.data.Destination;
+import net.i2p.util.SecureFileOutputStream;
 
 public class AddressbookBean
 {
@@ -330,7 +331,7 @@ public class AddressbookBean
 	{
 		String filename = properties.getProperty( getBook() + "_addressbook" );
 		
-		FileOutputStream fos = new FileOutputStream( ConfigBean.addressbookPrefix + filename  );
+		FileOutputStream fos = new SecureFileOutputStream( ConfigBean.addressbookPrefix + filename  );
 		addressbook.store( fos, null );
 		try {
 			fos.close();
diff --git a/apps/susidns/src/java/src/i2p/susi/dns/ConfigBean.java b/apps/susidns/src/java/src/i2p/susi/dns/ConfigBean.java
index f6655757d8318977ee667baf4c8cbf013948fb05..ee65753564a0ff961f9432664fdfd5c8444b57bd 100644
--- a/apps/susidns/src/java/src/i2p/susi/dns/ConfigBean.java
+++ b/apps/susidns/src/java/src/i2p/susi/dns/ConfigBean.java
@@ -27,13 +27,13 @@ package i2p.susi.dns;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.Serializable;
 
 import net.i2p.I2PAppContext;
+import net.i2p.util.SecureFileOutputStream;
 
 public class ConfigBean implements Serializable {
 	
@@ -111,7 +111,7 @@ public class ConfigBean implements Serializable {
 	{
 		File file = new File( configFileName );
 		try {
-			PrintWriter out = new PrintWriter( new FileOutputStream( file ) );
+			PrintWriter out = new PrintWriter( new SecureFileOutputStream( file ) );
 			out.print( config );
 			out.flush();
 			out.close();
diff --git a/apps/susidns/src/java/src/i2p/susi/dns/SubscriptionsBean.java b/apps/susidns/src/java/src/i2p/susi/dns/SubscriptionsBean.java
index 6b1a80576999b83406f5de862d881755b6d3f92a..176561acaf16c6934ae7c3a879b46b3f91d2cc63 100644
--- a/apps/susidns/src/java/src/i2p/susi/dns/SubscriptionsBean.java
+++ b/apps/susidns/src/java/src/i2p/susi/dns/SubscriptionsBean.java
@@ -28,12 +28,13 @@ import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.Properties;
 
+import net.i2p.util.SecureFileOutputStream;
+
 public class SubscriptionsBean
 {
 	private String action, fileName, content, serial, lastSerial;
@@ -113,7 +114,7 @@ public class SubscriptionsBean
 	{
 		File file = new File( getFileName() );
 		try {
-			PrintWriter out = new PrintWriter( new FileOutputStream( file ) );
+			PrintWriter out = new PrintWriter( new SecureFileOutputStream( file ) );
 			out.print( content );
 			out.flush();
 			out.close();
diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java
index aac61d4beb63913166384b15c995fa95d43b1cfe..751cbb37aa73c3c5d8960a2e9af21e8fc5ede02d 100644
--- a/core/java/src/net/i2p/I2PAppContext.java
+++ b/core/java/src/net/i2p/I2PAppContext.java
@@ -31,6 +31,7 @@ import net.i2p.util.KeyRing;
 import net.i2p.util.LogManager;
 //import net.i2p.util.PooledRandomSource;
 import net.i2p.util.RandomSource;
+import net.i2p.util.SecureDirectory;
 
 /**
  * <p>Provide a base scope for accessing singletons that I2P exposes.  Rather than
@@ -217,7 +218,7 @@ public class I2PAppContext {
         // config defaults to base
         s = getProperty("i2p.dir.config");
         if (s != null) {
-            _configDir = new File(s);
+            _configDir = new SecureDirectory(s);
             if (!_configDir.exists())
                 _configDir.mkdir();
         } else {
@@ -226,7 +227,7 @@ public class I2PAppContext {
         // router defaults to config
         s = getProperty("i2p.dir.router");
         if (s != null) {
-            _routerDir = new File(s);
+            _routerDir = new SecureDirectory(s);
             if (!_routerDir.exists())
                 _routerDir.mkdir();
         } else {
@@ -240,7 +241,7 @@ public class I2PAppContext {
         // these all default to router
         s = getProperty("i2p.dir.log");
         if (s != null) {
-            _logDir = new File(s);
+            _logDir = new SecureDirectory(s);
             if (!_logDir.exists())
                 _logDir.mkdir();
         } else {
@@ -248,7 +249,7 @@ public class I2PAppContext {
         }
         s = getProperty("i2p.dir.app");
         if (s != null) {
-            _appDir = new File(s);
+            _appDir = new SecureDirectory(s);
             if (!_appDir.exists())
                 _appDir.mkdir();
         } else {
@@ -278,14 +279,14 @@ public class I2PAppContext {
                 String d = getProperty("i2p.dir.temp", System.getProperty("java.io.tmpdir"));
                 // our random() probably isn't warmed up yet
                 String f = "i2p-" + Math.abs((new java.util.Random()).nextInt()) + ".tmp";
-                _tmpDir = new File(d, f);
+                _tmpDir = new SecureDirectory(d, f);
                 if (_tmpDir.exists()) {
                     // good or bad ?
                 } else if (_tmpDir.mkdir()) {
                     _tmpDir.deleteOnExit();
                 } else {
                     System.err.println("Could not create temp dir " + _tmpDir.getAbsolutePath());
-                    _tmpDir = new File(_routerDir, "tmp");
+                    _tmpDir = new SecureDirectory(_routerDir, "tmp");
                     _tmpDir.mkdir();
                 }
             }
diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java
index 07997fd105eb5fc2a86e05aca360c0e40daa1526..6ac316ee9d1278b4ba400f803269a51f376539b6 100644
--- a/core/java/src/net/i2p/data/DataHelper.java
+++ b/core/java/src/net/i2p/data/DataHelper.java
@@ -17,7 +17,6 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -42,6 +41,7 @@ import net.i2p.util.ByteCache;
 import net.i2p.util.OrderedProperties;
 import net.i2p.util.ReusableGZIPInputStream;
 import net.i2p.util.ReusableGZIPOutputStream;
+import net.i2p.util.SecureFileOutputStream;
 
 /**
  * Defines some simple IO routines for dealing with marshalling data structures
@@ -304,11 +304,12 @@ public class DataHelper {
     /**
      * Writes the props to the file, unsorted (unless props is an OrderedProperties)
      * Note that this does not escape the \r or \n that are unescaped in loadProps() above.
+     * As of 0.8.1, file will be mode 600.
      */
     public static void storeProps(Properties props, File file) throws IOException {
         PrintWriter out = null;
         try {
-            out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")));
+            out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(file), "UTF-8")));
             out.println("# NOTE: This I2P config file must use UTF-8 encoding");
             for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
                 String name = (String)iter.next();
diff --git a/core/java/src/net/i2p/util/LogWriter.java b/core/java/src/net/i2p/util/LogWriter.java
index b15aa6cfbb723720958237b4ba5640b16cfb94dc..7dca7ba96dc75cdfe8d045491ee241baeda61aa7 100644
--- a/core/java/src/net/i2p/util/LogWriter.java
+++ b/core/java/src/net/i2p/util/LogWriter.java
@@ -11,7 +11,6 @@ package net.i2p.util;
 
 import java.io.BufferedWriter;
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
@@ -158,7 +157,8 @@ class LogWriter implements Runnable {
         File parent = f.getParentFile();
         if (parent != null) {
             if (!parent.exists()) {
-                boolean ok = parent.mkdirs();
+                File sd = new SecureDirectory(parent.getAbsolutePath());
+                boolean ok = sd.mkdirs();
                 if (!ok) {
                     System.err.println("Unable to create the parent directory: " + parent.getAbsolutePath());
                     //System.exit(0);
@@ -171,7 +171,7 @@ class LogWriter implements Runnable {
         }
         closeFile();
         try {
-            _currentOut = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), "UTF-8"));
+            _currentOut = new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(f), "UTF-8"));
         } catch (IOException ioe) {
             System.err.println("Error rotating into [" + f.getAbsolutePath() + "]" + ioe);
         }
diff --git a/core/java/src/net/i2p/util/RandomSource.java b/core/java/src/net/i2p/util/RandomSource.java
index c6ac80a65ca63f6410b178098d2933928e2c3a7a..100ec47d736c8406b5d23a968384216fa88c000e 100644
--- a/core/java/src/net/i2p/util/RandomSource.java
+++ b/core/java/src/net/i2p/util/RandomSource.java
@@ -145,7 +145,7 @@ public class RandomSource extends SecureRandom implements EntropyHarvester {
         File f = new File(I2PAppContext.getGlobalContext().getConfigDir(), SEEDFILE);
         FileOutputStream fos = null;
         try {
-            fos = new FileOutputStream(f);
+            fos = new SecureFileOutputStream(f);
             fos.write(buf);
         } catch (IOException ioe) {
             // ignore
diff --git a/core/java/src/net/i2p/util/SecureDirectory.java b/core/java/src/net/i2p/util/SecureDirectory.java
index 393e118865cc91a7e9005b715bcae82ca5e93eec..30d609e96fb70d50c1c206e8005ff0024623d92a 100644
--- a/core/java/src/net/i2p/util/SecureDirectory.java
+++ b/core/java/src/net/i2p/util/SecureDirectory.java
@@ -38,6 +38,18 @@ public class SecureDirectory extends File {
         return rv;
     }
 
+    /**
+     *  Sets directory to mode 700 if the directory is created
+     *  Does NOT change the mode of other created directories
+     */
+    @Override
+    public boolean mkdirs() {
+        boolean rv = super.mkdirs();
+        if (rv)
+            setPerms();
+        return rv;
+    }
+
     /**
      *  Tries to set the permissions to 700,
      *  ignores errors
diff --git a/router/java/src/net/i2p/router/KeyManager.java b/router/java/src/net/i2p/router/KeyManager.java
index 4d19228b7208c16a177770fcfb490cb7acf62cf2..fd0e85a9eb6f31cefeac96dbc5cff92e4bc22564 100644
--- a/router/java/src/net/i2p/router/KeyManager.java
+++ b/router/java/src/net/i2p/router/KeyManager.java
@@ -27,6 +27,8 @@ import net.i2p.data.SigningPrivateKey;
 import net.i2p.data.SigningPublicKey;
 import net.i2p.util.Clock;
 import net.i2p.util.Log;
+import net.i2p.util.SecureDirectory;
+import net.i2p.util.SecureFileOutputStream;
 
 /**
  * Maintain all of the key pairs for the router.
@@ -142,7 +144,7 @@ public class KeyManager {
         }
         public void runJob() {
             String keyDir = getContext().getProperty(PROP_KEYDIR, DEFAULT_KEYDIR);
-            File dir = new File(getContext().getRouterDir(), keyDir);
+            File dir = new SecureDirectory(getContext().getRouterDir(), keyDir);
             if (!dir.exists())
                 dir.mkdirs();
             if (dir.exists() && dir.isDirectory() && dir.canRead() && dir.canWrite()) {
@@ -219,7 +221,7 @@ public class KeyManager {
             FileInputStream in = null;
             try {
                 if (exists) {
-                    out = new FileOutputStream(keyFile);
+                    out = new SecureFileOutputStream(keyFile);
                     structure.writeBytes(out);
                     return structure;
                 } else {
diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index 0651e35d261465bb41c27462b9ba291c404f34da..a091cba13451c44d9d3c62b98a198a5f69e1a7ac 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -46,6 +46,7 @@ import net.i2p.util.FileUtil;
 import net.i2p.util.I2PAppThread;
 import net.i2p.util.I2PThread;
 import net.i2p.util.Log;
+import net.i2p.util.SecureFileOutputStream;
 import net.i2p.util.SimpleScheduler;
 import net.i2p.util.SimpleTimer;
 
@@ -305,6 +306,7 @@ public class Router {
     public void setHigherVersionSeen(boolean seen) { _higherVersionSeen = seen; }
     
     public long getWhenStarted() { return _started; }
+
     /** wall clock uptime */
     public long getUptime() { 
         if ( (_context == null) || (_context.clock() == null) ) return 1; // racing on startup
@@ -1053,11 +1055,12 @@ public class Router {
      * this does escape the \r or \n that are unescaped in DataHelper.loadProps().
      * Note that the escaping of \r or \n was probably a mistake and should be taken out.
      *
+     * FIXME Synchronize!!
      */
     public boolean saveConfig() {
         FileOutputStream fos = null;
         try {
-            fos = new FileOutputStream(_configFilename);
+            fos = new SecureFileOutputStream(_configFilename);
             StringBuilder buf = new StringBuilder(8*1024);
             buf.append("# NOTE: This I2P config file must use UTF-8 encoding\n");
             synchronized (_config) {
@@ -1541,7 +1544,7 @@ private static class PersistRouterInfoJob extends JobImpl {
 
         FileOutputStream fos = null;
         try {
-            fos = new FileOutputStream(infoFile);
+            fos = new SecureFileOutputStream(infoFile);
             info.writeBytes(fos);
         } catch (DataFormatException dfe) {
             _log.error("Error rebuilding the router information", dfe);
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java
index 77ea8c4573136b0c58b402927c110b209f846b97..0172dfcc6907a5b54923498cfcd4364877d587bc 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java
@@ -29,6 +29,8 @@ import net.i2p.router.RouterContext;
 import net.i2p.router.networkdb.reseed.ReseedChecker;
 import net.i2p.util.I2PThread;
 import net.i2p.util.Log;
+import net.i2p.util.SecureDirectory;
+import net.i2p.util.SecureFileOutputStream;
 
 /**
  * Write out keys to disk when we get them and periodically read ones we don't know
@@ -288,7 +290,7 @@ class PersistentDataStore extends TransientDataStore {
             long dataPublishDate = getPublishDate(data);
             if (dbFile.lastModified() < dataPublishDate) {
                 // our filesystem is out of date, lets replace it
-                fos = new FileOutputStream(dbFile);
+                fos = new SecureFileOutputStream(dbFile);
                 try {
                     data.writeBytes(fos);
                     fos.close();
@@ -440,7 +442,7 @@ class PersistentDataStore extends TransientDataStore {
     
     
     private File getDbDir() throws IOException {
-        File f = new File(_context.getRouterDir(), _dbDir);
+        File f = new SecureDirectory(_context.getRouterDir(), _dbDir);
         if (!f.exists()) {
             boolean created = f.mkdirs();
             if (!created)
diff --git a/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java b/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java
index 29fce33a6cb18e1664b2f61efff98151c36c0089..21870341e74aba73ebaf8823d03fd1e085a72097 100644
--- a/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java
+++ b/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java
@@ -17,6 +17,8 @@ import net.i2p.router.RouterContext;
 import net.i2p.util.EepGet;
 import net.i2p.util.I2PAppThread;
 import net.i2p.util.Log;
+import net.i2p.util.SecureDirectory;
+import net.i2p.util.SecureFileOutputStream;
 import net.i2p.util.SSLEepGet;
 import net.i2p.util.Translate;
 
@@ -261,11 +263,11 @@ public class Reseeder {
     
         private void writeSeed(String name, byte data[]) throws Exception {
             String dirName = "netDb"; // _context.getProperty("router.networkDatabase.dbDir", "netDb");
-            File netDbDir = new File(_context.getRouterDir(), dirName);
+            File netDbDir = new SecureDirectory(_context.getRouterDir(), dirName);
             if (!netDbDir.exists()) {
                 boolean ok = netDbDir.mkdirs();
             }
-            FileOutputStream fos = new FileOutputStream(new File(netDbDir, "routerInfo-" + name + ".dat"));
+            FileOutputStream fos = new SecureFileOutputStream(new File(netDbDir, "routerInfo-" + name + ".dat"));
             fos.write(data);
             fos.close();
         }
diff --git a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java
index 606b4883cf288f4e7a905aa67df81a3fd7bf2456..610dfec4f8a26eb01f07a781b483bf180105a43b 100644
--- a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java
+++ b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java
@@ -3,7 +3,6 @@ package net.i2p.router.peermanager;
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.FilenameFilter;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -19,6 +18,8 @@ import net.i2p.data.DataHelper;
 import net.i2p.data.Hash;
 import net.i2p.router.RouterContext;
 import net.i2p.util.Log;
+import net.i2p.util.SecureDirectory;
+import net.i2p.util.SecureFileOutputStream;
 
 class ProfilePersistenceHelper {
     private Log _log;
@@ -61,7 +62,7 @@ class ProfilePersistenceHelper {
         long before = _context.clock().now();
         OutputStream fos = null;
         try {
-            fos = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(f)));
+            fos = new BufferedOutputStream(new GZIPOutputStream(new SecureFileOutputStream(f)));
             writeProfile(profile, fos);
         } catch (IOException ioe) {
             _log.error("Error writing profile to " + f);
@@ -310,7 +311,7 @@ class ProfilePersistenceHelper {
     private File getProfileDir() {
         if (_profileDir == null) {
             String dir = _context.getProperty(PROP_PEER_PROFILE_DIR, DEFAULT_PEER_PROFILE_DIR);
-            _profileDir = new File(_context.getRouterDir(), dir);
+            _profileDir = new SecureDirectory(_context.getRouterDir(), dir);
         }
         return _profileDir;
     }
diff --git a/router/java/src/net/i2p/router/startup/ClientAppConfig.java b/router/java/src/net/i2p/router/startup/ClientAppConfig.java
index 982d4a298c4987bc5bdebe601f5f19c4fe4c0d36..33f4351fefcc06754d57bad86465cdb25b76bb89 100644
--- a/router/java/src/net/i2p/router/startup/ClientAppConfig.java
+++ b/router/java/src/net/i2p/router/startup/ClientAppConfig.java
@@ -11,6 +11,7 @@ import java.util.Properties;
 import net.i2p.I2PAppContext;
 import net.i2p.data.DataHelper;
 import net.i2p.router.RouterContext;
+import net.i2p.util.SecureFileOutputStream;
 
 
 /**
@@ -191,7 +192,7 @@ public class ClientAppConfig {
         File cfgFile = configFile(ctx);
         FileOutputStream fos = null;
         try {
-            fos = new FileOutputStream(cfgFile);
+            fos = new SecureFileOutputStream(cfgFile);
             StringBuilder buf = new StringBuilder(2048);
             for(int i = 0; i < apps.size(); i++) {
                 ClientAppConfig app = (ClientAppConfig) apps.get(i);
diff --git a/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java b/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java
index 459cd0fb3ae2a8d07959a34cd208efb562cd1124..36b989bc7761609ab28b9bf3d83a3b994432d27a 100644
--- a/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java
+++ b/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java
@@ -27,6 +27,7 @@ import net.i2p.router.JobImpl;
 import net.i2p.router.Router;
 import net.i2p.router.RouterContext;
 import net.i2p.util.Log;
+import net.i2p.util.SecureFileOutputStream;
 
 public class CreateRouterInfoJob extends JobImpl {
     private static Log _log = new Log(CreateRouterInfoJob.class);
@@ -80,12 +81,12 @@ public class CreateRouterInfoJob extends JobImpl {
             
             String infoFilename = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
             File ifile = new File(getContext().getRouterDir(), infoFilename);
-            fos1 = new FileOutputStream(ifile);
+            fos1 = new SecureFileOutputStream(ifile);
             info.writeBytes(fos1);
             
             String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT);
             File kfile = new File(getContext().getRouterDir(), keyFilename);
-            fos2 = new FileOutputStream(kfile);
+            fos2 = new SecureFileOutputStream(kfile);
             privkey.writeBytes(fos2);
             signingPrivKey.writeBytes(fos2);
             pubkey.writeBytes(fos2);
diff --git a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java
index e3daf60ea44d7fec76f55b3b11eef195c44d1936..b417c32bbb3343ed72f34dae41f0d7399a32343c 100644
--- a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java
+++ b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java
@@ -26,6 +26,7 @@ import net.i2p.router.JobImpl;
 import net.i2p.router.Router;
 import net.i2p.router.RouterContext;
 import net.i2p.util.Log;
+import net.i2p.util.SecureFileOutputStream;
 
 /**
  * This used be called from StartAcceptingClientsJob but is now disabled.
@@ -135,7 +136,7 @@ public class RebuildRouterInfoJob extends JobImpl {
             
             FileOutputStream fos = null;
             try {
-                fos = new FileOutputStream(infoFile);
+                fos = new SecureFileOutputStream(infoFile);
                 info.writeBytes(fos);
             } catch (DataFormatException dfe) {
                 _log.log(Log.CRIT, "Error rebuilding the router information", dfe);
diff --git a/router/java/src/net/i2p/router/startup/WorkingDir.java b/router/java/src/net/i2p/router/startup/WorkingDir.java
index 545239777fedf09d15a4706dacd5683a62083308..0b32c661f0ddce616cb77f0e184006375088afdf 100644
--- a/router/java/src/net/i2p/router/startup/WorkingDir.java
+++ b/router/java/src/net/i2p/router/startup/WorkingDir.java
@@ -11,6 +11,8 @@ import java.io.PrintWriter;
 import java.util.Properties;
 
 import net.i2p.data.DataHelper;
+import net.i2p.util.SecureDirectory;
+import net.i2p.util.SecureFileOutputStream;
 
 /**
  * Get a working directory for i2p.
@@ -64,19 +66,19 @@ public class WorkingDir {
         boolean isWindows = System.getProperty("os.name").startsWith("Win");
         File dirf = null;
         if (dir != null) {
-            dirf = new File(dir);
+            dirf = new SecureDirectory(dir);
         } else {
             String home = System.getProperty("user.home");
             if (isWindows) {
                 String appdata = System.getenv("APPDATA");
                 if (appdata != null)
                     home = appdata;
-                dirf = new File(home, WORKING_DIR_DEFAULT_WINDOWS);
+                dirf = new SecureDirectory(home, WORKING_DIR_DEFAULT_WINDOWS);
             } else {
                 if (DAEMON_USER.equals(System.getProperty("user.name")))
-                    dirf = new File(home, WORKING_DIR_DEFAULT_DAEMON);
+                    dirf = new SecureDirectory(home, WORKING_DIR_DEFAULT_DAEMON);
                 else
-                    dirf = new File(home, WORKING_DIR_DEFAULT);
+                    dirf = new SecureDirectory(home, WORKING_DIR_DEFAULT);
             }
         }
 
@@ -143,7 +145,7 @@ public class WorkingDir {
         // this one must be after MIGRATE_BASE
         success &= migrateJettyXml(oldDirf, dirf);
         success &= migrateClientsConfig(oldDirf, dirf);
-        success &= copy(new File(oldDirf, "docs/news.xml"), new File(dirf, "docs"));
+        success &= copy(new File(oldDirf, "docs/news.xml"), new SecureDirectory(dirf, "docs"));
 
         // Report success or failure
         if (success) {
@@ -197,7 +199,7 @@ public class WorkingDir {
         PrintWriter out = null;
         try {
             in = new FileInputStream(oldFile);
-            out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(newFile), "UTF-8")));
+            out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(newFile), "UTF-8")));
             out.println("# Modified by I2P User dir migration script");
             String s = null;
             boolean isDaemon = DAEMON_USER.equals(System.getProperty("user.name"));
@@ -240,7 +242,7 @@ public class WorkingDir {
         PrintWriter out = null;
         try {
             in = new FileInputStream(oldFile);
-            out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(newFile), "UTF-8")));
+            out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(newFile), "UTF-8")));
             String s = null;
             while ((s = DataHelper.readLine(in)) != null) {
                 if (s.indexOf("./eepsite/") >= 0) {
@@ -270,7 +272,7 @@ public class WorkingDir {
      * @param targetDir the directory to copy to, will be created if it doesn't exist
      * @return true for success OR if src does not exist
      */
-    public static final boolean copy(File src, File targetDir) {
+    private static boolean copy(File src, File targetDir) {
         if (!src.exists())
             return true;
         if (!targetDir.exists()) {
@@ -280,7 +282,8 @@ public class WorkingDir {
             }
             System.err.println("Created " + targetDir.getPath());
         }
-        File targetFile = new File(targetDir, src.getName());
+        // SecureDirectory is a File so this works for non-directories too
+        File targetFile = new SecureDirectory(targetDir, src.getName());
         if (!src.isDirectory())
             return copyFile(src, targetFile);
         File children[] = src.listFiles();
@@ -305,10 +308,10 @@ public class WorkingDir {
     
     /**
      * @param src not a directory, must exist
-     * @param dst not a directory, will be overwritten if existing
+     * @param dst not a directory, will be overwritten if existing, will be mode 600
      * @return true if it was copied successfully
      */
-    public static boolean copyFile(File src, File dst) {
+    private static boolean copyFile(File src, File dst) {
         if (!src.exists()) return false;
         boolean rv = true;
 
@@ -317,7 +320,7 @@ public class WorkingDir {
         FileOutputStream out = null;
         try {
             in = new FileInputStream(src);
-            out = new FileOutputStream(dst);
+            out = new SecureFileOutputStream(dst);
             
             int read = 0;
             while ( (read = in.read(buf)) != -1)