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