From 51d700f6fe634d092adb3f238caf429a2d4c4dc7 Mon Sep 17 00:00:00 2001 From: Jonathan Cobb Date: Thu, 6 Aug 2020 01:20:47 -0400 Subject: [PATCH] add rand_ip handlebars helper --- .../cobbzilla/util/daemon/ZillaRuntime.java | 18 +++++++- .../util/handlebars/HandlebarsUtil.java | 44 ++++++++++++++++++- .../cobbzilla/util/network/NetworkUtil.java | 24 +++++++++- .../util/security/bcrypt/BCrypt.java | 4 +- .../util/security/bcrypt/BCryptUtil.java | 6 +-- 5 files changed, 87 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/cobbzilla/util/daemon/ZillaRuntime.java b/src/main/java/org/cobbzilla/util/daemon/ZillaRuntime.java index 3c28d0e..ecc5b28 100644 --- a/src/main/java/org/cobbzilla/util/daemon/ZillaRuntime.java +++ b/src/main/java/org/cobbzilla/util/daemon/ZillaRuntime.java @@ -21,6 +21,7 @@ import java.lang.reflect.Array; import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; +import java.security.SecureRandom; import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicLong; @@ -31,6 +32,7 @@ import static java.lang.Long.toHexString; import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.stream.LongStream.range; import static org.apache.commons.collections.CollectionUtils.collect; +import static org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric; import static org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace; import static org.cobbzilla.util.error.ExceptionHandler.DEFAULT_EX_RUNNABLE; import static org.cobbzilla.util.io.FileUtil.abs; @@ -291,6 +293,17 @@ public class ZillaRuntime { public static BigInteger bigint(int val) { return new BigInteger(String.valueOf(val)); } public static BigInteger bigint(byte val) { return new BigInteger(String.valueOf(val)); } + public static BigInteger random_bigint(BigInteger limit) { return random_bigint(limit, RANDOM); } + + // adapted from https://stackoverflow.com/a/2290089/1251543 + public static BigInteger random_bigint(BigInteger limit, SecureRandom rand) { + BigInteger randomNumber; + do { + randomNumber = new BigInteger(limit.bitLength(), rand); + } while (randomNumber.compareTo(limit) >= 0); + return randomNumber; + } + public static BigDecimal big(String val) { return new BigDecimal(val); } public static BigDecimal big(double val) { return new BigDecimal(String.valueOf(val)); } public static BigDecimal big(float val) { return new BigDecimal(String.valueOf(val)); } @@ -310,7 +323,10 @@ public class ZillaRuntime { public static String uuid() { return UUID.randomUUID().toString(); } - private static AtomicLong systemTimeOffset = new AtomicLong(0L); + private static final AtomicLong systemTimeOffset = new AtomicLong(0L); + + public static final SecureRandom RANDOM = new SecureRandom((randomAlphanumeric(20)+now()).getBytes()); + public static long getSystemTimeOffset () { return systemTimeOffset.get(); } public static void setSystemTimeOffset (long t) { systemTimeOffset.set(t); } public static long incrementSystemTimeOffset(long t) { return systemTimeOffset.addAndGet(t); } diff --git a/src/main/java/org/cobbzilla/util/handlebars/HandlebarsUtil.java b/src/main/java/org/cobbzilla/util/handlebars/HandlebarsUtil.java index e2f56bb..ad81dc6 100644 --- a/src/main/java/org/cobbzilla/util/handlebars/HandlebarsUtil.java +++ b/src/main/java/org/cobbzilla/util/handlebars/HandlebarsUtil.java @@ -43,13 +43,16 @@ import java.io.IOException; import java.io.StringWriter; import java.lang.reflect.Method; import java.math.BigDecimal; +import java.math.BigInteger; import java.math.MathContext; +import java.net.InetAddress; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; import static java.util.regex.Pattern.quote; +import static org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric; import static org.cobbzilla.util.collection.ArrayUtil.arrayToString; import static org.cobbzilla.util.daemon.DaemonThreadFactory.fixedPool; import static org.cobbzilla.util.daemon.ZillaRuntime.*; @@ -59,6 +62,8 @@ import static org.cobbzilla.util.io.StreamUtil.loadResourceAsStream; import static org.cobbzilla.util.io.StreamUtil.stream2string; import static org.cobbzilla.util.json.JsonUtil.getJsonStringEncoder; import static org.cobbzilla.util.json.JsonUtil.json; +import static org.cobbzilla.util.network.NetworkUtil.big2ip4; +import static org.cobbzilla.util.network.NetworkUtil.big2ip6; import static org.cobbzilla.util.security.ShaUtil.sha256_hex; import static org.cobbzilla.util.string.Base64.encodeBytes; import static org.cobbzilla.util.string.Base64.encodeFromFile; @@ -508,12 +513,43 @@ public class HandlebarsUtil extends AbstractTemplateLoader { final String kind = options.param(0, "alphanumeric"); final String alphaCase = options.param(1, "lowercase"); switch (kind) { - case "alphanumeric": case "alnum": default: return new Handlebars.SafeString(adjustCase(RandomStringUtils.randomAlphanumeric(len), alphaCase)); + case "alphanumeric": case "alnum": default: return new Handlebars.SafeString(adjustCase(randomAlphanumeric(len), alphaCase)); case "alpha": case "alphabetic": return new Handlebars.SafeString(adjustCase(RandomStringUtils.randomAlphabetic(len), alphaCase)); case "num": case "numeric": return new Handlebars.SafeString(RandomStringUtils.randomNumeric(len)); } }); + hb.registerHelper("rand_ip", (Helper) (cidr, options) -> { + final String seed = options.param(0, null); + final int slashPos = cidr.indexOf("/"); + if (slashPos == -1 || slashPos == cidr.length()-1) return die("rand_ip: invalid cidr: "+cidr); + final int fixedBits = Integer.parseInt(cidr.substring(slashPos+1)); + final String network = cidr.substring(0, slashPos); + final InetAddress addr = InetAddress.getByName(network); + final BigInteger addrInt = new BigInteger(1, addr.getAddress()); + final boolean v6 = cidr.contains(":"); + final int randBits = (v6 ? 128 : 32) - fixedBits; + final BigInteger offset = seed == null + ? random_bigint(bigint(2).pow(randBits)) + : new BigInteger(sha256_hex(parseRandSeed(seed)), 16).and(new BigInteger("1".repeat(randBits), 2)); + final BigInteger randIpInt = addrInt.add(offset); + String randAddr = (v6 ? big2ip6(randIpInt) : big2ip4(randIpInt)).toString(); + if (v6) { + // coerce oddball to :1 + if (randAddr.endsWith("::")) { + randAddr = randAddr.substring(0, randAddr.lastIndexOf("::")) + ":1"; + } else if (randAddr.endsWith(":0") || randAddr.endsWith(":0000") || randAddr.endsWith(":ffff")) { + randAddr = randAddr.substring(0, randAddr.lastIndexOf(":")) + ":1"; + } + } else { + if (randAddr.endsWith(".0") || randAddr.endsWith(".255")) { + // coerce oddball to .1 + randAddr = randAddr.substring(0, randAddr.lastIndexOf(".")) + ".1"; + } + } + return new Handlebars.SafeString(randAddr); + }); + hb.registerHelper("truncate", (Helper) (max, options) -> { final String val = options.param(0, " "); if (empty(val)) return ""; @@ -599,6 +635,12 @@ public class HandlebarsUtil extends AbstractTemplateLoader { }); } + public static String parseRandSeed(String seed) { + if (seed.equals("!host")) return hostname(); + if (seed.equals("!domain")) return domainname(); + return seed; + } + private static String adjustCase(String val, String alphaCase) { switch (alphaCase) { case "lower": case "lowercase": case "lc": return val.toLowerCase(); diff --git a/src/main/java/org/cobbzilla/util/network/NetworkUtil.java b/src/main/java/org/cobbzilla/util/network/NetworkUtil.java index ccc7eba..778c07a 100644 --- a/src/main/java/org/cobbzilla/util/network/NetworkUtil.java +++ b/src/main/java/org/cobbzilla/util/network/NetworkUtil.java @@ -8,8 +8,8 @@ import org.cobbzilla.util.io.FileUtil; import java.io.File; import java.io.IOException; -import java.net.InetAddress; -import java.net.NetworkInterface; +import java.math.BigInteger; +import java.net.*; import java.util.*; import java.util.stream.Collectors; @@ -217,6 +217,26 @@ public class NetworkUtil { } } + // adapted from https://stackoverflow.com/a/19238983/1251543 + public static Inet6Address big2ip6(BigInteger ipNumber) throws UnknownHostException { + String ipString = ""; + final BigInteger a = new BigInteger("FFFF", 16); + for (int i=0; i<8; i++) { + ipString = ipNumber.and(a).toString(16)+":"+ipString; + ipNumber = ipNumber.shiftRight(16); + } + return (Inet6Address) Inet6Address.getByName(ipString.substring(0, ipString.length()-1)); + } + public static Inet4Address big2ip4(BigInteger ipNumber) throws UnknownHostException { + String ipString = ""; + final BigInteger a = new BigInteger("FF", 16); + for (int i=0; i<4; i++) { + ipString = ipNumber.and(a).toString(10)+"."+ipString; + ipNumber = ipNumber.shiftRight(8); + } + return (Inet4Address) Inet4Address.getByName(ipString.substring(0, ipString.length()-1)); + } + public static Set toHostSet(File file) throws IOException { return toHostSet(FileUtil.toStringList(file)); } diff --git a/src/main/java/org/cobbzilla/util/security/bcrypt/BCrypt.java b/src/main/java/org/cobbzilla/util/security/bcrypt/BCrypt.java index c718b61..ff3f9f3 100644 --- a/src/main/java/org/cobbzilla/util/security/bcrypt/BCrypt.java +++ b/src/main/java/org/cobbzilla/util/security/bcrypt/BCrypt.java @@ -18,6 +18,8 @@ import java.io.UnsupportedEncodingException; import java.security.SecureRandom; +import static org.cobbzilla.util.daemon.ZillaRuntime.RANDOM; + /** * BCrypt implements OpenBSD-style Blowfish password hashing using * the scheme described in "A Future-Adaptable Password Scheme" by @@ -726,7 +728,7 @@ public class BCrypt { * @return an encoded salt value */ public static String gensalt(int log_rounds) { - return gensalt(log_rounds, new SecureRandom()); + return gensalt(log_rounds, RANDOM); } /** diff --git a/src/main/java/org/cobbzilla/util/security/bcrypt/BCryptUtil.java b/src/main/java/org/cobbzilla/util/security/bcrypt/BCryptUtil.java index 3993373..d32102c 100644 --- a/src/main/java/org/cobbzilla/util/security/bcrypt/BCryptUtil.java +++ b/src/main/java/org/cobbzilla/util/security/bcrypt/BCryptUtil.java @@ -2,13 +2,11 @@ package org.cobbzilla.util.security.bcrypt; import lombok.extern.slf4j.Slf4j; -import java.security.SecureRandom; +import static org.cobbzilla.util.daemon.ZillaRuntime.RANDOM; @Slf4j public class BCryptUtil { - private static final SecureRandom random = new SecureRandom(); - private static volatile Integer bcryptRounds = null; public synchronized static void setBcryptRounds(int rounds) { @@ -23,7 +21,7 @@ public class BCryptUtil { public static Integer getBcryptRounds() { return bcryptRounds; } public static String hash(String password) { - return BCrypt.hashpw(password, BCrypt.gensalt(getBcryptRounds(), random)); + return BCrypt.hashpw(password, BCrypt.gensalt(getBcryptRounds(), RANDOM)); } public static void main (String[] args) {