001package com.bitbucket.thinbus.srp6.js; 002 003import static com.nimbusds.srp6.BigIntegerUtils.toHex; 004 005import java.math.BigInteger; 006import java.nio.charset.Charset; 007import java.security.MessageDigest; 008 009/** 010 * Secure Remote Password (SRP-6a) hashing routine for Java compatible with 011 * browser implementations by using hashing of string concatenated hex strings. 012 * 013 * <p> 014 * Specification RFC 2945 015 * 016 * @author Simon Massey 017 */ 018public class HexHashedRoutines { 019 020 public final static Charset utf8 = utf8(); 021 022 static Charset utf8() { 023 return Charset.forName("UTF8"); 024 } 025 026 public static BigInteger hashValues(final MessageDigest digest, final String... values) { 027 final StringBuilder builder = new StringBuilder(); 028 for (String v : values) { 029 builder.append(v); 030 } 031 final byte[] bytes = builder.toString().getBytes(utf8); 032 digest.update(bytes, 0, bytes.length); 033 return new BigInteger(1, digest.digest()); 034 } 035 036 private HexHashedRoutines() { 037 // empty 038 } 039 040 public static String leadingZerosPad(String value, int desiredLength) { 041 StringBuilder builder = new StringBuilder(); 042 int difference = desiredLength - value.length(); 043 for (int i = 0; i < difference; i++) { 044 builder.append('0'); 045 } 046 builder.append(value); 047 return builder.toString(); 048 } 049 050 public static String hashCredentials(MessageDigest digest, String salt, 051 String identity, String password) { 052 digest.reset(); 053 054 String concat = identity + ":" + password; 055 056 digest.update(concat.getBytes(utf8)); 057 byte[] output = digest.digest(); 058 digest.reset(); 059 060 final String hash1 = toHex(new BigInteger(1, output)); 061 062 concat = (salt + hash1).toUpperCase(); 063 064 digest.update(concat.getBytes(utf8)); 065 output = digest.digest(); 066 067 return toHexString(output); 068 } 069 070 final private static char[] hexArray = "0123456789abcdef".toCharArray(); 071 072 /** 073 * http://stackoverflow.com/a/9855338 074 * 075 * Compute a String in HexDigit from the input. Note that this string may 076 * have leading zeros but hex strings created by toString(16) of BigInteger 077 * would strip leading zeros. 078 * 079 * @param bytes 080 * Raw byte array 081 * @return Hex encoding of the input 082 */ 083 public static String toHexString(final byte[] bytes) { 084 char[] hexChars = new char[bytes.length * 2]; 085 for (int j = 0; j < bytes.length; j++) { 086 int v = bytes[j] & 0xFF; 087 hexChars[j * 2] = hexArray[v >>> 4]; 088 hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 089 } 090 return new String(hexChars); 091 } 092}