Home > Database > Mysql Tutorial > A detailed introduction to the authentication package and code of the mysql protocol

A detailed introduction to the authentication package and code of the mysql protocol

黄舟
Release: 2017-03-08 14:06:24
Original
1276 people have browsed it


git


https://github.com/sea-boat/mysql-protocol

Overview

Mysql client requires an interactive process to log in to the mysql server. First, the server sends an initial handshake packet to the client. After receiving the handshake packet, the client returns an authentication packet to the server. As follows, the authentication package is analyzed here.

client                 server
   |-------connect------>|
   |                     |
   |<-----handshake------|
   |                     |
   |---authentication--->|
   |                     |
Copy after login

mysql communication message structure

A detailed introduction to the authentication package and code of the mysql protocol

##PayloadAuthentication Package
4              capability flags, CLIENT_PROTOCOL_41 always set
4              max-packet size
1              character set
string[23]     reserved (all [0])
string[NUL]    username
  if capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA {
lenenc-int     length of auth-response
string[n]      auth-response
  } else if capabilities & CLIENT_SECURE_CONNECTION {
1              length of auth-response
string[n]      auth-response
  } else {
string[NUL]    auth-response
  }
  if capabilities & CLIENT_CONNECT_WITH_DB {
string[NUL]    database
  }
  if capabilities & CLIENT_PLUGIN_AUTH {
string[NUL]    auth plugin name
  }
  if capabilities & CLIENT_CONNECT_ATTRS {
lenenc-int     length of all key-values
lenenc-str     key
lenenc-str     value
   if-more data in &#39;length of all key-values&#39;, more keys and value pairs
  }
Copy after login

More details: http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse

Authentication package operation

1. Authentication package class

/**
 * 
 * @author seaboat
 * @date 2016-09-25
 * @version 1.0
 * <pre class="brush:php;toolbar:false"><b>email: </b>849586227@qq.com
Copy after login
Copy after login
Copy after login
*
<b>blog: </b>http://www.php.cn/;/pre>
 * <p>mysql auth packet.</p>
 */public class AuthPacket extends MySQLPacket {
    private static final byte[] FILLER = new byte[23];    
    public long clientFlags;    
    public long maxPacketSize;    
    public int charsetIndex;    
    public byte[] extra;    
    public String user;    
    public byte[] password;    
    public String database;    
    public void read(byte[] data) {
        MySQLMessage mm = new MySQLMessage(data);
        packetLength = mm.readUB3();
        packetId = mm.read();
        clientFlags = mm.readUB4();
        maxPacketSize = mm.readUB4();
        charsetIndex = (mm.read() & 0xff);        
        int current = mm.position();        
        int len = (int) mm.readLength();        
        if (len > 0 && len < FILLER.length) {            
        byte[] ab = new byte[len];
            System.arraycopy(mm.bytes(), mm.position(), ab, 0, len);            
            this.extra = ab;
        }
        mm.position(current + FILLER.length);
        user = mm.readStringWithNull();
        password = mm.readBytesWithLength();        
        if (((clientFlags & Capabilities.CLIENT_CONNECT_WITH_DB) != 0)
                && mm.hasRemaining()) {
            database = mm.readStringWithNull();
        }
    }    public void write(ByteBuffer buffer) throws IOException {
        BufferUtil.writeUB3(buffer, calcPacketSize());
        buffer.put(packetId);
        BufferUtil.writeUB4(buffer, clientFlags);
        BufferUtil.writeUB4(buffer, maxPacketSize);
        buffer.put((byte) charsetIndex);
        buffer.put(FILLER);        if (user == null) {
            buffer.put((byte) 0);
        } else {
            BufferUtil.writeWithNull(buffer, user.getBytes());
        }        if (password == null) {
            buffer.put((byte) 0);
        } else {
            BufferUtil.writeWithLength(buffer, password);
        }        if (database == null) {
            buffer.put((byte) 0);
        } else {
            BufferUtil.writeWithNull(buffer, database.getBytes());
        }
    }    @Override
    public int calcPacketSize() {        
    int size = 32;// 4+4+1+23;
        size += (user == null) ? 1 : user.length() + 1;
        size += (password == null) ? 1 : BufferUtil.getLength(password);
        size += (database == null) ? 1 : database.length() + 1;        
        return size;
    }    @Override
    protected String getPacketInfo() {        
    return "MySQL Authentication Packet";
    }

}
Copy after login

  1. Encryption and decryption tool

  2. /**
     * 
     * @author seaboat
     * @date 2016-09-25
     * @version 1.0
     * <pre class="brush:php;toolbar:false"><b>email: </b>849586227@qq.com
    Copy after login
    Copy after login
    Copy after login
    *
    <b>blog: </b>http://www.php.cn/;/pre>
     * <p>a security util .</p>
     */public class SecurityUtil {
    
        public static final byte[] scramble411(byte[] pass, byte[] seed)            
        throws NoSuchAlgorithmException {
            MessageDigest md = MessageDigest.getInstance("SHA-1");        
            byte[] pass1 = md.digest(pass);
            md.reset();        
            byte[] pass2 = md.digest(pass1);
            md.reset();
            md.update(seed);        
            byte[] pass3 = md.digest(pass2);        
            for (int i = 0; i < pass3.length; i++) {
                pass3[i] = (byte) (pass3[i] ^ pass1[i]);
            }        return pass3;
        }    public static final String scramble323(String pass, String seed) {        
        if ((pass == null) || (pass.length() == 0)) {            
        return pass;
            }        
            byte b;        
            double d;        
            long[] pw = hash(seed);        
            long[] msg = hash(pass);        
            long max = 0x3fffffffL;        
            long seed1 = (pw[0] ^ msg[0]) % max;        
            long seed2 = (pw[1] ^ msg[1]) % max;        
            char[] chars = new char[seed.length()];        
            for (int i = 0; i < seed.length(); i++) {
                seed1 = ((seed1 * 3) + seed2) % max;
                seed2 = (seed1 + seed2 + 33) % max;
                d = (double) seed1 / (double) max;
                b = (byte) java.lang.Math.floor((d * 31) + 64);
                chars[i] = (char) b;
            }
            seed1 = ((seed1 * 3) + seed2) % max;
            seed2 = (seed1 + seed2 + 33) % max;
            d = (double) seed1 / (double) max;
            b = (byte) java.lang.Math.floor(d * 31);        
            for (int i = 0; i < seed.length(); i++) {
                chars[i] ^= (char) b;
            }        return new String(chars);
        }    private static long[] hash(String src) {        
        long nr = 1345345333L;        
        long add = 7;        
        long nr2 = 0x12345671L;        
        long tmp;        
        for (int i = 0; i < src.length(); ++i) {            
        switch (src.charAt(i)) {            
        case &#39; &#39;:            
        case &#39;\t&#39;:                
        continue;            
        default:
                    tmp = (0xff & src.charAt(i));
                    nr ^= ((((nr & 63) + add) * tmp) + (nr << 8));
                    nr2 += ((nr2 << 8) ^ nr);
                    add += tmp;
                }
            }        
            long[] result = new long[2];
            result[0] = nr & 0x7fffffffL;
            result[1] = nr2 & 0x7fffffffL;        
            return result;
        }
    
    }
    Copy after login
  1. Test class

  2. /**
     * 
     * @author seaboat
     * @date 2016-09-25
     * @version 1.0
     * <pre class="brush:php;toolbar:false"><b>email: </b>849586227@qq.com
    Copy after login
    Copy after login
    Copy after login
    *
    <b>blog: </b>http://www.php.cn/;/pre>
     * <p>test auth packet.</p>
     */public class AuthPacketTest {
        @Test
        public void produce() {        
        // handshake packet&#39;s rand1 and rand2
            byte[] rand1 = RandomUtil.randomBytes(8);        
            byte[] rand2 = RandomUtil.randomBytes(12);        
            byte[] seed = new byte[rand1.length + rand2.length];
            System.arraycopy(rand1, 0, seed, 0, rand1.length);
            System.arraycopy(rand2, 0, seed, rand1.length, rand2.length);
    
            AuthPacket auth = new AuthPacket();
            auth.packetId = 0;
            auth.clientFlags = getClientCapabilities();
            auth.maxPacketSize = 1024 * 1024 * 16;
            auth.user = "seaboat";        try {
                auth.password = SecurityUtil
                        .scramble411("seaboat".getBytes(), seed);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            auth.database = "test";
    
            ByteBuffer buffer = ByteBuffer.allocate(256);
            auth.write(buffer);
            buffer.flip();        byte[] bytes = new byte[buffer.remaining()];
            buffer.get(bytes, 0, bytes.length);
            String result = HexUtil.Bytes2HexString(bytes);
            System.out.println(result);
            assertTrue(Integer.valueOf(result.substring(0, 2), 16) == result
                    .length() / 2 - 4);
    
            AuthPacket auth2 = new AuthPacket();
            auth2.read(bytes);
            assertTrue(auth2.database.equals("test"));
        }    protected int getClientCapabilities() {        
        int flag = 0;
            flag |= Capabilities.CLIENT_LONG_PASSWORD;
            flag |= Capabilities.CLIENT_FOUND_ROWS;
            flag |= Capabilities.CLIENT_LONG_FLAG;
            flag |= Capabilities.CLIENT_CONNECT_WITH_DB;
            flag |= Capabilities.CLIENT_ODBC;
            flag |= Capabilities.CLIENT_IGNORE_SPACE;
            flag |= Capabilities.CLIENT_PROTOCOL_41;
            flag |= Capabilities.CLIENT_INTERACTIVE;
            flag |= Capabilities.CLIENT_IGNORE_SIGPIPE;
            flag |= Capabilities.CLIENT_TRANSACTIONS;
            flag |= Capabilities.CLIENT_SECURE_CONNECTION;        
            return flag;
        }
    }
    Copy after login


    The above is the detailed content of A detailed introduction to the authentication package and code of the mysql protocol. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template