Skip to content

cloude-lee/spring-kms-crypto-library

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Spring KMS Crypto Library

A Spring Boot library that provides encryption and decryption functionality using AWS KMS data keys with AES-256-GCM encryption.

Project Generation Prompt

This project was initially created using the following prompt:

Spring Boot Kotlin 라이브러리를 만들어줘. 이 라이브러리는 암호화 복호화 기능을 제공한다.
AWS KMS를 사용하여 data key를 생성하고, 이 data key를 이용하여 AES-256-GCM 방식으로 암호화 복호화를 수행한다.
사용자는 이 라이브러리를 dependency로 추가하여 사용할 수 있어야 한다.
Spring Boot의 auto-configuration을 사용하여 별도의 설정 없이도 기본적인 기능을 사용할 수 있도록 한다.
설정 파일(application.yml)에서 KMS 설정과 암호화 옵션을 지정할 수 있어야 한다.
키 로테이션을 지원하여 여러 버전의 키를 관리할 수 있어야 한다.

Subsequent modifications:

  1. Data Key Caching Implementation:
KmsDataKeyService를 통해 얻어온 data key는 이후 저장해서 계속 사용하고 싶다.

This resulted in adding a comprehensive caching mechanism with TTL and size limits for data keys.

  1. Package Name Change:
root package를 com.example.crypto 대신 com.musinsa.crypto.kms 로 변경해줘

Changed the root package from com.example.crypto to com.musinsa.crypto.kms.

  1. Cache Simplification:
data key는 instance가 떠있는 동안 계속 사용될 것이기 때문에 ttl이 필요없습니다.
cache는 항상사용할 것이기 때문에 cache.enabled 설정도 필요 없습니다
max-size 설정도 필요 없는 것 같습니다. 즉 최종적으로 cache 설정은 불필요해보입니다

Simplified caching to permanently store data keys for the instance lifetime without TTL, size limits, or configuration options.

Features

  • AES-256-GCM encryption/decryption
  • AWS KMS integration for data key management
  • Permanent data key caching for performance (cached for instance lifetime)
  • Spring Boot auto-configuration
  • Support for key rotation (multiple key versions)

Installation

Add the following dependency to your build.gradle.kts:

dependencies {
    implementation("com.musinsa:spring-kms-crypto-library:1.0.0")
}

Configuration

Configure the library in your application.yml:

crypto-kms:
  enabled: true
  aws-region: us-east-1
  current-key-id: v1
  encrypted-data-keys:
    v1: "Base64EncodedEncryptedDataKey1..."
    v2: "Base64EncodedEncryptedDataKey2..."

⚠️ Important: All configured data keys are decrypted at application startup. If any encrypted data key is missing or invalid, or if KMS is unavailable, the application will fail to start. This is a fail-fast approach to ensure data security and prevent runtime encryption/decryption failures.

Note: If a key that wasn't configured at startup is requested later (e.g., old keys for decryption), the library will attempt to decrypt it from KMS on-demand, which will increase latency and log a warning.

Usage

Basic Encryption/Decryption

@RestController
@RequestMapping("/api/crypto")
class CryptoController(
    private val cryptoService: CryptoService
) {
    
    @PostMapping("/encrypt")
    fun encrypt(@RequestBody request: CryptoRequest): CryptoResponse {
        return cryptoService.encrypt(request)
    }
    
    @PostMapping("/decrypt")
    fun decrypt(@RequestBody request: DecryptRequest): Map<String, String> {
        val plaintext = cryptoService.decrypt(request)
        return mapOf("plaintext" to plaintext)
    }
}

Generating Encrypted Data Keys

To generate encrypted data keys for configuration:

val kmsClient = KmsClient.builder()
    .region(Region.US_EAST_1)
    .build()

val generateDataKeyRequest = GenerateDataKeyRequest.builder()
    .keyId("your-kms-master-key-id")
    .keySpec(DataKeySpec.AES_256)
    .build()

val response = kmsClient.generateDataKey(generateDataKeyRequest)
val encryptedDataKey = Base64.getEncoder().encodeToString(
    response.ciphertextBlob().asByteArray()
)

API

CryptoService Interface

interface CryptoService {
    fun encrypt(request: CryptoRequest): CryptoResponse
    fun decrypt(request: DecryptRequest): String
}

Models

data class CryptoRequest(
    val plaintext: String
)

data class CryptoResponse(
    val keyId: String,        // Version identifier
    val encryptedText: String, // Base64 encoded
    val iv: String            // Base64 encoded IV
)

data class DecryptRequest(
    val keyId: String,
    val encryptedText: String,
    val iv: String
)

Security Considerations

  1. Data Key Storage: Encrypted data keys are stored in configuration and decrypted at startup using AWS KMS
  2. Key Rotation: Support multiple key versions for gradual key rotation
  3. Caching: Plaintext data keys are cached in memory for the lifetime of the application instance
  4. Encryption: Uses AES-256-GCM for authenticated encryption
  5. Startup Validation: All configured data keys must be valid and accessible via KMS at startup, or the application will fail to initialize

AWS IAM Permissions

Your application needs the following KMS permissions:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": "arn:aws:kms:region:account:key/*"
        }
    ]
}

Testing

Run tests with:

./gradlew test

License

Apache License 2.0

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages