DigestServerAuthenticationHelper.java 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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. package com.genersoft.iot.vmp.gb28181.auth;
  27. import java.security.MessageDigest;
  28. import java.security.NoSuchAlgorithmException;
  29. import java.util.Date;
  30. import java.util.Random;
  31. import javax.sip.address.URI;
  32. import javax.sip.header.AuthorizationHeader;
  33. import javax.sip.header.HeaderFactory;
  34. import javax.sip.header.WWWAuthenticateHeader;
  35. import javax.sip.message.Request;
  36. import javax.sip.message.Response;
  37. import gov.nist.core.InternalErrorHandler;
  38. /**
  39. * Implements the HTTP digest authentication method server side functionality.
  40. *
  41. * @author M. Ranganathan
  42. * @author Marc Bednarek
  43. */
  44. public class DigestServerAuthenticationHelper {
  45. private MessageDigest messageDigest;
  46. public static final String DEFAULT_ALGORITHM = "MD5";
  47. public static final String DEFAULT_SCHEME = "Digest";
  48. /** to hex converter */
  49. private static final char[] toHex = { '0', '1', '2', '3', '4', '5', '6',
  50. '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
  51. /**
  52. * Default constructor.
  53. * @throws NoSuchAlgorithmException
  54. */
  55. public DigestServerAuthenticationHelper()
  56. throws NoSuchAlgorithmException {
  57. messageDigest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
  58. }
  59. public static String toHexString(byte b[]) {
  60. int pos = 0;
  61. char[] c = new char[b.length * 2];
  62. for (int i = 0; i < b.length; i++) {
  63. c[pos++] = toHex[(b[i] >> 4) & 0x0F];
  64. c[pos++] = toHex[b[i] & 0x0f];
  65. }
  66. return new String(c);
  67. }
  68. /**
  69. * Generate the challenge string.
  70. *
  71. * @return a generated nonce.
  72. */
  73. private String generateNonce() {
  74. // Get the time of day and run MD5 over it.
  75. Date date = new Date();
  76. long time = date.getTime();
  77. Random rand = new Random();
  78. long pad = rand.nextLong();
  79. String nonceString = (new Long(time)).toString()
  80. + (new Long(pad)).toString();
  81. byte mdbytes[] = messageDigest.digest(nonceString.getBytes());
  82. // Convert the mdbytes array into a hex string.
  83. return toHexString(mdbytes);
  84. }
  85. public Response generateChallenge(HeaderFactory headerFactory, Response response, String realm) {
  86. try {
  87. WWWAuthenticateHeader proxyAuthenticate = headerFactory
  88. .createWWWAuthenticateHeader(DEFAULT_SCHEME);
  89. proxyAuthenticate.setParameter("realm", realm);
  90. proxyAuthenticate.setParameter("nonce", generateNonce());
  91. proxyAuthenticate.setParameter("opaque", "");
  92. proxyAuthenticate.setParameter("stale", "FALSE");
  93. proxyAuthenticate.setParameter("algorithm", DEFAULT_ALGORITHM);
  94. response.setHeader(proxyAuthenticate);
  95. } catch (Exception ex) {
  96. InternalErrorHandler.handleException(ex);
  97. }
  98. return response;
  99. }
  100. /**
  101. * Authenticate the inbound request.
  102. *
  103. * @param request - the request to authenticate.
  104. * @param hashedPassword -- the MD5 hashed string of username:realm:plaintext password.
  105. *
  106. * @return true if authentication succeded and false otherwise.
  107. */
  108. public boolean doAuthenticateHashedPassword(Request request, String hashedPassword) {
  109. AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
  110. if ( authHeader == null ) return false;
  111. String realm = authHeader.getRealm();
  112. String username = authHeader.getUsername();
  113. if ( username == null || realm == null ) {
  114. return false;
  115. }
  116. String nonce = authHeader.getNonce();
  117. URI uri = authHeader.getURI();
  118. if (uri == null) {
  119. return false;
  120. }
  121. String A2 = request.getMethod().toUpperCase() + ":" + uri.toString();
  122. String HA1 = hashedPassword;
  123. byte[] mdbytes = messageDigest.digest(A2.getBytes());
  124. String HA2 = toHexString(mdbytes);
  125. String cnonce = authHeader.getCNonce();
  126. String KD = HA1 + ":" + nonce;
  127. if (cnonce != null) {
  128. KD += ":" + cnonce;
  129. }
  130. KD += ":" + HA2;
  131. mdbytes = messageDigest.digest(KD.getBytes());
  132. String mdString = toHexString(mdbytes);
  133. String response = authHeader.getResponse();
  134. return mdString.equals(response);
  135. }
  136. /**
  137. * Authenticate the inbound request given plain text password.
  138. *
  139. * @param request - the request to authenticate.
  140. * @param pass -- the plain text password.
  141. *
  142. * @return true if authentication succeded and false otherwise.
  143. */
  144. public boolean doAuthenticatePlainTextPassword(Request request, String pass) {
  145. AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
  146. if ( authHeader == null ) return false;
  147. String realm = authHeader.getRealm();
  148. String username = authHeader.getUsername();
  149. if ( username == null || realm == null ) {
  150. return false;
  151. }
  152. String nonce = authHeader.getNonce();
  153. URI uri = authHeader.getURI();
  154. if (uri == null) {
  155. return false;
  156. }
  157. String A1 = username + ":" + realm + ":" + pass;
  158. String A2 = request.getMethod().toUpperCase() + ":" + uri.toString();
  159. byte mdbytes[] = messageDigest.digest(A1.getBytes());
  160. String HA1 = toHexString(mdbytes);
  161. mdbytes = messageDigest.digest(A2.getBytes());
  162. String HA2 = toHexString(mdbytes);
  163. String cnonce = authHeader.getCNonce();
  164. String KD = HA1 + ":" + nonce;
  165. if (cnonce != null) {
  166. KD += ":" + cnonce;
  167. }
  168. KD += ":" + HA2;
  169. mdbytes = messageDigest.digest(KD.getBytes());
  170. String mdString = toHexString(mdbytes);
  171. String response = authHeader.getResponse();
  172. return mdString.equals(response);
  173. }
  174. }