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}