From 3a306eefe9cbb4365905e3cf04540dc610f36403 Mon Sep 17 00:00:00 2001 From: Barry Lind Date: Mon, 12 Nov 2001 19:11:56 +0000 Subject: [PATCH] Commit to support MD5 passwords as per the backend for 7.2. This patch was submitted by Jeremy Wohl jeremyw-pgjdbc@igmus.org --- src/interfaces/jdbc/org/postgresql/Connection.java | 32 ++++++++-- .../jdbc/org/postgresql/util/MD5Digest.java | 73 ++++++++++++++++++++++ 2 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 src/interfaces/jdbc/org/postgresql/util/MD5Digest.java diff --git a/src/interfaces/jdbc/org/postgresql/Connection.java b/src/interfaces/jdbc/org/postgresql/Connection.java index 0982428e9e..0d53b96e48 100644 --- a/src/interfaces/jdbc/org/postgresql/Connection.java +++ b/src/interfaces/jdbc/org/postgresql/Connection.java @@ -11,7 +11,7 @@ import org.postgresql.util.*; import org.postgresql.core.*; /** - * $Id: Connection.java,v 1.34 2001/11/01 01:08:36 barry Exp $ + * $Id: Connection.java,v 1.35 2001/11/12 19:11:56 barry Exp $ * * This abstract class is used by org.postgresql.Driver to open either the JDBC1 or * JDBC2 versions of the Connection class. @@ -63,6 +63,7 @@ public abstract class Connection private static final int AUTH_REQ_KRB5 = 2; private static final int AUTH_REQ_PASSWORD = 3; private static final int AUTH_REQ_CRYPT = 4; + private static final int AUTH_REQ_MD5 = 5; // New for 6.3, salt value for crypt authorisation private String salt; @@ -180,22 +181,34 @@ public abstract class Connection // Get the type of request areq = pg_stream.ReceiveIntegerR(4); - // Get the password salt if there is one + // Get the crypt password salt if there is one if (areq == AUTH_REQ_CRYPT) { byte[] rst = new byte[2]; rst[0] = (byte)pg_stream.ReceiveChar(); rst[1] = (byte)pg_stream.ReceiveChar(); salt = new String(rst, 0, 2); - DriverManager.println("Salt=" + salt); + DriverManager.println("Crypt salt=" + salt); + } + + // Or get the md5 password salt if there is one + if (areq == AUTH_REQ_MD5) + { + byte[] rst = new byte[4]; + rst[0] = (byte)pg_stream.ReceiveChar(); + rst[1] = (byte)pg_stream.ReceiveChar(); + rst[2] = (byte)pg_stream.ReceiveChar(); + rst[3] = (byte)pg_stream.ReceiveChar(); + salt = new String(rst, 0, 4); + DriverManager.println("MD5 salt=" + salt); } // now send the auth packet switch (areq) { case AUTH_REQ_OK: - break; - + break; + case AUTH_REQ_KRB4: DriverManager.println("postgresql: KRB4"); throw new PSQLException("postgresql.con.kerb4"); @@ -221,6 +234,15 @@ public abstract class Connection pg_stream.flush(); break; + case AUTH_REQ_MD5: + DriverManager.println("postgresql: MD5"); + byte[] digest = MD5Digest.encode(PG_USER, PG_PASSWORD, salt); + pg_stream.SendInteger(5 + digest.length, 4); + pg_stream.Send(digest); + pg_stream.SendInteger(0, 1); + pg_stream.flush(); + break; + default: throw new PSQLException("postgresql.con.auth", new Integer(areq)); } diff --git a/src/interfaces/jdbc/org/postgresql/util/MD5Digest.java b/src/interfaces/jdbc/org/postgresql/util/MD5Digest.java new file mode 100644 index 0000000000..450f242d60 --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/util/MD5Digest.java @@ -0,0 +1,73 @@ +package org.postgresql.util; + +/** + * MD5-based utility function to obfuscate passwords before network transmission + * + * @author Jeremy Wohl + * + */ + +import java.security.*; + +public class MD5Digest +{ + private MD5Digest() {} + + + /** + * Encodes user/password/salt information in the following way: + * MD5(MD5(password + user) + salt) + * + * @param user The connecting user. + * @param password The connecting user's password. + * @param salt A four-character string sent by the server. + * + * @return A 35-byte array, comprising the string "md5", followed by an MD5 digest. + */ + public static byte[] encode(String user, String password, String salt) + { + MessageDigest md; + byte[] temp_digest, pass_digest; + byte[] hex_digest = new byte[35]; + + + try { + md = MessageDigest.getInstance("MD5"); + + md.update(password.getBytes()); + md.update(user.getBytes()); + temp_digest = md.digest(); + + bytesToHex(temp_digest, hex_digest, 0); + md.update(hex_digest, 0, 32); + md.update(salt.getBytes()); + pass_digest = md.digest(); + + bytesToHex(pass_digest, hex_digest, 3); + hex_digest[0] = (byte) 'm'; hex_digest[1] = (byte) 'd'; hex_digest[2] = (byte) '5'; + } catch (Exception e) { + ; // "MessageDigest failure; " + e + } + + return hex_digest; + } + + + /** + * Turn 16-byte stream into a human-readable 32-byte hex string + */ + private static void bytesToHex(byte[] bytes, byte[] hex, int offset) + { + final char lookup[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' }; + + int i, c, j, pos = offset; + + for (i = 0; i < 16; i++) { + c = bytes[i] & 0xFF; j = c >> 4; + hex[pos++] = (byte) lookup[j]; + j = (c & 0xF); + hex[pos++] = (byte) lookup[j]; + } + } +} -- 2.11.0