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