001package com.bitbucket.thinbus.srp6.js;
002
003import java.math.BigInteger;
004import java.nio.charset.Charset;
005import java.nio.file.Files;
006import java.nio.file.Paths;
007import java.security.MessageDigest;
008import java.util.ArrayList;
009import java.util.List;
010import java.util.regex.Matcher;
011import java.util.regex.Pattern;
012
013import com.nimbusds.srp6.SRP6Routines;
014
015/**
016 * A class to parse the output of 'openssl dhparam -text bits' where bits is the
017 * prime number bit length. Will output 'N', 'g', 'k' in bases 10, 10, 16
018 * respectively. Note that k is derived from 'N' and 'g' but Nimbus 1.4.x
019 * currently uses a the byte array constructor of BigInteger to computes 'k'
020 * which is not available in Javascript so the value genenerated by Java needs
021 * to be configure in the Javascript.
022 */
023public class OpenSSLCryptoConfigConverter {
024
025        public List<String> run(String hash, List<String> lines) throws Exception {
026                int generator = 0;
027                StringBuilder hexparts = new StringBuilder();
028
029                for (String line : lines) {
030                        if (line.endsWith("prime:")) {
031                                // skip this one
032                        } else if (line.endsWith(":")) {
033                                hexparts.append(line.trim());
034                        } else if (line.contains("generator")) {
035                                try {
036                                        generator = generator(line.trim());
037                                } catch (Exception e) {
038                                        throw new AssertionError(
039                                                        "could not parse 'generator: x' number out of line containing 'generator': "
040                                                                        + line);
041                                }
042                        }
043                }
044
045                if (generator <= 0) {
046                        throw new AssertionError(
047                                        "could not parse 'generator: x' number out of line containing 'generator'");
048                }
049
050                String primeHex = hexparts.toString().replace(":", "");
051
052                List<String> output = new ArrayList<String>();
053
054                BigInteger N = new BigInteger(primeHex, 16);
055                BigInteger g = new BigInteger(generator + "");
056
057                output.add("hashing to create 'k' using " + hash);
058
059                MessageDigest digest = MessageDigest.getInstance(hash);
060                BigInteger k = SRP6Routines.computeK(digest, N, g);
061
062                output.add("computing...");
063                output.add("N base10: " + N.toString(10));
064                output.add("g base10: " + g.toString(10));
065                output.add("k base16: " + k.toString(16));
066
067                return output;
068        }
069
070        public static void main(String[] args) throws Exception {
071
072                if (args.length != 2) {
073                        System.err.println("Arguments: file hash ");
074                        System.err.println("Example  : /tmp/my_dhparam.txt SHA-256 ");
075                        System.exit(1);
076                }
077
078                final String file = args[0];
079                final String hash = args[1];
080
081                System.out
082                                .println(String
083                                                .format("Attempting to load 'openssl dhparam -text <bitlength>' output text file at: %s",
084                                                                file));
085
086                final List<String> lines = Files.readAllLines(Paths.get(args[0]),
087                                Charset.forName("UTF8"));
088
089                System.out.println(String.format("Loaded %s lines.", lines.size()));
090
091                System.out.println(String.format(
092                                "Creating configuration parmeters using hash algorithm %s.",
093                                hash));
094
095                for (String output : (new OpenSSLCryptoConfigConverter()).run(hash,
096                                lines)) {
097                        System.out.println(output);
098                }
099        }
100
101        static Pattern generatorPattern = Pattern
102                        .compile(".*generator: (\\d*) \\(.*");
103
104        private static int generator(String line) {
105                Matcher matcher = generatorPattern.matcher(line);
106                matcher.matches();
107                String number = matcher.group(1);
108                return Integer.valueOf(number);
109        }
110}