Skip to content

Instantly share code, notes, and snippets.

@rzwitserloot
Last active December 11, 2016 22:23
Show Gist options
  • Save rzwitserloot/099fbdc706a2a0302b3b98479e9b7eab to your computer and use it in GitHub Desktop.
Save rzwitserloot/099fbdc706a2a0302b3b98479e9b7eab to your computer and use it in GitHub Desktop.
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.SecureRandom;
import java.util.Random;
import lombok.NonNull;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
@UtilityClass
public class Security {
private final Random RANDOM = new SecureRandom();
public String bytesToHexNibbles(@NonNull byte[] in, boolean spaceSeparated) {
if (in.length == 0) return "";
StringBuilder out = new StringBuilder(in.length * 2 + (spaceSeparated ? in.length - 1 : 0));
for (int i = 0; i < in.length; i++) {
if (spaceSeparated && out.length() > 0) out.append(' ');
out.append(String.format("%02X", in[i]));
}
return out.toString();
}
public byte[] hexNibblesToBytes(@NonNull String in) {
in = in.replaceAll("\\s+", "");
if (in.length() == 0) return new byte[0];
if ((in.length() & 1) != 0) throw new IllegalArgumentException("Expected an even number of (non-space) characters.");
byte[] out = new byte[in.length() / 2];
int s = 0;
for (int i = 0; i < in.length(); i++) {
int v = in.charAt(i);
if (v >= '0' && v <= '9') v -= '0';
else if (v >= 'A' && v <= 'F') v = v - 'A' + 10;
else if (v >= 'a' && v <= 'f') v = v - 'a' + 10;
else throw new IllegalArgumentException("Expected a hex nibble (0-9, A-F).");
if ((i & 1) == 0) s = v << 4;
else out[i / 2] = (byte) (s + v);
}
return out;
}
private final class Storage {
private static byte[] SYSTEM_KEY;
static {
SYSTEM_KEY = loadSystemKey();
}
@SneakyThrows(IOException.class)
private static byte[] loadSystemKey() {
Path keyFile = Paths.get(HomeFinder.homeDir(Security.class), "server.key");
if (!Files.isRegularFile(keyFile)) throw throwServerKeyFileProblem(keyFile, "file is missing");
String raw = new String(Files.readAllBytes(keyFile), StandardCharsets.UTF_8);
byte[] res = hexNibblesToBytes(raw);
if (res.length != 32) throw throwServerKeyFileProblem(keyFile, "file is not properly formatted (expected 64 hex digits).");
return res;
}
private static RuntimeException throwServerKeyFileProblem(Path keyFile, String msg) throws IOException {
byte[] rnd = new byte[32];
RANDOM.nextBytes(rnd);
throw new IOException(String.format("Problem with server.key: %s\nPaste this content into file %s and restart the server:\n%s",
msg,
keyFile.toAbsolutePath().toString(),
bytesToHexNibbles(rnd, true)
));
}
}
@SneakyThrows
public final byte[] getSystemKey() throws IOException {
try {
return Storage.SYSTEM_KEY;
} catch (ExceptionInInitializerError e) {
Throwable cause = e.getCause();
throw cause == null ? e : cause;
}
}
public void main(String[] args) throws IOException {
System.out.println("The system key is: " + bytesToHexNibbles(getSystemKey(), true));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment