1 21 22 27 28 package com.sun.mail.smtp; 29 30 import java.io.*; 31 import java.util.*; 32 import java.security.*; 33 34 import com.sun.mail.util.*; 35 36 42 43 public class DigestMD5 { 44 45 private PrintStream debugout; private MessageDigest md5; 47 private String uri; 48 private String clientResponse; 49 50 public DigestMD5(PrintStream debugout) { 51 this.debugout = debugout; 52 if (debugout != null) 53 debugout.println("DEBUG DIGEST-MD5: Loaded"); 54 } 55 56 61 public byte[] authClient(String host, String user, String passwd, 62 String realm, String serverChallenge) 63 throws IOException { 64 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 65 OutputStream b64os = new BASE64EncoderStream(bos, Integer.MAX_VALUE); 66 SecureRandom random; 67 try { 68 random = new SecureRandom(); 70 md5 = MessageDigest.getInstance("MD5"); 71 } catch (NoSuchAlgorithmException ex) { 72 if (debugout != null) 73 debugout.println("DEBUG DIGEST-MD5: " + ex); 74 throw new IOException(ex.toString()); 75 } 76 StringBuffer result = new StringBuffer (); 77 78 uri = "smtp/" + host; 79 String nc = "00000001"; 80 String qop = "auth"; 81 byte[] bytes = new byte[32]; int resp; 83 84 if (debugout != null) 85 debugout.println("DEBUG DIGEST-MD5: Begin authentication ..."); 86 87 Hashtable map = tokenize(serverChallenge); 89 90 if (realm == null) { 91 String text = (String )map.get("realm"); 92 realm = text != null ? new StringTokenizer(text, ",").nextToken() 93 : host; 94 } 95 96 String nonce = (String )map.get("nonce"); 98 99 random.nextBytes(bytes); 100 b64os.write(bytes); 101 b64os.flush(); 102 103 String cnonce = bos.toString(); 105 bos.reset(); 106 107 md5.update(md5.digest( 109 ASCIIUtility.getBytes(user + ":" + realm + ":" + passwd))); 110 md5.update(ASCIIUtility.getBytes(":" + nonce + ":" + cnonce)); 111 clientResponse = toHex(md5.digest()) 112 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":"; 113 114 md5.update(ASCIIUtility.getBytes("AUTHENTICATE:" + uri)); 116 md5.update(ASCIIUtility.getBytes(clientResponse + toHex(md5.digest()))); 117 118 result.append("username=\"" + user + "\""); 120 result.append(",realm=\"" + realm + "\""); 121 result.append(",qop=" + qop); 122 result.append(",nc=" + nc); 123 result.append(",nonce=\"" + nonce + "\""); 124 result.append(",cnonce=\"" + cnonce + "\""); 125 result.append(",digest-uri=\"" + uri + "\""); 126 result.append(",response=" + toHex(md5.digest())); 127 128 if (debugout != null) 129 debugout.println("DEBUG DIGEST-MD5: Response => " 130 + result.toString()); 131 b64os.write(ASCIIUtility.getBytes(result.toString())); 132 b64os.flush(); 133 return bos.toByteArray(); 134 } 135 136 142 public boolean authServer(String serverResponse) throws IOException { 143 Hashtable map = tokenize(serverResponse); 144 md5.update(ASCIIUtility.getBytes(":" + uri)); 146 md5.update(ASCIIUtility.getBytes(clientResponse + toHex(md5.digest()))); 147 String text = toHex(md5.digest()); 148 if (!text.equals((String )map.get("rspauth"))) { 149 if (debugout != null) 150 debugout.println("DEBUG DIGEST-MD5: " + 151 "Expected => rspauth=" + text); 152 return false; } 154 return true; 155 } 156 157 162 private Hashtable tokenize(String serverResponse) throws IOException { 163 Hashtable map = new Hashtable(); 164 byte[] bytes = serverResponse.getBytes(); 165 String key = null; 166 int ttype; 167 StreamTokenizer tokens 168 = new StreamTokenizer( 169 new InputStreamReader( 170 new BASE64DecoderStream( 171 new ByteArrayInputStream(bytes, 4, bytes.length - 4) 172 ))); 173 174 tokens.ordinaryChars('0', '9'); tokens.wordChars('0', '9'); while ((ttype = tokens.nextToken()) != StreamTokenizer.TT_EOF) { 177 switch (ttype) { 178 case StreamTokenizer.TT_WORD: 179 if (key == null) { 180 key = tokens.sval; 181 break; 182 } 183 case '"': 185 if (debugout != null) 186 debugout.println("DEBUG DIGEST-MD5: Received => " 187 + key + "='" + tokens.sval + "'"); 188 if (map.containsKey(key)) { map.put(key, map.get(key) + "," + tokens.sval); 190 } else { 191 map.put(key, tokens.sval); 192 } 193 key = null; 194 break; 195 } 196 } 197 return map; 198 } 199 200 private static char[] digits = { 201 '0', '1', '2', '3', '4', '5', '6', '7', 202 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' 203 }; 204 205 208 private static String toHex(byte[] bytes) { 209 char[] result = new char[bytes.length * 2]; 210 211 for (int index = 0, i = 0; index < bytes.length; index++) { 212 int temp = bytes[index] & 0xFF; 213 result[i++] = digits[temp >> 4]; 214 result[i++] = digits[temp & 0xF]; 215 } 216 return new String (result); 217 } 218 } 219 | Popular Tags |