Skip to content

Commit 00e8757

Browse files
committed
Feat: 암호화/복호화 기능을 위한 Crypto 클래스 추가
- 테스트 코드 추가
1 parent 90ad197 commit 00e8757

2 files changed

Lines changed: 138 additions & 0 deletions

File tree

  • core/security/src
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.threegap.bitnagil.security
2+
3+
import javax.crypto.Cipher
4+
import javax.crypto.spec.IvParameterSpec
5+
6+
class Crypto(
7+
private val keyProvider: KeyProvider,
8+
private val transformation: String = "AES/CBC/PKCS7Padding",
9+
) {
10+
fun encrypt(bytes: ByteArray): ByteArray {
11+
val cipher = Cipher.getInstance(transformation)
12+
cipher.init(Cipher.ENCRYPT_MODE, keyProvider.getKey())
13+
val iv = cipher.iv
14+
val encrypted = cipher.doFinal(bytes)
15+
return iv + encrypted
16+
}
17+
18+
fun decrypt(bytes: ByteArray): ByteArray {
19+
val cipher = Cipher.getInstance(transformation)
20+
val iv = bytes.copyOfRange(0, cipher.blockSize)
21+
val data = bytes.copyOfRange(cipher.blockSize, bytes.size)
22+
cipher.init(Cipher.DECRYPT_MODE, keyProvider.getKey(), IvParameterSpec(iv))
23+
return cipher.doFinal(data)
24+
}
25+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package com.threegap.bitnagil.security
2+
3+
import org.junit.Assert.assertEquals
4+
import org.junit.Assert.assertNotEquals
5+
import org.junit.Assert.assertThrows
6+
import org.junit.Test
7+
import javax.crypto.KeyGenerator
8+
import javax.crypto.SecretKey
9+
10+
class CryptoTest {
11+
private class FakeKeyProvider : KeyProvider {
12+
private val key: SecretKey =
13+
KeyGenerator
14+
.getInstance("AES")
15+
.apply { init(128) }
16+
.generateKey()
17+
18+
override fun getKey(): SecretKey = key
19+
}
20+
21+
private val crypto =
22+
Crypto(
23+
keyProvider = FakeKeyProvider(),
24+
transformation = "AES/CBC/PKCS5Padding",
25+
)
26+
27+
@Test
28+
fun `암호화 후 복호화하면 원래 데이터와 같아야 한다`() {
29+
// given
30+
val original = "테스트 데이터".toByteArray()
31+
32+
// when
33+
val encrypted = crypto.encrypt(original)
34+
val decrypted = crypto.decrypt(encrypted)
35+
36+
// then
37+
assertEquals(String(original), String(decrypted))
38+
}
39+
40+
@Test
41+
fun `같은 데이터를 암호화해도 결과는 달라야 한다`() {
42+
// given
43+
val input = "같은 입력".toByteArray()
44+
45+
// when
46+
val encrypted1 = crypto.encrypt(input)
47+
val encrypted2 = crypto.encrypt(input)
48+
49+
// then
50+
assertNotEquals(encrypted1.toList(), encrypted2.toList())
51+
}
52+
53+
@Test
54+
fun `잘못된 데이터로 복호화를 시도하면 예외가 발생해야 한다`() {
55+
// given
56+
val invalid = ByteArray(4) { 0x00 }
57+
58+
// when & then
59+
assertThrows(Exception::class.java) {
60+
crypto.decrypt(invalid)
61+
}
62+
}
63+
64+
@Test
65+
fun `IV 일부가 조작된 경우 복호화하면 원래 데이터와 달라야 한다`() {
66+
// given
67+
val original = "iv 테스트".toByteArray()
68+
val encrypted = crypto.encrypt(original)
69+
encrypted[0] = encrypted[0].inc()
70+
71+
// when
72+
val decrypted = crypto.decrypt(encrypted)
73+
74+
// then
75+
assertNotEquals(String(original), String(decrypted))
76+
}
77+
78+
@Test
79+
fun `암호화된 데이터가 조작된 경우 복호화 실패해야 한다`() {
80+
// given
81+
val original = "데이터 조작".toByteArray()
82+
val encrypted = crypto.encrypt(original)
83+
encrypted[encrypted.lastIndex] = encrypted.last().inc()
84+
85+
// when & then
86+
assertThrows(Exception::class.java) {
87+
crypto.decrypt(encrypted)
88+
}
89+
}
90+
91+
@Test
92+
fun `다른 키로 복호화하면 실패해야 한다`() {
93+
// given
94+
val original = "다른 키 테스트".toByteArray()
95+
val encrypted = crypto.encrypt(original)
96+
97+
val otherKeyProvider =
98+
object : KeyProvider {
99+
override fun getKey(): SecretKey {
100+
val keyGen = KeyGenerator.getInstance("AES")
101+
keyGen.init(128)
102+
return keyGen.generateKey()
103+
}
104+
}
105+
106+
val otherCrypto = Crypto(otherKeyProvider, "AES/CBC/PKCS5Padding")
107+
108+
// when & then
109+
assertThrows(Exception::class.java) {
110+
otherCrypto.decrypt(encrypted)
111+
}
112+
}
113+
}

0 commit comments

Comments
 (0)