이전에 알아보았던 RSA 와 AES 암호화를 혼합해서 사용하는 하이브리드 암호화 방식에 대해 알아보도록 하겠습니다. 이 방식은 대칭키 암호화(AES)와 비대칭키 암호화(RSA)를 함께 사용하여, 보안성과 성능을 모두 최적화하는 것이 목표입니다. 주로 RSA로 AES의 대칭키를 안전하게 전달하고, AES는 실제 데이터를 빠르고 효율적으로 암호화하는 방식으로 동작합니다.
서버는 대칭키인 AES 키와 비대칭 키인 RSA 키를 생성합니다. 대칭 키는 동일한 키로 암복호화가 가능하고, 비대칭 키는 Private key 로 암호화, Public key 로 복호화가 가능합니다.
데이터를 암호화 하기 위한 AES 비대칭 키를 전송합니다. 이 때, AES 키는 RSA Private key 로 암호화 하여 전송합니다. 결론적으로 RSA Private key로 암호화된 AES key 와 RSA 복호화를 위한 Public 키를 같이 전송합니다.
클라이언트는 받은 RSA Public key로 암호화된 AES key를 복호화 하고, AES key를 사용하여 데이터를 암호화 합니다. AES는 대용량 데이터를 암호화할 때 빠르게 처리할 수 있기 때문에, 대량의 데이터를 효율적으로 보호할 수 있습니다.
클라이언트는 AES로 암호화된 데이터를 전송하고, 서버는 받은 데이터를 AES 키로 복호화 합니다.
결론적으로 AES key로는 데이터를 암/복호화하고 RSA로는 AES의 키만 암/복호화 하는 방식입니다.
보안성
RSA의 비대칭키 암호화를 사용해 AES 대칭키를 안전하게 전송할 수 있으므로, AES 키 유출 위험을 줄일 수 있습니다.
성능
AES는 대칭키 암호화로 성능이 뛰어나 대량의 데이터를 효율적으로 처리할 수 있습니다.
확장성
AES 대칭키 암호화는 확장성이 좋으며, RSA로 AES 키만 전송하므로 키 관리가 간편합니다.
기존에 작성했던 RsaCryptoService 와 AesCryptoService 를 활용하겠습니다. Hybrid 방식만 사용하겠다면 기존 코드를 잘 조합해서 활용하세요.
common.encryption.hybrid.HybridCryptoService
@Slf4j
@Configuration
@RequiredArgsConstructor
public class HybridCryptoService implements CryptoService {
private final RsaCryptoService rsaCryptoService;
private final AesCryptoService aesCryptoService;
@Override
@Deprecated
public void createKey() throws NoSuchAlgorithmException {
}
@Override
public Key getPublicKey() {
return this.rsaCryptoService.getPublicKey();
}
@Override
public String decrypt(String encryptedText) {
return this.aesCryptoService.decrypt(encryptedText);
}
@Override
public String encrypt(String plainText) {
return this.aesCryptoService.encrypt(plainText);
}
public String getEncryptedAesKey() {
SecretKey secretKey = this.aesCryptoService.getPublicKey();
String secretKeyString = Base64.getEncoder().encodeToString(secretKey.getEncoded());
return this.rsaCryptoService.encrypt(secretKeyString);
}
}
위에서 설명한 것과 같이 RSA Public key 로 AES key 를 암호화하는 getEncryptedAesKey method 가 추가되었고, public key는 RSA의 Public key를, 암/복호화는 AES로 동작하고 있습니다.
기존 CryptoController 에 Hybrid key를 요청하는 method 를 추가하겠습니다.
domain.crypto.CryptoController
@RestController
@RequiredArgsConstructor
@Tag(name = "암호화 관련 정보 요청", description = "보안이 필요한 정보를 암호화 하기 위한 키 요청")
@RequestMapping("v1")
public class CryptoController {
private final CryptoService rsaCryptoService;
private final CryptoService aesCryptoService;
private final HybridCryptoService hybridCryptoService; //추가
private final MessageConfig messageConfig;
//생략..
@Operation(summary = "Hybrid Key 요청", description = """
Hybrid key<br />
RSA public key 와 RSA public key 로 암호화된 AES key 를 전달. (Base64 encoded)<br />
전달받은 RSA Public key 로 암호화된 AES 키를 복호화 하고,<br />
복호화된 AES key 로 데이터를 암호화 하여 전송
""", operationId = "API-999-03")
@PostMapping(value = "/key/hybrid", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ItemResponse<HybridKeyResponse>> getHybridKey() {
PublicKey publicKey = (PublicKey) this.hybridCryptoService.getPublicKey();
String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded());
String encryptedAesKey = this.hybridCryptoService.getEncryptedAesKey();
HybridKeyResponse hybridKeyResponse = HybridKeyResponse.builder()
.publicKey(publicKeyString)
.encryptedKey(encryptedAesKey)
.build();
return ResponseEntity.ok()
.body(ItemResponse.<HybridKeyResponse>builder()
.status(messageConfig.getCode(NormalCode.SEARCH_SUCCESS))
.message(messageConfig.getMessage(NormalCode.SEARCH_SUCCESS))
.item(hybridKeyResponse)
.build());
domain.crypto.record.HybridKeyResponse
@Builder
public record HybridKeyResponse(
String publicKey,
String encryptedKey
) {
}
클라이언트는 받은 public key 로 encryptedKey를 복호화 하여 AES key를 추출하고 AES key로 데이터를 암호화 하여 전송합니다. 서버는 암호화된 데이터는 AES key로 복호화 하여 처리합니다.
하이브리드 암호화는 RSA의 강력한 보안과 AES의 효율적인 성능을 동시에 충족하는 방식으로, 대규모 데이터 전송 및 보호가 중요한 다양한 시스템에서 필수적으로 사용되는 암호화 기법입니다. RSA와 AES의 장점을 결합한 이 방식은 데이터 기밀성과 전송 안전성을 극대화하며, 안정적이고 신뢰할 수 있는 보안 솔루션을 제공합니다.
단순히 몇몇 데이만 암호화 하는 경우에는 오버스펙이 될 수 있으니, 암호화 레벨, 주어진 환경에 따라 적절한 암호화 방식을 사용하도록 합시다.