Last active
          December 11, 2016 22:23 
        
      - 
      
- 
        Save rzwitserloot/099fbdc706a2a0302b3b98479e9b7eab to your computer and use it in GitHub Desktop. 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | 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