-
Notifications
You must be signed in to change notification settings - Fork 2
feat: 어드민 비밀번호 수정 API 구현 #346
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| package com.listywave.admin; | ||
|
|
||
| public record AdminUpdateRequest( | ||
| String password | ||
| ) { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| package com.listywave.common.encrypt; | ||
|
|
||
| import static com.listywave.common.exception.ErrorCode.ENCRYPT_ERROR; | ||
|
|
||
| import com.listywave.common.exception.CustomException; | ||
| import jakarta.annotation.PostConstruct; | ||
| import java.security.InvalidAlgorithmParameterException; | ||
| import java.security.InvalidKeyException; | ||
| import java.security.NoSuchAlgorithmException; | ||
| import java.security.SecureRandom; | ||
| import java.security.spec.InvalidKeySpecException; | ||
| import java.security.spec.KeySpec; | ||
| import java.util.Base64; | ||
| import javax.crypto.BadPaddingException; | ||
| import javax.crypto.Cipher; | ||
| import javax.crypto.IllegalBlockSizeException; | ||
| import javax.crypto.NoSuchPaddingException; | ||
| import javax.crypto.SecretKey; | ||
| import javax.crypto.SecretKeyFactory; | ||
| import javax.crypto.spec.IvParameterSpec; | ||
| import javax.crypto.spec.PBEKeySpec; | ||
| import javax.crypto.spec.SecretKeySpec; | ||
| import org.springframework.beans.factory.annotation.Value; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| @Component | ||
| public class Aes256Cipher { | ||
|
|
||
| private static final String ALGORITHM = "AES/CBC/PKCS5Padding"; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 그런데 이런 값을 프로필에 안넣고 노출시켜도 될까요??
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 음 애초에 클래스 이름부터 암호화 알고리즘을 나타내기 때문에, 숨길 필요가 있을까 싶긴 합니다.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 확인했습니다!
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아 추가로, AES 암호화는 일반 사용자 대상으로 사용할 예정입니다! |
||
|
|
||
| @Value("${aes.password}") | ||
| private String password; | ||
| @Value("${aes.salt}") | ||
| private String salt; | ||
|
|
||
| private SecretKey secretKey; | ||
| private IvParameterSpec iv; | ||
|
|
||
| @PostConstruct | ||
| public void init() throws NoSuchAlgorithmException, InvalidKeySpecException { | ||
| this.secretKey = createSecretKey(); | ||
| this.iv = createIv(); | ||
| } | ||
|
|
||
| private SecretKey createSecretKey() throws NoSuchAlgorithmException, InvalidKeySpecException { | ||
| SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto |
||
| KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 65536, 256); | ||
| return new SecretKeySpec(secretKeyFactory.generateSecret(keySpec).getEncoded(), "AES"); | ||
| } | ||
|
|
||
| private IvParameterSpec createIv() { | ||
| byte[] iv = new byte[16]; | ||
| new SecureRandom().nextBytes(iv); | ||
| return new IvParameterSpec(iv); | ||
| } | ||
|
|
||
| public String encrypt(String plainText) { | ||
| try { | ||
| Cipher cipher = Cipher.getInstance(ALGORITHM); | ||
| cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv); | ||
| byte[] cipherText = cipher.doFinal(plainText.getBytes()); | ||
| return Base64.getEncoder().encodeToString(cipherText); | ||
| } catch ( | ||
| NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException | | ||
| InvalidAlgorithmParameterException | BadPaddingException | InvalidKeyException e) { | ||
| throw new CustomException(ENCRYPT_ERROR, e.getMessage()); | ||
| } | ||
| } | ||
|
|
||
| public String decrypt(String cipherText) { | ||
| try { | ||
| Cipher cipher = Cipher.getInstance(ALGORITHM); | ||
| cipher.init(Cipher.DECRYPT_MODE, secretKey, iv); | ||
| byte[] plainText = cipher.doFinal(Base64.getDecoder().decode(cipherText)); | ||
| return new String(plainText); | ||
| } catch ( | ||
| NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException | | ||
| InvalidAlgorithmParameterException | BadPaddingException | InvalidKeyException e) { | ||
| throw new RuntimeException(e); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package com.listywave.common.encrypt; | ||
|
|
||
| import java.security.MessageDigest; | ||
| import java.security.NoSuchAlgorithmException; | ||
| import org.springframework.beans.factory.annotation.Value; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| @Component | ||
| public class Sha256Cipher { | ||
|
|
||
| @Value("${sha.salt}") | ||
| private String salt; | ||
|
|
||
| public String encrypt(String plainText) { | ||
| try { | ||
| MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); | ||
| byte[] encodedHash = messageDigest.digest(plainText.concat(salt).getBytes()); | ||
| return bytesToHex(encodedHash); | ||
| } catch (NoSuchAlgorithmException e) { | ||
| throw new RuntimeException(e); | ||
| } | ||
| } | ||
|
|
||
| private String bytesToHex(byte[] encodedHash) { | ||
| StringBuilder hexString = new StringBuilder(2 * encodedHash.length); | ||
|
|
||
| for (byte hash : encodedHash) { | ||
| String hex = Integer.toHexString(0xff & hash); | ||
| if (hex.length() == 1) { | ||
| hexString.append('0'); | ||
| } | ||
| hexString.append(hex); | ||
| } | ||
| return hexString.toString(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| package com.listywave.common.encrypt; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
| import static org.junit.jupiter.api.Assertions.assertAll; | ||
|
|
||
| import com.listywave.common.IntegrationTest; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| class Aes256CipherTest extends IntegrationTest { | ||
|
|
||
| @Test | ||
| void 암호화를_한다() { | ||
| // given | ||
| String plainText = "plain"; | ||
|
|
||
| // when | ||
| String result = aes256Cipher.encrypt(plainText); | ||
| String result2 = aes256Cipher.encrypt(plainText); | ||
| String result3 = aes256Cipher.encrypt(plainText); | ||
|
|
||
| // then | ||
| assertAll( | ||
| () -> assertThat(result).isEqualTo(result2).isEqualTo(result3), | ||
| () -> assertThat(plainText).isNotEqualTo(result) | ||
| .isNotEqualTo(result2) | ||
| .isNotEqualTo(result3) | ||
| ); | ||
| } | ||
|
|
||
| @Test | ||
| void 복호화를_한다() { | ||
| // given | ||
| String plainText = "plain"; | ||
|
|
||
| String encrypted = aes256Cipher.encrypt(plainText); | ||
|
|
||
| // when | ||
| String decrypted = aes256Cipher.decrypt(encrypted); | ||
|
|
||
| // then | ||
| assertThat(plainText).isEqualTo(decrypted); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package com.listywave.common.encrypt; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
|
|
||
| import com.listywave.common.IntegrationTest; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| class Sha256CipherTest extends IntegrationTest { | ||
|
|
||
| @Test | ||
| void 암호화를_한다() { | ||
| // given | ||
| String plainText = "1234"; | ||
|
|
||
| // when | ||
| String encrypted1 = sha256Cipher.encrypt(plainText); | ||
| String encrypted2 = sha256Cipher.encrypt(plainText); | ||
|
|
||
| // then | ||
| assertThat(plainText).isNotEqualTo(encrypted1); | ||
| assertThat(encrypted1).isEqualTo(encrypted2); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,3 +58,9 @@ jwt: | |
| local-login: | ||
| id: | ||
| password: | ||
|
|
||
| aes: | ||
| password: 12345 | ||
| salt: 54321 | ||
| sha: | ||
| salt: 12345 | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍🏻