BCrypt matches 동작 방식 : 매번 다른 해싱에도 일치 검증 가능한 이유

2024. 10. 25. 19:57·Programming/Java,Back-end

 

BCrypt로 인코딩을 해보면 같은 평문이라도 해싱 결과값이 매번 다른데,
어떻게 두 문자열의 값이 같다고 판단하는 걸까?

 

 


 

BCrypt Encode (암호화 과정)

BCrypt는 무작위로 생성되는 솔트라는 데이터를 해시 과정에서 비밀번호에 추가하여 해시 결과가 매번 달라지도록 만든다.

@Override
public String encode(CharSequence rawPassword) {
	if (rawPassword == null) {
		throw new IllegalArgumentException("rawPassword cannot be null");
	}
	String salt = getSalt();
	return BCrypt.hashpw(rawPassword.toString(), salt);
}

 

getSalt 메서드를 사용하여 salt 값을 만들어낸다. 그리고 해당 salt 값을 사용하여 해시를 수행한다.

 

mathces 동작 방식

✔️ matches

평문의 비밀번호와 암호화된 비밀번호가 서로 일치하는지 확인하는 matches() 메서드 동작 방식 알아보기.

@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
	// ...
	return BCrypt.checkpw(rawPassword.toString(), encodedPassword);
}
	
public static boolean checkpw(String plaintext, String hashed) {
	byte[] passwordb = plaintext.getBytes(StandardCharsets.UTF_8);
	return equalsNoEarlyReturn(hashed, hashpwforcheck(passwordb, hashed));
}
	
static boolean equalsNoEarlyReturn(String a, String b) {
	return MessageDigest.isEqual(a.getBytes(StandardCharsets.UTF_8), b.getBytes(StandardCharsets.UTF_8));
}

 

일치 여부를 최종적으로 리턴하는 equalsNoEarlyReturn까지의 과정에 있어서, 암호화할때 사용했던 hashpw 메서드를 여기서도 사용하는것을 찾아볼 수 있다.

private static String hashpwforcheck(byte[] passwordb, String salt) {
	return hashpw(passwordb, salt, true);
}

 

 

✔️ hashpw() 메소드

private static String hashpw(byte passwordb[], String salt, boolean for_check) {
	BCrypt B;
	String real_salt;
	byte saltb[], hashed[];
	char minor = (char) 0;
	int rounds, off;
	StringBuilder rs = new StringBuilder();

	// 생략...
		
	// 솔트 값 추출
	real_salt = salt.substring(off + 3, off + 25);
	saltb = decode_base64(real_salt, BCRYPT_SALT_LEN);**

	if (minor >= 'a') {
		passwordb = Arrays.copyOf(passwordb, passwordb.length + 1);
	}
		
	// 해싱 프로세스
	B = new BCrypt();
	hashed = B.crypt_raw(passwordb, saltb, rounds, minor == 'x', minor == 'a' ? 0x10000 : 0, for_check);
		
	// 결과 해시 생성
	rs.append("$2");
	if (minor >= 'a') {
		rs.append(minor);
	}
	rs.append("$");
	if (rounds < 10) {
		rs.append("0");
	}
	rs.append(rounds);
	rs.append("$");
	encode_base64(saltb, saltb.length, rs);
	encode_base64(hashed, bf_crypt_ciphertext.length * 4 - 1, rs);
	return rs.toString();
}

 

동작 방식

솔트 값 추출 : 암호화된 문자열에서 실제 솔트 값을 추출하고 이를 디코딩한다.

해싱 프로세스 : 실제 솔트값을 사용해 일치 여부를 확인할 평문 비밀번호의 해싱을 수행한다.

결과 해시 생성 : 적절한 접두사 및 라운드 그리고 해시 결과를 포함여 최종 해시 문자열을 구성한다.

​

요약

저장된 비밀번호에서 실제 솔트를 추출 후, 입력한 비밀번호에 대해 솔트를 사용하여 해싱 프로세스를 거친다. 최종적인 해시 결과를 비교하여 일치 여부를 확인하는 것이다.

'Programming > Java,Back-end' 카테고리의 다른 글

[Java] 익명 클래스와 람다(Lambda) 정리  (0) 2024.10.29
[Gradle] runtimeOnly, implementation, compileOnly, api 차이  (0) 2024.10.26
[Java] 메인 메소드 존재 이유, 매개변수 String[] args에 대하여  (0) 2024.10.26
ObjectMapper 싱글톤 빈으로 사용해도 될까?  (1) 2024.09.14
DAO와 Repository는 다른 개념일까?(차이를 구분할때의 장점)  (2) 2024.05.01
'Programming/Java,Back-end' 카테고리의 다른 글
  • [Gradle] runtimeOnly, implementation, compileOnly, api 차이
  • [Java] 메인 메소드 존재 이유, 매개변수 String[] args에 대하여
  • ObjectMapper 싱글톤 빈으로 사용해도 될까?
  • DAO와 Repository는 다른 개념일까?(차이를 구분할때의 장점)
우니wooni
우니wooni
  • 우니wooni
    woonDev
    우니wooni
  • 전체
    오늘
    어제
    • 전체
      • Programming
        • Java,Back-end
        • Spring,JPA
        • OS
        • Network
        • 기술 면접 대비
      • Books
        • MySQL 8.0
      • Side Project
        • Study Together
      • Life
        • 회고
        • 일상 이야기
  • 블로그 메뉴

    • 홈
    • GitHub
  • 링크

    • GitHub
  • 공지사항

  • 인기 글

  • 태그

    스프링
    Optimistic Lock
    Spring
    낙관적 락
    디자인 패턴
    Java
    Persistence Context
    Pessimistic lock
    동시성
    event-driven architecture
    redis
    비관적 락
    익명 클래스
    비동기
    영속성 컨텍스트
    동시성 제어
    hibernate
    람다
    레디스
    이벤트 기반 구조
    JPA
    추상화
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
우니wooni
BCrypt matches 동작 방식 : 매번 다른 해싱에도 일치 검증 가능한 이유
상단으로

티스토리툴바