Skip to content

Commit

Permalink
feat: (#490) kms config & adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
rlaisqls committed May 9, 2023
1 parent 82b1dac commit dd960ba
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 0 deletions.
12 changes: 12 additions & 0 deletions dms-core/src/main/kotlin/team/aliens/dms/common/spi/EncryptPort.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package team.aliens.dms.common.spi

interface EncryptPort {

fun symmetricEncrypt(secretKey: String, plainText: String): String

fun symmetricDecrypt(secretKey: String, cipherText: String): String

fun asymmetricEncrypt(plainText: String): String

fun asymmetricDecrypt(cipherText: String): String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package team.aliens.dms.thirdparty.encrypt

import com.amazonaws.services.kms.AWSKMSAsync
import com.amazonaws.services.kms.model.DecryptRequest
import com.amazonaws.services.kms.model.EncryptRequest
import com.amazonaws.services.kms.model.EncryptionAlgorithmSpec
import org.springframework.cache.annotation.Cacheable
import org.springframework.stereotype.Component
import team.aliens.dms.common.spi.EncryptPort
import team.aliens.dms.thirdparty.encrypt.exception.KMSException
import java.nio.ByteBuffer
import java.util.Base64
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec

@Component
class AwsKMSAdapter(
private val awskmsAsync: AWSKMSAsync,
private val awsKMSProperties: AwsKMSProperties,
) : EncryptPort {

companion object {
private const val ENCRYPT_TRANSFORMATION = "AES/ECB/PKCS5Padding"
private const val ENCRYPT_ALGORITHM = "AES"
}

override fun symmetricEncrypt(
secretKey: String,
plainText: String,
): String {
val cipher = getCipher(Cipher.ENCRYPT_MODE, secretKey)
return String(
cipher.doFinal(plainText.toByteArray()).encodeBase64()
)
}

override fun symmetricDecrypt(
secretKey: String,
cipherText: String,
): String {
val cipher = getCipher(Cipher.DECRYPT_MODE, secretKey)
return String(
cipher.doFinal(cipherText.decodeBase64())
)
}

@Cacheable("cipher")
protected fun getCipher(opmode: Int, key: String): Cipher =
Cipher.getInstance(ENCRYPT_TRANSFORMATION).apply {
init(opmode, SecretKeySpec(key.toByteArray(), ENCRYPT_ALGORITHM))
}

override fun asymmetricEncrypt(plainText: String): String {

val request = EncryptRequest()
.withKeyId(awsKMSProperties.key)
.withPlaintext(ByteBuffer.wrap(plainText.toByteArray()))
.withEncryptionAlgorithm(EncryptionAlgorithmSpec.RSAES_OAEP_SHA_256)

val encryptedByte = runCatching {
awskmsAsync.encrypt(request).ciphertextBlob.array()
}.onFailure { e ->
e.printStackTrace()
throw KMSException
}.getOrThrow()

return String(
encryptedByte.encodeBase64()
)
}

@Cacheable("decryptedText")
override fun asymmetricDecrypt(cipherText: String): String {

val request = DecryptRequest()
.withKeyId(awsKMSProperties.key)
.withCiphertextBlob(ByteBuffer.wrap(cipherText.decodeBase64()))
.withEncryptionAlgorithm(EncryptionAlgorithmSpec.RSAES_OAEP_SHA_256)

val decryptedByte = runCatching {
awskmsAsync.decrypt(request).plaintext.array()
}.onFailure { e ->
e.printStackTrace()
throw KMSException
}.getOrThrow()

return String(decryptedByte)
}

// byteArray를 String으로 바로 변환하면 padding이 깨지는 문제가 발생하기 때문에
// encoding 결과를 Base64로 암호화하여 저장한다.
private fun ByteArray.encodeBase64() = Base64.getEncoder().encode(this)
private fun String.decodeBase64() = Base64.getDecoder().decode(this)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package team.aliens.dms.thirdparty.encrypt

import com.amazonaws.auth.AWSStaticCredentialsProvider
import com.amazonaws.auth.BasicAWSCredentials
import com.amazonaws.regions.Regions
import com.amazonaws.services.kms.AWSKMSAsync
import com.amazonaws.services.kms.AWSKMSAsyncClient
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import team.aliens.dms.thirdparty.AwsProperties

@Configuration
class AwsKMSConfiguration(
private val awsProperties: AwsProperties
) {
@Bean
fun awsKMSAsync(): AWSKMSAsync {
val basicAWSCredentials = BasicAWSCredentials(awsProperties.accessKey, awsProperties.secretKey)

return AWSKMSAsyncClient.asyncBuilder()
.withCredentials(AWSStaticCredentialsProvider(basicAWSCredentials))
.withRegion(Regions.AP_NORTHEAST_2)
.build()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package team.aliens.dms.thirdparty.encrypt

import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.ConstructorBinding

@ConfigurationProperties("cloud.aws.kms")
@ConstructorBinding
class AwsKMSProperties(
val key: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package team.aliens.dms.thirdparty.encrypt.exception

import team.aliens.dms.common.error.DmsException
import team.aliens.dms.global.error.GlobalErrorCode

object KMSException : DmsException(
GlobalErrorCode.KEY_MANAGEMENT_SERVICE
)

0 comments on commit dd960ba

Please sign in to comment.