본문 바로가기
Course/Spring Security

[netplix-security-a] PasswordEncoder 구현

by Lpromotion 2024. 10. 3.
Netplix 구독형 멤버십 프로젝트로 배우는 SpringSecurity
[Ch 4. PasswordEncoder] - 01. PasswordEncoder 살펴보기
강의를 바탕으로 실습 내용을 정리하였습니다.

목차
 

1. 키 생성기

키 생성기는 특정한 종류의 키를 생성하는 객체로 일반적으로 암호화해싱 알고리즘에 필요함

스프링 시큐리티에서 제공하는 키 생성기 인터페이스:

  • BytesKeyGenerator
  • StringKeyGenerator

 

StringKeyGenerator

문자열 키 생성기를 이용해 문자열 키를 얻을 수 있음

  • 이 키를 기반으로 해싱 또는 알고리즘의 솔트(salt) 값으로 이용할 수 있음

StringKeyGenerator 는 generateKey() 메소드를 제공함

 

StringKeyGenerator 와 솔팅

StringKeyGenerator 인스턴스를 얻고 솔트 값을 가져오는 예시

  • HexEncodingStringKeyGenerator: 8바이트 키를 생성하고 이를 16진수 문자열로 인코딩함
StringKeyGenerator generator = KeyGenerators.string();
String salt = generator.generateKey();

 

BytesKeyGenerator

byte[] 키를 반환하며 키 값의 길이를 반환하는 기능을 제공함

  • BytesKeyGenerator 는 generateKey() 메소드 뿐만 아니라 getKeyLength() 메소드를 제공함
  • generateKey() 가 호출될 때마다 매번 다른 고유한(unique) 키 값이 생성됨

 

BytesKeyGenerator 사용하기

BytesKeyGenerator generator = KeyGenerators.secureRandom();
byte[] key = generator.generateKey();
int length = generator.getKeyLength();

 

8바이트 길이의 키를 생성함

  • 다른 길이의 키를 생성하려면 KeyGenerators.secureRandom() 에 파라미터로 원하는 값을 전달하면 됨
  • KeyGenerators.secureRandom(16);: 16바이트 길이의 키가 생성됨

 

만약 매번 같은 키 값을 반환하는 로직이 필요한 경우에는 KeyGenerators.shared() 를 활용할 수 있음

BytesKeyGenerator generator = KeyGenerators.shared(16);
byte[] key1 = generator.generateKey();
byte[] key2 = generator.generateKey();
// key1과 key2는 값을 값을 가짐

 

테스트 코드

  • shared 로 생성된 key1 과 key2 가 동일한지 검증
package fast.campus.fcss01.generator;

import org.junit.jupiter.api.Test;
import org.springframework.security.crypto.keygen.BytesKeyGenerator;
import org.springframework.security.crypto.keygen.KeyGenerators;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class MyGeneratorTest {

    /** BytesKeyGenerator 사용하기 **/
    @Test
    public void test() {
        // given
        BytesKeyGenerator generator = KeyGenerators.shared(16);

        // when
        byte[] key1 = generator.generateKey();
        byte[] key2 = generator.generateKey();

        // then
        assertEquals(key1, key2);
    }
}

 

2. 암호기

암호기는 암호화 알고리즘을 구현하는 객체

암호화와 복호화는 보안을 위해 꼭 필요한 기능으로 애플리케이션에서 암호기를 많이 사용함

암호화는 서버 간 통신에서 데이터를 전송하거나 저장을 할 때 사용되는 경우가 많음

스프링 시큐리티에서는 아래 두 유형의 암호기가 정의되어 있음

  • BytesEncryptor
  • TextEncryptor

 

역할은 비슷하지만 다른 데이터 형식을 처리함에 있어 다름

⇒ BytesEncryptor는 Byte값을 핸들링, TextEncryptor은 String 값을 핸들링

 

TextEncryptor

TextEncryptor 는 두 개의 메소드를 제공함

  • 암호화를 나타내는 encrypt() 와 복호화를 나타내는 decrypt() 가 있음

 

BytesEncryptor

TextEncryptor 와 비슷하게 encrypt() 메소드와 decrypt() 메소드를 제공함

  • 인풋과 아웃풋에서 차이가 있음

 

Encryptors 팩토리 클래스

 

BytesEncryptors 암호기 사용

KeyGenerators.string() 기반으로 salt 생성

secret 과 salt 기반으로 BytesEncryptor 정의

  • 더 강력한 암호기를 만들기 위해서는 standard 대신 stronger 를 활용하면 됨

encrypt 하고자 하는 값은 “HELLO”

decrypt 한 결과값과 encrypt 와 동일한지 확인

/** BytesEncryptors 암호기 사용 **/
@Test
public void test2() {
    String salt = KeyGenerators.string().generateKey();
    String password = "secret";
    String valueToEncrypt = "HELLO";

    BytesEncryptor bytesEncryptor = Encryptors.standard(password, salt);
    byte[] encrypted = bytesEncryptor.encrypt(valueToEncrypt.getBytes());
    byte[] decrypted = bytesEncryptor.decrypt(encrypted);

    assertArrayEquals(valueToEncrypt.getBytes(), decrypted);
}

 

TextEncryptors 암호기 사용

TextEncryptors 는 두 가지 주요 형식이 존재함

  • Encryptors.text(), Encryptors.delux()

 

값을 암호화하지 않는 더미 TextEncryptor 도 존재함

  • Encryptors.noOpText()
/** TextEncryptors 암호기 사용 **/
@Test
public void test3() {
    String valueToEncrypt = "HELLO";

    TextEncryptor textEncryptor = Encryptors.noOpText();
    String encrypted = textEncryptor.encrypt(valueToEncrypt);
    String decrypted = textEncryptor.decrypt(encrypted);

    assertEquals(valueToEncrypt, decrypted);
}

 

암호화되지 않은 평문 그대로임을 확인할 수 있음

 

Encryptors.text() 암호기는 Encryptors.standard() 메소드를 암호화 작업에 사용함

Encryptors.delux() 암호기는 Encryptors.stronger() 메소드를 암호화 작업에 사용함

 

같은 입력으로 encrypt() 메소드를 반복 호출해도 다른 출력이 반환됨

  • 매번 새로운 값이 나올 수 있도록 초기화를 시키기 때문

 

값이 변경되는 것 확인

/** TextEncryptors의 encrypt()에서 매번 새로운 값이 나옴 **/
@Test
public void test4() {
    String salt = KeyGenerators.string().generateKey();
    String password = "secret";
    String valueToEncrypt = "HELLO";

    TextEncryptor textEncryptor = Encryptors.delux(password, salt);
    String encrypted = textEncryptor.encrypt(valueToEncrypt);
    String decrypted = textEncryptor.decrypt(encrypted);

    assertEquals(valueToEncrypt, decrypted);
}

 

encrypted 값이 호출할 때마다 다른 값이 반환되는 것을 확인할 수 있음

반응형

댓글