1 /* 2 * Conditions Of Use 3 * 4 * This software was developed by employees of the National Institute of 5 * Standards and Technology (NIST), an agency of the Federal Government. 6 * Pursuant to title 15 Untied States Code Section 105, works of NIST 7 * employees are not subject to copyright protection in the United States 8 * and are considered to be in the public domain. As a result, a formal 9 * license is not needed to use the software. 10 * 11 * This software is provided by NIST as a service and is expressly 12 * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED 13 * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF 14 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT 15 * AND DATA ACCURACY. NIST does not warrant or make any representations 16 * regarding the use of the software or the results thereof, including but 17 * not limited to the correctness, accuracy, reliability or usefulness of 18 * the software. 19 * 20 * Permission to use this software is contingent upon your acceptance 21 * of the terms of this agreement 22 * 23 * . 24 * 25 */ 26 /******************************************************************************* 27 * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * 28 *******************************************************************************/ 29 package gov.nist.javax.sip; 30 31 import gov.nist.javax.sip.header.Via; 32 import gov.nist.javax.sip.message.SIPResponse; 33 34 import java.security.MessageDigest; 35 import java.util.HashSet; 36 37 /** 38 * A few utilities that are used in various places by the stack. This is used to 39 * convert byte arrays to hex strings etc. Generate tags and branch identifiers 40 * and odds and ends. 41 * 42 * @author mranga 43 * @version 1.2 $Revision: 1.21 $ $Date: 2009/10/18 13:46:37 $ 44 */ 45 public class Utils implements UtilsExt { 46 47 private static MessageDigest digester; 48 49 private static java.util.Random rand; 50 51 private static long counter = 0; 52 53 private static int callIDCounter; 54 55 private static String signature ; 56 57 private static Utils instance = new Utils(); 58 59 60 /** 61 * to hex converter 62 */ 63 private static final char[] toHex = { '0', '1', '2', '3', '4', '5', '6', 64 '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 65 66 static { 67 try { 68 digester = MessageDigest.getInstance("MD5"); 69 } catch (Exception ex) { 70 throw new RuntimeException("Could not intialize Digester ", ex); 71 } 72 rand = new java.util.Random(); 73 signature = toHexString(Integer.toString(Math.abs( rand.nextInt() % 1000 )).getBytes()); 74 } 75 76 77 public static Utils getInstance() { 78 return instance; 79 } 80 81 /** 82 * convert an array of bytes to an hexadecimal string 83 * 84 * @return a string 85 * @param b 86 * bytes array to convert to a hexadecimal string 87 */ 88 89 public static String toHexString(byte b[]) { 90 int pos = 0; 91 char[] c = new char[b.length * 2]; 92 for (int i = 0; i < b.length; i++) { 93 c[pos++] = toHex[(b[i] >> 4) & 0x0F]; 94 c[pos++] = toHex[b[i] & 0x0f]; 95 } 96 return new String(c); 97 } 98 99 /** 100 * Put quotes around a string and return it. 101 * Any " characters appearing in str are escaped 102 * 103 * @return a quoted string 104 * @param str 105 * string to be quoted 106 */ 107 public static String getQuotedString(String str) { 108 return '"' + str.replace( "\"", "\\\"" ) + '"'; 109 } 110 111 /** 112 * Squeeze out all white space from a string and return the reduced string. 113 * 114 * @param input 115 * input string to sqeeze. 116 * @return String a reduced string. 117 */ 118 protected static String reduceString(String input) { 119 String newString = input.toLowerCase(); 120 int len = newString.length(); 121 String retval = ""; 122 for (int i = 0; i < len; i++) { 123 if (newString.charAt(i) == ' ' || newString.charAt(i) == '\t') 124 continue; 125 else 126 retval += newString.charAt(i); 127 } 128 return retval; 129 } 130 131 /** 132 * Generate a call identifier. This is useful when we want to generate a 133 * call identifier in advance of generating a message. 134 */ 135 public synchronized String generateCallIdentifier(String address) { 136 137 String date = Long.toString(System.currentTimeMillis() + callIDCounter++ 138 + rand.nextLong()); 139 byte cid[] = digester.digest(date.getBytes()); 140 141 String cidString = Utils.toHexString(cid); 142 return cidString + "@" + address; 143 144 } 145 146 /** 147 * Generate a tag for a FROM header or TO header. Just return a random 4 148 * digit integer (should be enough to avoid any clashes!) Tags only need to 149 * be unique within a call. 150 * 151 * @return a string that can be used as a tag parameter. 152 * 153 * synchronized: needed for access to 'rand', else risk to generate same tag 154 * twice 155 */ 156 public synchronized String generateTag() { 157 158 return Integer.toHexString(rand.nextInt()); 159 160 } 161 162 /** 163 * Generate a cryptographically random identifier that can be used to 164 * generate a branch identifier. 165 * 166 * @return a cryptographically random gloablly unique string that can be 167 * used as a branch identifier. 168 */ 169 public synchronized String generateBranchId() { 170 // 171 172 173 long num = rand.nextLong() + Utils.counter++ + System.currentTimeMillis(); 174 175 byte bid[] = digester.digest(Long.toString(num).getBytes()); 176 // prepend with a magic cookie to indicate we are bis09 compatible. 177 return SIPConstants.BRANCH_MAGIC_COOKIE + Utils.toHexString(bid) + this.signature; 178 179 180 } 181 182 public boolean responseBelongsToUs(SIPResponse response) { 183 Via topmostVia = response.getTopmostVia(); 184 String branch = topmostVia.getBranch(); 185 return branch != null && branch.endsWith(this.signature); 186 } 187 188 public static String getSignature() { 189 return signature; 190 } 191 192 public static void main(String[] args) { 193 HashSet branchIds = new HashSet(); 194 for (int b = 0; b < 100000; b++) { 195 String bid = Utils.getInstance().generateBranchId(); 196 if (branchIds.contains(bid)) { 197 throw new RuntimeException("Duplicate Branch ID"); 198 } else { 199 branchIds.add(bid); 200 } 201 } 202 System.out.println("Done!!"); 203 204 } 205 206 207 208 } 209