250x250
Notice
Recent Posts
Recent Comments
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- JavaScript
- Spring Boot
- Open Source
- myBatis
- MSSQL
- error
- IntelliJ
- ubuntu
- JDBC
- git
- spring
- Python
- Source
- Thymeleaf
- maven
- PostgreSQL
- oracle
- Docker
- jpa
- 오픈소스
- Exception
- SpringBoot
- Tomcat
- AJAX
- MySQL
- Eclipse
- 문서
- Core Java
- STS
- 설정
Archives
- Today
- Total
헤르메스 LIFE
[Open Source] MySql Password Encoder 본문
728x90
MySQL에는 PASSWORD(str)이란 함수가 있습니다.
MySQL에는 OLD_PASSWORD()와 PASSWORD()로 나누어져있습니다.
MySQL 4.1이전에 사용하던 OLD_PASSWORD() 함수와 이후에 사용하는 PASSWORD()란 함수 입니다.
사용할 일이 있을 지... 혹시 몰라 크롤링(?) 해둡니다.
소스를 오픈해주신 분들께 감사드립니다.
1. PASSWORD 함수 소스
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* MySql의 password() 알고리즘으로 구현된 Password Encoder
*
* @author Antop
*/
public class MySqlPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
if (rawPassword == null) {
throw new NullPointerException();
}
byte[] bpara = new byte[rawPassword.length()];
byte[] rethash;
int i;
for (i = 0; i < rawPassword.length(); i++)
bpara[i] = (byte) (rawPassword.charAt(i) & 0xff);
try {
MessageDigest sha1er = MessageDigest.getInstance("SHA1");
rethash = sha1er.digest(bpara); // stage1
rethash = sha1er.digest(rethash); // stage2
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
StringBuffer r = new StringBuffer(41);
r.append("*");
for (i = 0; i < rethash.length; i++) {
String x = Integer.toHexString(rethash[i] & 0xff).toUpperCase();
if (x.length() < 2)
r.append("0");
r.append(x);
}
return r.toString();
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
if (encodedPassword == null || rawPassword == null) {
return false;
}
if (!encodedPassword.equals(encode(rawPassword))) {
return false;
}
return true;
}
}
출처 : https://antop.tistory.com/entry/Spring-Security-Session-Destroy
1. PASSWORD 함수 또 다른 소스
/**
* <p>입력한 데이터(바이트 배열)을 SHA1 알고리즘으로 처리하여 해쉬값을 도출한다.</p>
*
* <pre>
* getHash([0x68, 0x61, 0x6e]) = [0x4f, 0xf6, 0x15, 0x25, 0x34, 0x69, 0x98, 0x99, 0x32, 0x53, 0x2e, 0x92, 0x60, 0x06, 0xae, 0x5c, 0x99, 0x5e, 0x5d, 0xd6]
* </pre>
*
* @param input 입력 데이터(<code>null</code>이면 안된다.)
* @return 해쉬값
*/
public static byte[] getHash(byte[] input) {
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
return md.digest(input);
} catch (NoSuchAlgorithmException e) {
// 일어날 경우가 없다고 보지만 만약을 위해 Exception 발생
throw new RuntimeException("SHA1" + " Algorithm Not Found", e);
}
}
/**
* <p>>MySQL 의 PASSWORD() 함수.</p>
*
* <pre>
* MySqlFunction.password(null) = null
* MySqlFunction.password("mypassword".getBytes()) = "*FABE5482D5AADF36D028AC443D117BE1180B9725"
* </pre>
*
* @param input
* @return
*/
public static String password(byte[] input) {
byte[] digest = null;
// Stage 1
digest = getHash(input);
// Stage 2
digest = getHash(digest);
StringBuilder sb = new StringBuilder(1 + digest.length);
sb.append("*");
sb.append(ByteUtils.toHexString(digest).toUpperCase());
return sb.toString();
}
/**
* <p>>MySQL 의 PASSWORD() 함수.</p>
*
* <pre>
* MySqlFunction.password(null) = null
* MySqlFunction.password("mypassword") = "*FABE5482D5AADF36D028AC443D117BE1180B9725"
* </pre>
*
* @param input
* @return
* @throws NoSuchAlgorithmException
*/
public static String password(String input) {
if (input == null) {
return null;
}
return password(input.getBytes());
}
/**
* <p>>MySQL 의 PASSWORD() 함수.</p>
*
* <pre>
* MySqlFunction.password(null, *) = null
* MySqlFunction.password("mypassword", "ISO-8859-1") = "*FABE5482D5AADF36D028AC443D117BE1180B9725"
* </pre>
*
* @param input
* @param charsetName
* @return
* @throws UnsupportedEncodingException
*/
public static String password(String input, String charsetName) throws UnsupportedEncodingException {
if (input == null) {
return null;
}
return password(input.getBytes(charsetName));
}
SHA1을 두번 사용해서 출약메시지를 만들다음 16진수 문자열로 변환하여 앞에다 "*"를 붙여준 것 뿐.
테스트
@Test
public void testPasswordString() {
Assert.assertEquals((MySqlFunction.password("mypass"), "*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4");
Assert.assertEquals((MySqlFunction.password("passwordtest"), "*A76A397AE758994B641D5C456139B88F40610926");
}
3. OLD_PASSWORD 함수 소스
- 방황 끝에 찾에낸것은 sql/password.c 소스였다. 이 소스에 보면 아래처럼 구현되어 있다.
/*
Generate binary hash from raw text string
Used for Pre-4.1 password handling
SYNOPSIS
hash_password()
result OUT store hash in this location
password IN plain text password to build hash
password_len IN password length (password may be not null-terminated)
*/
void hash_password(ulong *result, const char *password, uint password_len)
{
register ulong nr=1345345333L, add=7, nr2=0x12345671L;
ulong tmp;
const char *password_end= password + password_len;
for (; password < password_end; password++)
{
if (*password == ' ' || *password == '\t')
continue; /* skip space in password */
tmp= (ulong) (uchar) *password;
nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
nr2+=(nr2 << 8) ^ nr;
add+=tmp;
}
result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */;
result[1]=nr2 & (((ulong) 1L << 31) -1L);
이것을 자바로 구현
/**
* <p>>MySQL 의 OLD_PASSWORD() 함수.</p>
*
* <pre>
* MySqlFunction.oldPassword(null) = null
* MySqlFunction.oldPassword("mypassword".getBytes()) = 162eebfb6477e5d3
* </pre>
*
* @param input
* @return
*/
public static String oldPassword(byte[] input) {
if (input == null || input.length <= 0) {
return null;
}
long nr = 1345345333L;
long add = 7;
long nr2 = 0x12345671L;
for (int i = 0; i < input.length; i++) {
if (input[i] == ' ' || input[i] == '\t') {
continue;
}
nr ^= (((nr & 63) + add) * input[i]) + (nr << 8);
nr2 += (nr2 << 8) ^ nr;
add += input[i];
}
nr = nr & 0x7FFFFFFFL;
nr2 = nr2 & 0x7FFFFFFFL;
StringBuilder sb = new StringBuilder(16);
sb.append(Long.toString((nr & 0xF0000000) >> 28, 16));
sb.append(Long.toString((nr & 0xF000000) >> 24, 16));
sb.append(Long.toString((nr & 0xF00000) >> 20, 16));
sb.append(Long.toString((nr & 0xF0000) >> 16, 16));
sb.append(Long.toString((nr & 0xF000) >> 12, 16));
sb.append(Long.toString((nr & 0xF00) >> 8, 16));
sb.append(Long.toString((nr & 0xF0) >> 4, 16));
sb.append(Long.toString((nr & 0x0F), 16));
sb.append(Long.toString((nr2 & 0xF0000000) >> 28, 16));
sb.append(Long.toString((nr2 & 0xF000000) >> 24, 16));
sb.append(Long.toString((nr2 & 0xF00000) >> 20, 16));
sb.append(Long.toString((nr2 & 0xF0000) >> 16, 16));
sb.append(Long.toString((nr2 & 0xF000) >> 12, 16));
sb.append(Long.toString((nr2 & 0xF00) >> 8, 16));
sb.append(Long.toString((nr2 & 0xF0) >> 4, 16));
sb.append(Long.toString((nr2 & 0x0F), 16));
return sb.toString();
}
/**
* <p>>MySQL 의 OLD_PASSWORD() 함수.</p>
*
* <pre>
* MySqlFunction.oldPassword(null) = null
* MySqlFunction.oldPassword("mypassword") = "162eebfb6477e5d3"
* </pre>
*
* @param input
* @return
*/
public static String oldPassword(String input) {
if (input == null) {
return null;
}
return oldPassword(input.getBytes());
}
/**
* <p>>MySQL 의 OLD_PASSWORD() 함수.</p>
*
* <pre>
* MySqlFunction.oldPassword(null, *) = null
* MySqlFunction.oldPassword("mypassword", "ISO-8859-1") = "162eebfb6477e5d3"
* </pre>
*
* @param input
* @param charsetName
* @return
* @throws UnsupportedEncodingException
*/
public static String oldPassword(String input, String charsetName) throws UnsupportedEncodingException {
if (input == null) {
return null;
}
return oldPassword(input.getBytes(charsetName));
}
테스트
@Test
public void testOldPasswordString() {
Assert.assertEquals((MySqlFunction.oldPassword("mypass"), "6f8c114b58f2ce9e");
Assert.assertEquals((MySqlFunction.oldPassword("passwordtest"), "071e82b12678dc44");
}
잘 작동하는것을 확인할 수 있다. (그런데 문자열을 한글로 넘기면 엉뚱한 값이 계산된다. 필자의 내공으로는 고칠수 가 없다. ) 라고 합니다.
출처 : http://blog.kangwoo.kr/45
728x90
'Core Java' 카테고리의 다른 글
[오픈소스] DBConnectionManager.java (0) | 2022.08.15 |
---|---|
CXF 2.3.11 설정 (0) | 2022.08.11 |
[Source] Apache commons FTPClient Java example - Download files from server (0) | 2022.03.15 |
[Core Java] File List 떨구는 샘플 (0) | 2021.03.23 |
[Core Java] 외부명령 실행하기 (0) | 2021.03.23 |