提交 1ba7f9b1 编写于 作者: K KomachiSion

Refactor MySQLPasswordEncryptor

上级 74fb5fee
......@@ -11,6 +11,10 @@
<lombok.version>1.18.4</lombok.version>
<slf4j.version>1.7.28</slf4j.version>
<netty.version>4.1.16.Final</netty.version>
<junit.version>4.12</junit.version>
<hamcrest.version>1.3</hamcrest.version>
<mockito.version>2.7.21</mockito.version>
</properties>
<dependencies>
......@@ -65,6 +69,37 @@
<artifactId>mysql-binlog-connector-java</artifactId>
<version>0.20.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
......
......@@ -29,24 +29,36 @@ import java.security.NoSuchAlgorithmException;
public class MySQLPasswordEncryptor {
/**
* Encrypt password.
* Encrypt password with MySQL protocol 41.
*
* <p>
* MySQL Internals Manual / MySQL Client/Server Protocol / Authentication Method / Secure Password Authentication
* https://dev.mysql.com/doc/internals/en/secure-password-authentication.html
* </p>
*
* @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;
}
}
......@@ -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);
......
/*
* 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};
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册