diff --git a/pom.xml b/pom.xml index 94e3389c07554e87ee315a47d6d2761771668405..187eb54a6fc7894eadca69e7f5cf509ae17d6ab8 100755 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,10 @@ 1.18.4 1.7.28 4.1.16.Final + + 4.12 + 1.3 + 2.7.21 @@ -65,6 +69,37 @@ mysql-binlog-connector-java 0.20.1 + + + junit + junit + ${junit.version} + test + + + org.hamcrest + hamcrest-library + ${hamcrest.version} + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + org.hamcrest + hamcrest-core + + + + + org.mockito + mockito-inline + ${mockito.version} + test + diff --git a/src/main/java/info/avalon566/shardingscaling/sync/mysql/binlog/MySQLPasswordEncryptor.java b/src/main/java/info/avalon566/shardingscaling/sync/mysql/binlog/MySQLPasswordEncryptor.java index 2d526aaaa5e33c3a3caecefe225fcc61bd3a0b15..a1407e5b47c840bcb61c7641d4a0698a15758ab3 100644 --- a/src/main/java/info/avalon566/shardingscaling/sync/mysql/binlog/MySQLPasswordEncryptor.java +++ b/src/main/java/info/avalon566/shardingscaling/sync/mysql/binlog/MySQLPasswordEncryptor.java @@ -29,24 +29,36 @@ import java.security.NoSuchAlgorithmException; public class MySQLPasswordEncryptor { /** - * Encrypt password. + * Encrypt password with MySQL protocol 41. + * + *

+ * MySQL Internals Manual / MySQL Client/Server Protocol / Authentication Method / Secure Password Authentication + * https://dev.mysql.com/doc/internals/en/secure-password-authentication.html + *

* * @param password password - * @param seed seed + * @param seed 20-bytes random data from server * @return encrypted password * @throws NoSuchAlgorithmException no such algorithm exception */ - public static byte[] scramble411(final byte[] password, final byte[] seed) throws NoSuchAlgorithmException { - MessageDigest md = MessageDigest.getInstance("SHA-1"); - byte[] pass1 = md.digest(password); - 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]); + public static byte[] encryptWithMySQL41(final byte[] password, final byte[] seed) throws NoSuchAlgorithmException { + MessageDigest messageDigest = MessageDigest.getInstance("SHA-1"); + byte[] passwordSha1 = messageDigest.digest(password); + byte[] concatSeed = concatSeed(messageDigest, seed, messageDigest.digest(passwordSha1)); + return xorPassword(passwordSha1, concatSeed); + } + + private static byte[] concatSeed(final MessageDigest messageDigest, final byte[] seed, final byte[] passwordSha1) { + messageDigest.update(seed); + messageDigest.update(passwordSha1); + return messageDigest.digest(); + } + + private static byte[] xorPassword(final byte[] passwordSha1, final byte[] concatSeed) { + byte[] result = new byte[concatSeed.length]; + for (int i = 0; i < concatSeed.length; i++) { + result[i] = (byte) (concatSeed[i] ^ passwordSha1[i]); } - return pass3; + return result; } } diff --git a/src/main/java/info/avalon566/shardingscaling/sync/mysql/binlog/packet/auth/ClientAuthenticationPacket.java b/src/main/java/info/avalon566/shardingscaling/sync/mysql/binlog/packet/auth/ClientAuthenticationPacket.java index cce7e71596cfd5658ebee4a28f517f9defe47704..d780b2627dc20335bfd47a13d9ba180382f2cdde 100644 --- a/src/main/java/info/avalon566/shardingscaling/sync/mysql/binlog/packet/auth/ClientAuthenticationPacket.java +++ b/src/main/java/info/avalon566/shardingscaling/sync/mysql/binlog/packet/auth/ClientAuthenticationPacket.java @@ -94,7 +94,7 @@ public final class ClientAuthenticationPacket extends AbstractPacket { DataTypesCodec.writeByte((byte) 0x00, result); } else { try { - byte[] encryptedPassword = MySQLPasswordEncryptor.scramble411(getPassword().getBytes(), scrumbleBuff); + byte[] encryptedPassword = MySQLPasswordEncryptor.encryptWithMySQL41(getPassword().getBytes(), scrumbleBuff); DataTypesCodec.writeLengthCodedBinary(encryptedPassword, result); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("can't encrypt password that will be sent to MySQL server.", e); diff --git a/src/test/java/info/avalon566/shardingscaling/sync/mysql/binlog/MySQLPasswordEncryptorTest.java b/src/test/java/info/avalon566/shardingscaling/sync/mysql/binlog/MySQLPasswordEncryptorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0213f908c8b96a570495d90685ab720a03044b80 --- /dev/null +++ b/src/test/java/info/avalon566/shardingscaling/sync/mysql/binlog/MySQLPasswordEncryptorTest.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package info.avalon566.shardingscaling.sync.mysql.binlog; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.security.NoSuchAlgorithmException; + +import org.junit.Test; + +public class MySQLPasswordEncryptorTest { + + @Test + public void assertEncryptWithMySQL41() throws NoSuchAlgorithmException { + byte[] passwordBytes = "password".getBytes(); + byte[] seed = getRandomSeed(); + assertThat(MySQLPasswordEncryptor.encryptWithMySQL41(passwordBytes, seed), is(getExpectedPassword())); + } + + private byte[] getRandomSeed() { + byte[] result = new byte[20]; + for (int i = 0; i < result.length; i++) { + result[i] = (byte) i; + } + return result; + } + + private byte[] getExpectedPassword() { + return new byte[] {-110, -31, 48, -32, -22, -29, 54, -40, 54, 118, -119, -16, -96, -25, 121, -64, -75, -103, 73, -44}; + } +}