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        final SRP6Routines srp6Routines = new SRP6Routines();
026
027        public List<String> run(String hash, List<String> lines) throws Exception {
028                int generator = 0;
029                StringBuilder hexparts = new StringBuilder();
030
031                for (String line : lines) {
032                        if (line.endsWith("prime:")) {
033                                // skip this one
034                        } else if (line.endsWith(":")) {
035                                hexparts.append(line.trim());
036                        } else if (line.contains("generator")) {
037                                try {
038                                        generator = generator(line.trim());
039                                } catch (Exception e) {
040                                        throw new AssertionError(
041                                                        "could not parse 'generator: x' number out of line containing 'generator': "
042                                                                        + line);
043                                }
044                        }
045                }
046
047                if (generator <= 0) {
048                        throw new AssertionError(
049                                        "could not parse 'generator: x' number out of line containing 'generator'");
050                }
051
052                String primeHex = hexparts.toString().replace(":", "");
053
054                List<String> output = new ArrayList<String>();
055
056                BigInteger N = new BigInteger(primeHex, 16);
057                BigInteger g = new BigInteger(generator + "");
058
059                output.add("hashing to create 'k' using " + hash);
060
061                MessageDigest digest = MessageDigest.getInstance(hash);
062                BigInteger k = srp6Routines.computeK(digest, N, g);
063
064                output.add("computing...");
065                output.add("N base10: " + N.toString(10));
066                output.add("g base10: " + g.toString(10));
067                output.add("k base16: " + k.toString(16));
068
069                return output;
070        }
071
072        public static void main(String[] args) throws Exception {
073
074                if (args.length != 2) {
075                        System.err.println("Arguments: file hash ");
076                        System.err.println("Example  : /tmp/my_dhparam.txt SHA-256 ");
077                        System.exit(1);
078                }
079
080                final String file = args[0];
081                final String hash = args[1];
082
083                System.out
084                                .println(String
085                                                .format("Attempting to load 'openssl dhparam -text <bitlength>' output text file at: %s",
086                                                                file));
087
088                final List<String> lines = Files.readAllLines(Paths.get(args[0]),
089                                Charset.forName("UTF8"));
090
091                System.out.println(String.format("Loaded %s lines.", lines.size()));
092
093                System.out.println(String.format(
094                                "Creating configuration parmeters using hash algorithm %s.",
095                                hash));
096
097                for (String output : (new OpenSSLCryptoConfigConverter()).run(hash,
098                                lines)) {
099                        System.out.println(output);
100                }
101        }
102
103        static Pattern generatorPattern = Pattern
104                        .compile(".*generator: (\\d*) \\(.*");
105
106        private static int generator(String line) {
107                Matcher matcher = generatorPattern.matcher(line);
108                matcher.matches();
109                String number = matcher.group(1);
110                return Integer.valueOf(number);
111        }
112}