| 1 | /* |
| 2 | Copyright (C) 2002-2004 MySQL AB |
| 3 | |
| 4 | This program is free software; you can redistribute it and/or modify |
| 5 | it under the terms of version 2 of the GNU General Public License as |
| 6 | published by the Free Software Foundation. |
| 7 | |
| 8 | There are special exceptions to the terms and conditions of the GPL |
| 9 | as it is applied to this software. View the full text of the |
| 10 | exception in file EXCEPTIONS-CONNECTOR-J in the directory of this |
| 11 | software distribution. |
| 12 | |
| 13 | This program is distributed in the hope that it will be useful, |
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | GNU General Public License for more details. |
| 17 | |
| 18 | You should have received a copy of the GNU General Public License |
| 19 | along with this program; if not, write to the Free Software |
| 20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 21 | |
| 22 | |
| 23 | |
| 24 | */ |
| 25 | package com.mysql.jdbc; |
| 26 | |
| 27 | import java.io.ObjectInputStream; |
| 28 | import java.io.PrintWriter; |
| 29 | import java.io.StringWriter; |
| 30 | |
| 31 | /** |
| 32 | * Various utility methods for the driver. |
| 33 | * |
| 34 | * @author Mark Matthews |
| 35 | */ |
| 36 | public class Util { |
| 37 | // ~ Static fields/initializers |
| 38 | // --------------------------------------------- |
| 39 | |
| 40 | class RandStructcture { |
| 41 | long maxValue; |
| 42 | |
| 43 | double maxValueDbl; |
| 44 | |
| 45 | long seed1; |
| 46 | |
| 47 | long seed2; |
| 48 | } |
| 49 | |
| 50 | // ~ Methods |
| 51 | // ---------------------------------------------------------------- |
| 52 | |
| 53 | private static Util enclosingInstance = new Util(); |
| 54 | |
| 55 | // Right from Monty's code |
| 56 | static String newCrypt(String password, String seed) { |
| 57 | byte b; |
| 58 | double d; |
| 59 | |
| 60 | if ((password == null) || (password.length() == 0)) { |
| 61 | return password; |
| 62 | } |
| 63 | |
| 64 | long[] pw = newHash(seed); |
| 65 | long[] msg = newHash(password); |
| 66 | long max = 0x3fffffffL; |
| 67 | long seed1 = (pw[0] ^ msg[0]) % max; |
| 68 | long seed2 = (pw[1] ^ msg[1]) % max; |
| 69 | char[] chars = new char[seed.length()]; |
| 70 | |
| 71 | for (int i = 0; i < seed.length(); i++) { |
| 72 | seed1 = ((seed1 * 3) + seed2) % max; |
| 73 | seed2 = (seed1 + seed2 + 33) % max; |
| 74 | d = (double) seed1 / (double) max; |
| 75 | b = (byte) java.lang.Math.floor((d * 31) + 64); |
| 76 | chars[i] = (char) b; |
| 77 | } |
| 78 | |
| 79 | seed1 = ((seed1 * 3) + seed2) % max; |
| 80 | seed2 = (seed1 + seed2 + 33) % max; |
| 81 | d = (double) seed1 / (double) max; |
| 82 | b = (byte) java.lang.Math.floor(d * 31); |
| 83 | |
| 84 | for (int i = 0; i < seed.length(); i++) { |
| 85 | chars[i] ^= (char) b; |
| 86 | } |
| 87 | |
| 88 | return new String(chars); |
| 89 | } |
| 90 | |
| 91 | static long[] newHash(String password) { |
| 92 | long nr = 1345345333L; |
| 93 | long add = 7; |
| 94 | long nr2 = 0x12345671L; |
| 95 | long tmp; |
| 96 | |
| 97 | for (int i = 0; i < password.length(); ++i) { |
| 98 | if ((password.charAt(i) == ' ') || (password.charAt(i) == '\t')) { |
| 99 | continue; // skip spaces |
| 100 | } |
| 101 | |
| 102 | tmp = (0xff & password.charAt(i)); |
| 103 | nr ^= ((((nr & 63) + add) * tmp) + (nr << 8)); |
| 104 | nr2 += ((nr2 << 8) ^ nr); |
| 105 | add += tmp; |
| 106 | } |
| 107 | |
| 108 | long[] result = new long[2]; |
| 109 | result[0] = nr & 0x7fffffffL; |
| 110 | result[1] = nr2 & 0x7fffffffL; |
| 111 | |
| 112 | return result; |
| 113 | } |
| 114 | |
| 115 | static String oldCrypt(String password, String seed) { |
| 116 | long hp; |
| 117 | long hm; |
| 118 | long s1; |
| 119 | long s2; |
| 120 | long max = 0x01FFFFFF; |
| 121 | double d; |
| 122 | byte b; |
| 123 | |
| 124 | if ((password == null) || (password.length() == 0)) { |
| 125 | return password; |
| 126 | } |
| 127 | |
| 128 | hp = oldHash(seed); |
| 129 | hm = oldHash(password); |
| 130 | |
| 131 | long nr = hp ^ hm; |
| 132 | nr %= max; |
| 133 | s1 = nr; |
| 134 | s2 = nr / 2; |
| 135 | |
| 136 | char[] chars = new char[seed.length()]; |
| 137 | |
| 138 | for (int i = 0; i < seed.length(); i++) { |
| 139 | s1 = ((s1 * 3) + s2) % max; |
| 140 | s2 = (s1 + s2 + 33) % max; |
| 141 | d = (double) s1 / max; |
| 142 | b = (byte) java.lang.Math.floor((d * 31) + 64); |
| 143 | chars[i] = (char) b; |
| 144 | } |
| 145 | |
| 146 | return new String(chars); |
| 147 | } |
| 148 | |
| 149 | static long oldHash(String password) { |
| 150 | long nr = 1345345333; |
| 151 | long nr2 = 7; |
| 152 | long tmp; |
| 153 | |
| 154 | for (int i = 0; i < password.length(); i++) { |
| 155 | if ((password.charAt(i) == ' ') || (password.charAt(i) == '\t')) { |
| 156 | continue; |
| 157 | } |
| 158 | |
| 159 | tmp = password.charAt(i); |
| 160 | nr ^= ((((nr & 63) + nr2) * tmp) + (nr << 8)); |
| 161 | nr2 += tmp; |
| 162 | } |
| 163 | |
| 164 | return nr & ((1L << 31) - 1L); |
| 165 | } |
| 166 | |
| 167 | private static RandStructcture randomInit(long seed1, long seed2) { |
| 168 | RandStructcture randStruct = enclosingInstance.new RandStructcture(); |
| 169 | |
| 170 | randStruct.maxValue = 0x3FFFFFFFL; |
| 171 | randStruct.maxValueDbl = randStruct.maxValue; |
| 172 | randStruct.seed1 = seed1 % randStruct.maxValue; |
| 173 | randStruct.seed2 = seed2 % randStruct.maxValue; |
| 174 | |
| 175 | return randStruct; |
| 176 | } |
| 177 | |
| 178 | /** |
| 179 | * Given a ResultSet and an index into the columns of that ResultSet, read |
| 180 | * binary data from the column which represents a serialized object, and |
| 181 | * re-create the object. |
| 182 | * |
| 183 | * @param resultSet |
| 184 | * the ResultSet to use. |
| 185 | * @param index |
| 186 | * an index into the ResultSet. |
| 187 | * @return the object if it can be de-serialized |
| 188 | * @throws Exception |
| 189 | * if an error occurs |
| 190 | */ |
| 191 | public static Object readObject(java.sql.ResultSet resultSet, int index) |
| 192 | throws Exception { |
| 193 | ObjectInputStream objIn = new ObjectInputStream(resultSet |
| 194 | .getBinaryStream(index)); |
| 195 | Object obj = objIn.readObject(); |
| 196 | objIn.close(); |
| 197 | |
| 198 | return obj; |
| 199 | } |
| 200 | |
| 201 | private static double rnd(RandStructcture randStruct) { |
| 202 | randStruct.seed1 = ((randStruct.seed1 * 3) + randStruct.seed2) |
| 203 | % randStruct.maxValue; |
| 204 | randStruct.seed2 = (randStruct.seed1 + randStruct.seed2 + 33) |
| 205 | % randStruct.maxValue; |
| 206 | |
| 207 | return ((randStruct.seed1) / randStruct.maxValueDbl); |
| 208 | } |
| 209 | |
| 210 | /** |
| 211 | * DOCUMENT ME! |
| 212 | * |
| 213 | * @param message |
| 214 | * DOCUMENT ME! |
| 215 | * @param password |
| 216 | * DOCUMENT ME! |
| 217 | * |
| 218 | * @return DOCUMENT ME! |
| 219 | */ |
| 220 | public static String scramble(String message, String password) { |
| 221 | long[] hashPass; |
| 222 | long[] hashMessage; |
| 223 | byte[] to = new byte[8]; |
| 224 | String val = ""; //$NON-NLS-1$ |
| 225 | |
| 226 | message = message.substring(0, 8); |
| 227 | |
| 228 | if ((password != null) && (password.length() > 0)) { |
| 229 | hashPass = newHash(password); |
| 230 | hashMessage = newHash(message); |
| 231 | |
| 232 | RandStructcture randStruct = randomInit(hashPass[0] |
| 233 | ^ hashMessage[0], hashPass[1] ^ hashMessage[1]); |
| 234 | |
| 235 | int msgPos = 0; |
| 236 | int msgLength = message.length(); |
| 237 | int toPos = 0; |
| 238 | |
| 239 | while (msgPos++ < msgLength) { |
| 240 | to[toPos++] = (byte) (Math.floor(rnd(randStruct) * 31) + 64); |
| 241 | } |
| 242 | |
| 243 | /* Make it harder to break */ |
| 244 | byte extra = (byte) (Math.floor(rnd(randStruct) * 31)); |
| 245 | |
| 246 | for (int i = 0; i < to.length; i++) { |
| 247 | to[i] ^= extra; |
| 248 | } |
| 249 | |
| 250 | val = new String(to); |
| 251 | } |
| 252 | |
| 253 | return val; |
| 254 | } |
| 255 | |
| 256 | // ~ Inner Classes |
| 257 | // ---------------------------------------------------------- |
| 258 | |
| 259 | /** |
| 260 | * Converts a nested exception into a nicer message |
| 261 | * |
| 262 | * @param ex |
| 263 | * the exception to expand into a message. |
| 264 | * |
| 265 | * @return a message containing the exception, the message (if any), and a |
| 266 | * stacktrace. |
| 267 | */ |
| 268 | public static String stackTraceToString(Throwable ex) { |
| 269 | StringBuffer traceBuf = new StringBuffer(); |
| 270 | traceBuf.append(Messages.getString("Util.1")); //$NON-NLS-1$ |
| 271 | |
| 272 | if (ex != null) { |
| 273 | traceBuf.append(ex.getClass().getName()); |
| 274 | |
| 275 | String message = ex.getMessage(); |
| 276 | |
| 277 | if (message != null) { |
| 278 | traceBuf.append(Messages.getString("Util.2")); //$NON-NLS-1$ |
| 279 | traceBuf.append(message); |
| 280 | } |
| 281 | |
| 282 | StringWriter out = new StringWriter(); |
| 283 | |
| 284 | PrintWriter printOut = new PrintWriter(out); |
| 285 | |
| 286 | ex.printStackTrace(printOut); |
| 287 | |
| 288 | traceBuf.append(Messages.getString("Util.3")); //$NON-NLS-1$ |
| 289 | traceBuf.append(out.toString()); |
| 290 | } |
| 291 | |
| 292 | traceBuf.append(Messages.getString("Util.4")); //$NON-NLS-1$ |
| 293 | |
| 294 | return traceBuf.toString(); |
| 295 | } |
| 296 | } |