From dfee41a74094d9927e6f2dac00a9bd0e8d4fb26e Mon Sep 17 00:00:00 2001 From: Elex Date: Wed, 12 Mar 2025 10:43:35 +0900 Subject: [PATCH] 2025-03-12T10:43:35 --- docs/RxJava.md | 238 +++++++++++++++ docs/database/database.md | 164 +++++++++++ docs/security/bouncy castle.md | 263 +++++++++++++++++ docs/security/cipher.md | 240 ++++++++++++++++ docs/security/jce.md | 508 +++++++++++++++++++++++++++++++++ docs/security/pbkd.md | 164 +++++++++++ 6 files changed, 1577 insertions(+) create mode 100644 docs/RxJava.md create mode 100644 docs/database/database.md create mode 100644 docs/security/bouncy castle.md create mode 100644 docs/security/cipher.md create mode 100644 docs/security/jce.md create mode 100644 docs/security/pbkd.md diff --git a/docs/RxJava.md b/docs/RxJava.md new file mode 100644 index 0000000..b58849a --- /dev/null +++ b/docs/RxJava.md @@ -0,0 +1,238 @@ +### RxJava란? +RxJava(ReactX for Java)는 **반응형 프로그래밍(Reactive Programming)** 을 Java에서 구현할 수 있도록 만든 라이브러리야. 비동기 데이터 흐름을 다루기 쉽게 만들어주고, 함수형 스타일의 연산자를 통해 데이터를 조작할 수 있게 해. + +--- + +### 왜 RxJava를 사용할까? +Java에서 비동기 작업을 하려면 **`Thread`**, **`Executor`**, **`Future`**, **`Callback`** 같은 것들을 써야 하는데, 이 방식들은 코드가 복잡해지고 가독성이 떨어지는 단점이 있어. +RxJava는 이를 더 **선언적으로** 작성할 수 있도록 해주고, 다음과 같은 장점을 제공해: + +1. **비동기 처리** – `Observable`을 사용하여 비동기적으로 데이터를 생성하고 소비할 수 있어. +2. **함수형 조합** – `map`, `filter`, `flatMap` 등의 연산자를 사용해 데이터를 변환하고 조작할 수 있어. +3. **스트림 기반 처리** – 데이터가 하나씩 처리되는 것이 아니라 스트림으로 들어오는 데이터를 반응형으로 처리할 수 있어. +4. **에러 처리** – `onError` 핸들링을 통해 예외를 쉽게 관리할 수 있어. +5. **백프레셔(Backpressure) 지원** – 소비자가 데이터를 처리할 수 없을 때 과부하를 방지할 수 있어. + +--- + +### RxJava의 기본 개념 +#### 1. `Observable`과 `Observer` +RxJava에서 가장 중요한 개념은 **`Observable(발행자)`** 와 **`Observer(구독자)`** 야. +- **Observable**: 데이터를 발행하는 역할 +- **Observer**: 데이터를 구독해서 처리하는 역할 + +```java +import io.reactivex.rxjava3.core.Observable; + +public class RxJavaExample { + public static void main(String[] args) { + // Observable 생성 (데이터 발행자) + Observable observable = Observable.just("Hello", "RxJava"); + + // Observer(구독자) 정의 + observable.subscribe(System.out::println); + } +} +``` +출력: +``` +Hello +RxJava +``` + +--- + +#### 2. `map`을 이용한 데이터 변환 +`map` 연산자를 사용하면 데이터를 변환할 수 있어. + +```java +Observable.just(1, 2, 3) + .map(num -> num * 10) // 데이터를 10배 증가 + .subscribe(System.out::println); +``` +출력: +``` +10 +20 +30 +``` + +--- + +#### 3. `flatMap`을 이용한 비동기 작업 +`flatMap`은 비동기 작업을 수행하고 여러 개의 데이터를 반환할 때 유용해. + +```java +Observable.just("Hello") + .flatMap(str -> Observable.fromArray(str.split(""))) + .subscribe(System.out::println); +``` +출력: +``` +H +e +l +l +o +``` + +--- + +#### 4. `onError`를 활용한 에러 처리 +RxJava는 `onError`를 활용하여 에러를 잡아낼 수 있어. + +```java +Observable.just(5, 2, 0) + .map(num -> 10 / num) // 0으로 나누면 예외 발생 + .onErrorReturnItem(-1) // 예외 발생 시 기본값 반환 + .subscribe(System.out::println); +``` +출력: +``` +2 +5 +-1 +``` + +--- + +### 결론 +RxJava는 비동기 프로그래밍을 보다 직관적이고 선언적으로 작성할 수 있도록 도와주는 라이브러리야. +- `Observable`을 사용하여 데이터를 발행하고, `Observer`로 이를 구독할 수 있어. +- `map`, `flatMap`, `filter` 등의 연산자를 사용해 데이터를 변환할 수 있어. +- `onErrorReturnItem` 같은 방식으로 예외 처리를 쉽게 할 수 있어. + +비동기 처리, API 호출, 이벤트 스트림 처리 등 다양한 곳에서 활용될 수 있기 때문에, 필요에 따라 적용해보면 좋아! + + + + +--- + + + + +## RxJava의 주요 클래스 및 메서드 정리 + +RxJava에는 다양한 클래스를 통해 **비동기 데이터 흐름을 처리**할 수 있도록 도와줘. 핵심 클래스들을 정리하고, 각 클래스별 주요 메서드를 표로 정리할게. + +--- + +## 1. 주요 클래스 소개 +### (1) `Observable` +- **핵심 역할:** 데이터를 발행하는 기본적인 클래스. **N개의 데이터를 발행**할 수 있어. +- **특징:** 하나 이상의 `Observer`가 구독할 수 있으며, **onNext, onError, onComplete** 이벤트를 제공해. + +### (2) `Observer` +- **핵심 역할:** `Observable`이 발행하는 데이터를 **구독(Subscribe)** 하고 처리하는 클래스. +- **주요 메서드:** + - `onNext(T item)`: 새로운 데이터가 발행될 때 호출됨. + - `onError(Throwable e)`: 오류 발생 시 호출됨. + - `onComplete()`: 모든 데이터가 정상적으로 발행 완료되면 호출됨. + +### (3) `Single` +- **핵심 역할:** **오직 하나의 데이터** 혹은 **에러만**을 발행하는 클래스. +- **사용 예:** 네트워크 요청 결과(예: 로그인 API 응답). +- **특징:** `onSuccess(T item)`, `onError(Throwable e)` 이벤트를 제공. + +### (4) `Maybe` +- **핵심 역할:** 데이터가 **있을 수도 있고 없을 수도 있는** 경우 사용. +- **사용 예:** 로컬 캐시에서 데이터를 불러올 때. +- **특징:** `onSuccess`, `onError`, `onComplete` 이벤트 제공. + +### (5) `Completable` +- **핵심 역할:** 데이터를 발행하지 않고, **완료 여부만** 전달하는 클래스. +- **사용 예:** 데이터 저장, 파일 다운로드 완료 이벤트. +- **특징:** `onComplete()`, `onError(Throwable e)` 이벤트 제공. + +### (6) `Flowable` +- **핵심 역할:** `Observable`과 유사하지만 **백프레셔(Backpressure) 지원**이 필요한 경우 사용. +- **사용 예:** 많은 양의 데이터를 빠르게 발행할 때(예: 실시간 로그 스트림). + +--- + +## 2. 클래스별 주요 메서드 정리 +각 클래스별 주요 메서드를 표로 정리하면 다음과 같아. + +### (1) `Observable`의 주요 메서드 + +| 메서드 | 설명 | +|--------|------| +| `just(T...)` | 지정한 데이터를 순차적으로 발행 | +| `fromArray(T[])` | 배열 데이터를 순차적으로 발행 | +| `fromIterable(Iterable)` | 리스트 데이터를 순차적으로 발행 | +| `create(ObservableOnSubscribe)` | 직접 `onNext`, `onError`, `onComplete` 이벤트를 발생시키도록 정의 | +| `map(Function)` | 데이터를 변환 | +| `flatMap(Function>)` | 비동기적으로 데이터를 변환 | +| `filter(Predicate)` | 조건을 만족하는 데이터만 발행 | +| `debounce(long, TimeUnit)` | 짧은 시간 내에 연속으로 발행되는 데이터 중 마지막 데이터만 발행 | +| `merge(Observable...)` | 여러 개의 `Observable`을 합침 | +| `zip(Observable, Observable, BiFunction)` | 두 개의 `Observable`을 결합하여 새로운 데이터 발행 | +| `onErrorReturn(Function)` | 에러 발생 시 기본값을 반환 | +| `subscribe(Observer)` | 데이터를 구독 | + +--- + +### (2) `Single`의 주요 메서드 + +| 메서드 | 설명 | +|--------|------| +| `just(T)` | 단일 데이터를 발행 | +| `fromCallable(Callable)` | 데이터 생성 작업을 비동기적으로 수행 | +| `map(Function)` | 데이터를 변환 | +| `flatMap(Function>)` | 비동기적으로 데이터를 변환 | +| `subscribe(SingleObserver)` | 데이터를 구독 | + +--- + +### (3) `Maybe`의 주요 메서드 + +| 메서드 | 설명 | +|--------|------| +| `just(T)` | 단일 데이터를 발행 | +| `empty()` | 아무 데이터도 발행하지 않음 | +| `fromCallable(Callable)` | 데이터 생성 작업을 비동기적으로 수행 | +| `map(Function)` | 데이터를 변환 | +| `flatMap(Function>)` | 비동기적으로 데이터를 변환 | +| `subscribe(MaybeObserver)` | 데이터를 구독 | + +--- + +### (4) `Completable`의 주요 메서드 + +| 메서드 | 설명 | +|--------|------| +| `complete()` | 작업을 성공적으로 완료 | +| `fromRunnable(Runnable)` | 실행 후 완료 이벤트를 발행 | +| `fromCallable(Callable)` | 실행 후 완료 이벤트를 발행 | +| `subscribe(CompletableObserver)` | 완료 이벤트를 구독 | + +--- + +### (5) `Flowable`의 주요 메서드 + +| 메서드 | 설명 | +|--------|------| +| `just(T...)` | 지정한 데이터를 순차적으로 발행 | +| `fromArray(T[])` | 배열 데이터를 순차적으로 발행 | +| `fromIterable(Iterable)` | 리스트 데이터를 순차적으로 발행 | +| `create(FlowableOnSubscribe, BackpressureStrategy)` | 직접 데이터를 발행하며 백프레셔 전략 설정 | +| `map(Function)` | 데이터를 변환 | +| `flatMap(Function>)` | 비동기적으로 데이터를 변환 | +| `filter(Predicate)` | 조건을 만족하는 데이터만 발행 | +| `subscribe(Subscriber)` | 데이터를 구독 | + +--- + +## 3. 마무리 +RxJava에는 다양한 클래스가 있고, 각각의 역할이 있어: +- `Observable` → 일반적인 비동기 데이터 스트림 처리 +- `Single` → 하나의 데이터만 반환 (예: 네트워크 응답) +- `Maybe` → 데이터가 있을 수도, 없을 수도 있음 +- `Completable` → 데이터 없이 완료 이벤트만 전달 +- `Flowable` → 백프레셔가 필요한 경우 사용 + +각 클래스에는 `map`, `flatMap`, `filter` 같은 연산자가 존재해서 **데이터를 조작하고 가공**하는 게 가능해. +특히 `Observable`은 `just`, `fromArray`, `merge` 등을 이용해 다양한 방식으로 데이터를 발행할 수 있어. + +필요한 기능에 맞게 적절한 클래스를 선택해서 사용하면 RxJava를 효과적으로 활용할 수 있을 거야! \ No newline at end of file diff --git a/docs/database/database.md b/docs/database/database.md new file mode 100644 index 0000000..9cb740e --- /dev/null +++ b/docs/database/database.md @@ -0,0 +1,164 @@ +Java에서 사용되는 데이터베이스 중 **Java DB**(Apache Derby), **H2 Database**, 그리고 **SQLite**는 각각 임베디드 데이터베이스로 널리 사용되며, 각기 다른 특징과 장단점을 가지고 있습니다. 아래에서 이 세 가지를 주요 항목별로 비교하여 설명하겠습니다. + +--- + +### **1. 개요** +| **항목** | **Java DB (Apache Derby)** | **H2 Database** | **SQLite** | +|------------------|-----------------------------------------------|---------------------------------------------|--------------------------------------------| +| **개발 언어** | Java | Java | C | +| **라이선스** | Apache License 2.0 | MPL 2.0 / EPL 1.0 | Public Domain | +| **주요 용도** | 임베디드 및 경량 서버 애플리케이션 | 임베디드, 테스트, 경량 서버 애플리케이션 | 임베디드 애플리케이션 (모바일 포함) | +| **최초 출시** | 2004년 (IBM Cloudscape에서 파생) | 2005년 | 2000년 | + +- **Java DB**: IBM의 Cloudscape에서 파생된 Apache Derby로, 순수 Java로 작성된 관계형 데이터베이스. +- **H2**: Java로 작성된 고속, 경량 데이터베이스로, 특히 테스트 환경에서 인기. +- **SQLite**: C로 작성된 초경량 데이터베이스로, 모바일 및 임베디드 환경에서 널리 사용. + +--- + +### **2. 기능 비교** +| **항목** | **Java DB** | **H2** | **SQLite** | +|------------------|--------------------------------------|-------------------------------------|------------------------------------| +| **임베디드 모드**| 지원 | 지원 | 지원 | +| **서버 모드** | 지원 (네트워크 연결 가능) | 지원 (TCP 기반) | 미지원 (파일 기반만 가능) | +| **인메모리 지원**| 지원 | 지원 (빠른 성능) | 지원 | +| **SQL 표준 준수**| 높음 (SQL-92, SQL-99 지원) | 매우 높음 (다양한 SQL 기능 지원) | 중간 (일부 고급 기능 미지원) | +| **트랜잭션** | ACID 준수 | ACID 준수 | ACID 준수 | +| **사용자 관리** | 지원 (username/password) | 지원 | 미지원 (파일 접근 기반) | +| **최대 DB 크기** | 이론상 JVM 한계 (수 TB) | 4TB | 281TB | + +- **Java DB**: 서버 모드와 임베디드 모드 모두 지원하며, SQL 표준 준수도가 높음. +- **H2**: 서버 모드와 인메모리 모드를 지원하며, Java 함수 실행 등 고급 기능 제공. +- **SQLite**: 서버 모드는 없고, 파일 기반으로 동작하며 사용자 인증 기능이 없음. + +--- + +### **3. 성능** +- **Java DB**: 순수 Java로 작성되어 JVM에 의존적이며, 중간 정도의 성능. 대규모 데이터 처리 시 속도가 느려질 수 있음. +- **H2**: 인메모리 모드에서 매우 빠르며, Hibernate와 같은 ORM과의 통합에서 SQLite보다 우수한 성능을 보임(특히 쿼리 실행 속도). +- **SQLite**: C로 작성되어 네이티브 성능이 뛰어나지만, 복잡한 쿼리나 동시성 처리에서 약간 뒤질 수 있음. + +**참고**: Hibernate와 결합 시 H2가 SQLite보다 평균적으로 3~8배 빠르다는 벤치마크 결과가 있음(JPAB.org). + +--- + +### **4. 장단점** +#### **Java DB (Apache Derby)** +- **장점**: + - 순수 Java로 작성되어 플랫폼 독립적. + - 서버 모드와 임베디드 모드 모두 지원. + - 안정적이고 상용 소프트웨어에서도 사용됨. +- **단점**: + - SQLite나 H2에 비해 느린 성능. + - 커뮤니티 활동이 상대적으로 적음. + +#### **H2 Database** +- **장점**: + - 순수 Java로 작성, 설치 및 통합이 쉬움. + - 인메모리 모드에서 빠른 속도, 테스트에 이상적. + - 사용자 정의 Java 함수 지원. + - 서버 모드와 네트워크 접근 가능. +- **단점**: + - 비정상 종료 시 MVStore 손상 가능성. + - SQLite에 비해 커뮤니티와 사용 사례가 적음. + +#### **SQLite** +- **장점**: + - 초경량(라이브러리 크기 약 700KB). + - C로 작성되어 네이티브 성능 우수. + - 모바일(Android, iOS) 및 임베디드 환경에서 검증됨. + - 매우 큰 데이터베이스 크기 지원(281TB). +- **단점**: + - 서버 모드 미지원, 네트워크 접근 불가. + - 사용자 인증/권한 관리 없음. + - 복잡한 SQL 기능(예: RIGHT OUTER JOIN) 미지원. + +--- + +### **5. 사용 예제 (Java에서 연결)** +#### **Java DB** +```java +import java.sql.*; + +public class JavaDBExample { + public static void main(String[] args) throws Exception { + String url = "jdbc:derby:memory:myDB;create=true"; + Connection conn = DriverManager.getConnection(url); + Statement stmt = conn.createStatement(); + stmt.execute("CREATE TABLE test (id INT, name VARCHAR(50))"); + stmt.execute("INSERT INTO test VALUES (1, 'JavaDB')"); + ResultSet rs = stmt.executeQuery("SELECT * FROM test"); + while (rs.next()) { + System.out.println(rs.getInt("id") + ": " + rs.getString("name")); + } + conn.close(); + } +} +``` + +#### **H2** +```java +import java.sql.*; + +public class H2Example { + public static void main(String[] args) throws Exception { + String url = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"; + Connection conn = DriverManager.getConnection(url, "sa", ""); + Statement stmt = conn.createStatement(); + stmt.execute("CREATE TABLE test (id INT, name VARCHAR(50))"); + stmt.execute("INSERT INTO test VALUES (1, 'H2')"); + ResultSet rs = stmt.executeQuery("SELECT * FROM test"); + while (rs.next()) { + System.out.println(rs.getInt("id") + ": " + rs.getString("name")); + } + conn.close(); + } +} +``` + +#### **SQLite** +```java +import java.sql.*; + +public class SQLiteExample { + public static void main(String[] args) throws Exception { + String url = "jdbc:sqlite::memory:"; // 또는 파일 경로 + Connection conn = DriverManager.getConnection(url); + Statement stmt = conn.createStatement(); + stmt.execute("CREATE TABLE test (id INTEGER, name TEXT)"); + stmt.execute("INSERT INTO test VALUES (1, 'SQLite')"); + ResultSet rs = stmt.executeQuery("SELECT * FROM test"); + while (rs.next()) { + System.out.println(rs.getInt("id") + ": " + rs.getString("name")); + } + conn.close(); + } +} +``` + +**의존성 (Maven)**: +- Java DB: 기본 JDK에 포함 (별도 의존성 불필요). +- H2: `com.h2databaseh2` +- SQLite: `org.xerialsqlite-jdbc` + +--- + +### **6. 언제 무엇을 사용할까?** +- **Java DB**: + - 순수 Java 환경을 선호하며, 서버 모드와 임베디드 모드를 모두 필요로 할 때. + - 안정성과 표준 준수가 중요한 경우. +- **H2**: + - 테스트 환경(예: 단위 테스트) 또는 빠른 프로토타이핑이 필요할 때. + - Java 기반 고급 기능(사용자 정의 함수 등)이 필요할 때. +- **SQLite**: + - 모바일 또는 초경량 임베디드 애플리케이션에 적합. + - 네트워크 연결이 필요 없고, 단순한 파일 기반 저장소가 필요한 경우. + +--- + +### **결론** +- **성능과 테스트**: H2가 가장 빠르고 유연하며, Java 생태계와의 통합이 뛰어남. +- **경량성과 범용성**: SQLite는 모바일 및 임베디드 환경에서 입증된 선택. +- **안정성과 표준**: Java DB는 안정적이고 표준 준수도가 높아 신뢰성 있는 선택. + +프로젝트 요구사항(성능, 크기, 네트워크 지원 여부 등)에 따라 선택하면 됩니다. 추가 질문이 있다면 말씀해주세요! \ No newline at end of file diff --git a/docs/security/bouncy castle.md b/docs/security/bouncy castle.md new file mode 100644 index 0000000..536304e --- /dev/null +++ b/docs/security/bouncy castle.md @@ -0,0 +1,263 @@ +자바의 **Java Security API**(JCA 및 JCE 포함)는 암호화, 인증, 키 관리 등 보안 기능을 제공하는 다양한 클래스를 포함하고 있습니다. 여기서는 자바 시큐리티에서 자주 사용되는 주요 클래스와 그 역할에 대해 설명하고, 각 클래스의 주요 메서드를 표로 정리하겠습니다. + +--- + +### **주요 클래스와 역할** +1. **`java.security.MessageDigest`** + - **역할**: 해시 함수(MD5, SHA-1, SHA-256 등)를 사용하여 데이터의 메시지 다이제스트(해시 값)를 생성. 데이터 무결성 확인에 사용. + - **특징**: 단방향 함수로, 입력 데이터를 고정된 길이의 해시로 변환. + +2. **`javax.crypto.Cipher`** + - **역할**: 대칭키(AES) 및 비대칭키(RSA) 암호화/복호화 작업을 수행. + - **특징**: 운용 모드(예: CBC, GCM)와 패딩(예: PKCS5Padding)을 지정 가능. + +3. **`java.security.KeyPairGenerator`** + - **역할**: 비대칭키 알고리즘(RSA, DSA, EC 등)의 공개키와 개인키 쌍을 생성. + - **특징**: 키 크기(예: 2048비트)를 지정하여 생성. + +4. **`javax.crypto.KeyGenerator`** + - **역할**: 대칭키 알고리즘(AES, DES 등)의 키를 생성. + - **특징**: 고정된 길이의 무작위 키 생성. + +5. **`javax.crypto.SecretKeyFactory`** + - **역할**: 패스워드 기반 키 생성(PBKDF2) 또는 키 변환 작업을 수행. + - **특징**: `SecretKey` 객체를 생성하거나 키 사양(KeySpec)을 변환. + +6. **`java.security.SecureRandom`** + - **역할**: 암호화에 적합한 고품질의 난수 생성. + - **특징**: 일반 `Random`보다 안전성이 높음. + +7. **`java.security.KeyStore`** + - **역할**: 키와 인증서를 저장하고 관리하는 저장소. + - **특징**: JKS, PKCS12 등 다양한 형식 지원. + +--- + +### **각 클래스의 주요 메서드** +#### **1. `MessageDigest`** +| **메서드** | **설명** | +|---------------------------|--------------------------------------------------------------------------| +| `static getInstance(String algorithm)` | 지정된 해시 알고리즘(MD5, SHA-256 등)의 인스턴스를 생성. | +| `update(byte[] input)` | 해시 계산에 사용할 입력 데이터를 추가. | +| `digest()` | 입력 데이터를 해시로 변환하여 바이트 배열로 반환. | +| `reset()` | 인스턴스를 초기 상태로 재설정. | + +#### **2. `Cipher`** +| **메서드** | **설명** | +|---------------------------|--------------------------------------------------------------------------| +| `static getInstance(String transformation)` | 암호화 알고리즘, 모드, 패딩(예: "AES/GCM/NoPadding")을 지정하여 인스턴스 생성. | +| `init(int opmode, Key key, AlgorithmParameterSpec params)` | 암호화(ENCRYPT_MODE) 또는 복호화(DECRYPT_MODE) 모드로 초기화. 매개변수(IV 등) 지정 가능. | +| `update(byte[] input)` | 암호화/복호화할 데이터를 추가(스트리밍 처리 시 사용). | +| `doFinal(byte[] input)` | 암호화/복호화를 완료하고 결과를 반환. | +| `updateAAD(byte[] aad)` | GCM 모드 등에서 인증용 추가 데이터(AAD)를 추가. | + +#### **3. `KeyPairGenerator`** +| **메서드** | **설명** | +|---------------------------|--------------------------------------------------------------------------| +| `static getInstance(String algorithm)` | 키 쌍 생성기 인스턴스를 반환(예: "RSA", "EC"). | +| `initialize(int keysize)` | 키 크기(예: 2048비트)를 지정하여 초기화. | +| `generateKeyPair()` | 공개키와 개인키 쌍(`KeyPair`)을 생성하여 반환. | + +#### **4. `KeyGenerator`** +| **메서드** | **설명** | +|---------------------------|--------------------------------------------------------------------------| +| `static getInstance(String algorithm)` | 대칭키 생성기 인스턴스를 반환(예: "AES"). | +| `init(int keysize)` | 키 길이(예: 256비트)를 지정하여 초기화. | +| `generateKey()` | 지정된 길이의 대칭키(`SecretKey`)를 생성하여 반환. | + +#### **5. `SecretKeyFactory`** +| **메서드** | **설명** | +|---------------------------|--------------------------------------------------------------------------| +| `static getInstance(String algorithm)` | 키 팩토리 인스턴스를 반환(예: "PBKDF2WithHmacSHA256"). | +| `generateSecret(KeySpec spec)` | 키 사양(예: `PBEKeySpec`)을 기반으로 `SecretKey`를 생성. | +| `getKeySpec(SecretKey key, Class keySpec)` | 주어진 키를 특정 사양(예: `PBEKeySpec`)으로 변환. | + +#### **6. `SecureRandom`** +| **메서드** | **설명** | +|---------------------------|--------------------------------------------------------------------------| +| `SecureRandom()` | 기본 알고리즘으로 안전한 난수 생성기 인스턴스를 생성. | +| `nextBytes(byte[] bytes)` | 지정된 바이트 배열을 무작위 값으로 채움(예: IV, 솔트 생성에 사용). | +| `setSeed(byte[] seed)` | 난수 생성기의 시드 값을 설정(보안상 권장되지 않음). | + +#### **7. `KeyStore`** +| **메서드** | **설명** | +|---------------------------|--------------------------------------------------------------------------| +| `static getInstance(String type)` | 키 저장소 인스턴스를 반환(예: "JKS", "PKCS12"). | +| `load(InputStream stream, char[] password)` | 지정된 스트림에서 키 저장소를 로드하며, 비밀번호로 보호. | +| `getKey(String alias, char[] password)` | 지정된 별칭에 해당하는 키를 반환. | +| `setKeyEntry(String alias, Key key, char[] password, Certificate[] chain)` | 키와 인증서를 저장소에 추가. | +| `store(OutputStream stream, char[] password)` | 키 저장소를 지정된 스트림에 저장. | + +--- + +### **클래스 간 연계 예제** +아래는 `MessageDigest`, `Cipher`, `KeyGenerator`, `SecureRandom`을 함께 사용하는 AES-GCM 암호화 예제입니다. + +```java +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import java.security.MessageDigest; +import java.security.SecureRandom; +import java.util.Base64; + +public class SecurityExample { + public static void main(String[] args) throws Exception { + // 1. 키 생성 (KeyGenerator) + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); + SecretKey key = keyGen.generateKey(); + + // 2. IV 생성 (SecureRandom) + SecureRandom random = new SecureRandom(); + byte[] iv = new byte[12]; + random.nextBytes(iv); + + // 3. 암호화 (Cipher) + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + GCMParameterSpec spec = new GCMParameterSpec(128, iv); + cipher.init(Cipher.ENCRYPT_MODE, key, spec); + byte[] plaintext = "Hello, Java Security!".getBytes(); + byte[] ciphertext = cipher.doFinal(plaintext); + + // 4. 해시 생성 (MessageDigest) + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(plaintext); + + // 출력 + System.out.println("Ciphertext: " + Base64.getEncoder().encodeToString(ciphertext)); + System.out.println("Hash: " + Base64.getEncoder().encodeToString(hash)); + } +} +``` + +--- + +### **추가 참고** +- **제공자(Provider)**: `Security.getProviders()`로 사용 가능한 제공자를 확인할 수 있으며, 기본 제공자는 SunJCE입니다. Bouncy Castle 같은 외부 제공자를 추가할 수도 있습니다. +- **확장성**: JCA는 플러그인 구조로 설계되어 새로운 알고리즘을 쉽게 추가 가능. + +각 클래스에 대해 더 깊은 설명이나 특정 메서드의 사용 예제가 필요하면 말씀해주세요! + + + + + + + + + +--- + + +사용자가 "Bouncy Castle"에 대해 물었을 때, 문맥상 자바 보안과 암호화에 관련된 질문을 이어오셨으므로, 여기서는 **Bouncy Castle 암호화 라이브러리**(The Bouncy Castle Cryptography Library)에 대해 설명하겠습니다. 만약 실제 "바운시 캐슬"(어린이 놀이기구)을 의미한 것이라면, 말씀해 주시면 그에 맞춰 수정하겠습니다! + +--- + +### **Bouncy Castle 암호화 라이브러리란?** +Bouncy Castle은 자바(Java)와 C#(.NET)용으로 개발된 오픈소스 암호화 라이브러리로, 다양한 암호화 알고리즘과 보안 프로토콜을 구현할 수 있는 강력한 도구입니다. 이 라이브러리는 **Legion of the Bouncy Castle Inc.**라는 호주 기반의 등록된 자선 단체에서 개발 및 유지보수하며, 2000년 5월에 처음 출시되었습니다. + +Bouncy Castle은 자바의 기본 JCE(Java Cryptography Extension)와 JCA(Java Cryptography Architecture)를 보완하거나 대체할 수 있으며, 경량 API와 JCE 제공자(Provider)라는 두 가지 주요 구성 요소로 설계되었습니다. 이를 통해 메모리 제약이 있는 환경(예: Java ME)부터 일반 JVM 환경까지 폭넓게 사용할 수 있습니다. + +--- + +### **주요 특징** +1. **광범위한 알고리즘 지원**: + - 대칭키 암호화: AES, DES, Blowfish 등. + - 비대칭키 암호화: RSA, ECDSA, Diffie-Hellman 등. + - 해시 함수: SHA-1, SHA-256, SHA-3 등. + - 인증 암호화: AES-GCM, CCM 등. + - 기타: OpenPGP, CMS, TLS/DTLS, X.509 인증서 생성 등. + +2. **경량 API와 JCE 제공자**: + - **경량 API**: 메모리 제약 환경에서 직접 사용할 수 있는 저수준 API. + - **JCE 제공자**: 자바의 표준 암호화 프레임워크와 통합 가능. + +3. **FIPS 인증**: + - Bouncy Castle은 FIPS 140-2 인증 버전을 제공하며, 높은 보안 요구 사항이 있는 환경에서도 사용 가능. + +4. **오픈소스 및 커뮤니티 지원**: + - MIT 기반 라이선스로 배포되며, 누구나 무료로 사용 가능. + - GitHub를 통해 소스 코드가 공개되고, 커뮤니티 피드백을 반영. + +5. **플랫폼 유연성**: + - Java뿐만 아니라 C#도 지원하며, Android 환경에서는 **Spongy Castle**이라는 변형 버전으로 사용됨. + +--- + +### **Bouncy Castle의 기원** +Bouncy Castle은 두 명의 자바 개발자가 서버 측 애플리케이션에서 반복적으로 암호화 라이브러리를 작성해야 하는 상황에 지쳤을 때 시작되었습니다. 이들은 Java ME(J2ME)와 같은 제한된 환경에서도 동작할 수 있는 유연한 라이브러리를 목표로 설계했으며, 이는 현재의 아키텍처로 이어졌습니다. 초기 버전은 약 27,000줄의 코드로 시작했지만, 현재(최신 버전 기준) 약 39만 줄 이상으로 확장되었습니다. + +--- + +### **주요 사용 사례** +- **암호화 및 복호화**: AES, RSA 등을 사용한 데이터 보호. +- **디지털 서명**: ECDSA, RSA 기반 서명 생성 및 검증. +- **키 관리**: 키 쌍 생성, 패스워드 기반 키 생성(PBKDF2 등). +- **프로토콜 구현**: TLS, OpenPGP, S/MIME 등 보안 프로토콜 지원. +- **인증서 관리**: X.509 인증서 생성 및 처리. + +--- + +### **자바에서 Bouncy Castle 사용 예제** +Bouncy Castle을 자바 프로젝트에 추가하려면 Maven 의존성을 추가하고, JCE 제공자로 등록한 뒤 사용할 수 있습니다. + +#### **Maven 의존성** +```xml + + org.bouncycastle + bcprov-jdk18on + 1.78 + +``` + +#### **제공자 등록 및 AES 암호화 예제** +```java +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.security.Security; + +public class BouncyCastleExample { + public static void main(String[] args) throws Exception { + // Bouncy Castle 제공자 등록 + Security.addProvider(new BouncyCastleProvider()); + + // 키와 데이터 준비 + byte[] keyBytes = "ThisIsASecretKey".getBytes(); + SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); + String input = "Hello, Bouncy Castle!"; + + // 암호화 + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); + cipher.init(Cipher.ENCRYPT_MODE, key); + byte[] encrypted = cipher.doFinal(input.getBytes()); + + System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(encrypted)); + } +} +``` + +--- + +### **장점** +- **풍부한 기능**: JCE보다 더 많은 알고리즘과 프로토콜 지원. +- **유연성**: 경량 API로 임베디드 시스템에서도 사용 가능. +- **제한 없음**: 미국 암호화 수출 제한(JCE의 과거 제약)을 피할 수 있음. +- **커뮤니티와 지속적인 업데이트**: 활발한 개발과 최신 보안 표준 반영. + +### **단점** +- **복잡성**: JCE보다 학습 곡선이 다소 높을 수 있음. +- **성능**: 일부 경우 JCE의 네이티브 최적화(AES-NI 등)에 비해 느릴 수 있음. +- **의존성 관리**: Android 등 특정 환경에서는 별도 변형(Spongy Castle) 필요. + +--- + +### **JCE와의 비교** +- **JCE**: 자바 표준 라이브러리로, 간단한 사용과 기본 기능에 적합. 하지만 과거 키 길이 제한(현재는 완화됨)과 지원 알고리즘의 한계가 있음. +- **Bouncy Castle**: 더 많은 알고리즘과 프로토콜을 제공하며, FIPS 인증과 같은 고급 요구 사항을 충족. 그러나 추가 설정이 필요. + +--- + +Bouncy Castle은 암호화가 필요한 개발자에게 강력한 도구로 자리 잡고 있으며, 특히 보안 요구 사항이 높은 프로젝트에서 유용합니다. 추가로 궁금한 점이나 특정 기능에 대한 깊은 설명이 필요하면 말씀해 주세요! \ No newline at end of file diff --git a/docs/security/cipher.md b/docs/security/cipher.md new file mode 100644 index 0000000..dba1923 --- /dev/null +++ b/docs/security/cipher.md @@ -0,0 +1,240 @@ +자바에서 AES와 RSA 암호화 알고리즘을 사용할 때 지원되는 운용 모드, 패딩, 키 길이, 그리고 필요한 매개변수를 표로 정리하겠습니다. JCA/JCE에서 제공하는 기본 설정을 기준으로 하며, JDK 버전(예: JDK 8, 11, 17 등) 및 사용 중인 제공자(Provider, 예: SunJCE, Bouncy Castle)에 따라 일부 차이가 있을 수 있습니다. + +--- + +### **AES (Advanced Encryption Standard)** + +| **항목** | **설명** | +|--------------------|--------------------------------------------------------------------------------------------| +| **운용 모드** | - **ECB (Electronic Codebook)**: 블록 단위로 독립적 암호화 (보안성 낮음, 권장되지 않음).
- **CBC (Cipher Block Chaining)**: 이전 블록과 XOR 연산, IV 필요.
- **CTR (Counter)**: 스트림 암호처럼 동작, IV 또는 논스 필요.
- **GCM (Galois/Counter Mode)**: 인증 암호화, IV 및 추가 인증 데이터(AAD) 지원.
- **CFB (Cipher Feedback)**: 스트림 암호화, IV 필요.
- **OFB (Output Feedback)**: 스트림 암호화, IV 필요. | +| **패딩** | - **PKCS5Padding** (또는 PKCS7Padding): 블록 크기에 맞게 패딩 추가 (기본값).
- **NoPadding**: 패딩 없음, 데이터 길이가 블록 크기의 배수여야 함.
- **ISO10126Padding**: 랜덤 패딩 (일부 제공자에서 지원). | +| **키 길이** | - 128비트 (기본값).
- 192비트.
- 256비트 (JCE Unlimited Strength Policy 필요 시 설치). | +| **필요한 매개변수** | - **IV (Initialization Vector)**: CBC, CTR, GCM, CFB, OFB 모드에서 필요 (일반적으로 16바이트).
- **Nonce**: CTR, GCM에서 사용 가능.
- **AAD (Additional Authenticated Data)**: GCM 모드에서 인증용 추가 데이터 (선택적).
- **Tag 길이**: GCM 모드에서 인증 태그 길이 (기본 128비트, 96, 104, 112, 120 등 조정 가능). | +| **Cipher 형식** | `"AES/[운용모드]/[패딩]"` 예: `"AES/CBC/PKCS5Padding"`, `"AES/GCM/NoPadding"`. | + +#### **참고** +- AES는 블록 크기가 128비트(16바이트)로 고정되어 있습니다. +- ECB는 보안 취약성이 있어 권장되지 않으며, GCM은 인증과 암호화를 동시에 제공해 현대 애플리케이션에서 선호됩니다. +- 예제: `Cipher.getInstance("AES/GCM/NoPadding")`. + +--- + +### **RSA (Rivest-Shamir-Adleman)** + +| **항목** | **설명** | +|--------------------|--------------------------------------------------------------------------------------------| +| **운용 모드** | - RSA 자체는 블록 암호화로 동작하며, 별도의 운용 모드 없음.
- 단일 블록 암호화/복호화 또는 서명/검증 용도로 사용.
- 하이브리드 암호화 시 AES와 결합 가능 (RSA로 AES 키 암호화). | +| **패딩** | - **NoPadding**: 패딩 없음 (데이터 길이가 키 크기보다 작아야 함, 권장되지 않음).
- **PKCS1Padding**: PKCS#1 v1.5 패딩 (암호화/서명에 사용, 기본값).
- **OAEPWith<해시>AndMGF1Padding**: OAEP 패딩 (예: `"OAEPWithSHA-256AndMGF1Padding"`), 더 안전.
- **OAEPPadding**: 기본 OAEP (구형, 권장되지 않음). | +| **키 길이** | - 512비트 (취약, 사용 금지).
- 1024비트 (현재 취약, 권장되지 않음).
- 2048비트 (표준).
- 4096비트 (높은 보안 요구 시). | +| **필요한 매개변수** | - **PublicKey/PrivateKey**: 공개키/개인키 쌍.
- **OAEP 매개변수**: OAEP 사용 시 `OAEPParameterSpec`로 해시 알고리즘(SHA-256 등)과 MGF1(Mask Generation Function) 지정.
- **서명 시 해시**: 예: `"SHA256withRSA"` (RSA와 결합된 해시 알고리즘). | +| **Cipher 형식** | `"RSA/[운용모드]/[패딩]"` 예: `"RSA/None/PKCS1Padding"`, `"RSA/None/OAEPWithSHA-256AndMGF1Padding"`. | + +#### **참고** +- RSA는 비대칭 알고리즘이므로 대량 데이터 암호화에는 적합하지 않습니다. 주로 키 교환이나 디지털 서명에 사용됩니다. +- OAEP 패딩은 PKCS#1 v1.5보다 안전하며, SHA-256 이상의 해시와 함께 사용하는 것이 권장됩니다. +- 최대 암호화 가능한 데이터 크기는 키 길이와 패딩에 따라 달라집니다 (예: 2048비트 키 + PKCS1Padding = 최대 245바이트). + +--- + +### **AES와 RSA 비교 요약** + +| **특징** | **AES** | **RSA** | +|--------------------|----------------------------------|----------------------------------| +| **유형** | 대칭키 암호화 | 비대칭키 암호화 | +| **주요 용도** | 데이터 암호화 | 키 교환, 디지털 서명 | +| **속도** | 빠름 | 느림 | +| **키 길이** | 128, 192, 256비트 | 1024, 2048, 4096비트 | +| **운용 모드** | ECB, CBC, GCM 등 다양 | 없음 (단일 블록 암호화) | +| **패딩** | PKCS5Padding, NoPadding 등 | PKCS1Padding, OAEP 등 | + +--- + +### **예제 코드** +#### **AES 암호화** +```java +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; + +public class AesExample { + public static void main(String[] args) throws Exception { + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); + SecretKey key = keyGen.generateKey(); + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + byte[] iv = new byte[16]; // IV는 랜덤으로 생성해야 함 + IvParameterSpec ivSpec = new IvParameterSpec(iv); + cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); + byte[] encrypted = cipher.doFinal("Hello, AES!".getBytes()); + System.out.println(new String(encrypted)); + } +} +``` + +#### **RSA 암호화** +```java +import javax.crypto.Cipher; +import java.security.KeyPair; +import java.security.KeyPairGenerator; + +public class RsaExample { + public static void main(String[] args) throws Exception { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(2048); + KeyPair keyPair = keyGen.generateKeyPair(); + + Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding"); + cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic()); + byte[] encrypted = cipher.doFinal("Hello, RSA!".getBytes()); + System.out.println(new String(encrypted)); + } +} +``` + +--- + +추가로 궁금한 점이나 특정 항목에 대한 자세한 설명이 필요하면 말씀해주세요! + + + + + + + +--- + + + + +AES-GCM (Galois/Counter Mode)은 AES 암호화 알고리즘의 운용 모드 중 하나로, 대칭키 암호화와 인증을 동시에 제공하는 **인증 암호화 (Authenticated Encryption, AE)** 방식입니다. 이 모드는 현대 보안 애플리케이션에서 널리 사용되며, 특히 TLS/SSL, IPsec, 디스크 암호화 등에서 표준으로 채택되고 있습니다. 아래에서 AES-GCM의 상세한 특징, 동작 방식, 매개변수, 장단점 등을 정리하겠습니다. + +--- + +### **AES-GCM의 주요 특징** +1. **대칭키 암호화**: + - AES 블록 암호를 기반으로 하며, 블록 크기는 128비트(16바이트)로 고정됩니다. + - 키 길이는 128비트, 192비트, 256비트 중 선택 가능. + +2. **인증 제공**: + - 암호화된 데이터의 무결성과 출처 인증을 보장하기 위해 **인증 태그 (Authentication Tag)**를 생성합니다. + - 별도의 MAC(Message Authentication Code) 계산이 필요 없음. + +3. **스트림 암호처럼 동작**: + - CTR(Counter) 모드를 기반으로 하여, 입력 데이터 길이에 관계없이 암호화 가능 (블록 크기의 배수일 필요 없음). + +4. **Galois 필드 연산**: + - 인증 태그 생성에 GF(2^128) (Galois Field) 연산을 사용하며, 이를 통해 효율적이고 안전한 인증을 구현. + +--- + +### **AES-GCM의 동작 방식** +1. **입력**: + - 평문 (Plaintext): 암호화할 데이터. + - 키 (Key): AES 키 (128, 192, 256비트). + - IV (Initialization Vector) 또는 Nonce: 초기화 벡터 (일반적으로 12바이트 권장). + - AAD (Additional Authenticated Data): 인증만 필요한 추가 데이터 (선택적, 암호화되지 않음). + +2. **과정**: + - **CTR 모드 암호화**: IV와 카운터를 결합하여 AES로 키스트림(Key Stream)을 생성하고, 평문과 XOR 연산을 통해 암호문을 생성. + - **인증 태그 생성**: 암호문, AAD, IV 등을 Galois 필드 연산(GMAC)을 통해 인증 태그로 변환. + - 출력: 암호문(Ciphertext) + 인증 태그(Tag). + +3. **출력**: + - 암호문과 인증 태그를 함께 반환하며, 복호화 시 태그를 검증하여 데이터 무결성을 확인. + +--- + +### **주요 매개변수** +| **매개변수** | **설명** | **권장값/주의사항** | +|----------------------|--------------------------------------------------------------------------------------------|---------------------------------------------| +| **키 길이** | AES 암호화에 사용되는 키 크기. | 128, 192, 256비트 (256비트 권장). | +| **IV (Nonce)** | 초기화 벡터로, 암호화마다 고유해야 함. | 12바이트(96비트) 권장, 재사용 절대 금지. | +| **AAD** | 인증에만 사용되는 추가 데이터 (암호화되지 않음). | 선택적, 예: 프로토콜 헤더 등. | +| **태그 길이** | 인증 태그의 길이로, 무결성 검증에 사용. | 128비트(기본), 96, 104, 112, 120비트 가능. | +| **Cipher 형식** | 자바에서 GCM 모드를 지정하는 형식. | `"AES/GCM/NoPadding"` (패딩 불필요). | + +#### **IV/Nonce에 대한 중요 참고** +- GCM은 IV(Nonce) 재사용 시 보안이 심각하게 손상됩니다. 동일한 키와 IV 조합을 두 번 사용하면 인증 태그가 의미를 잃고, 암호문이 노출될 수 있습니다. +- 12바이트(96비트) Nonce가 표준으로 권장되며, 더 긴 IV를 사용할 경우 내부적으로 해시 처리됩니다. + +--- + +### **자바에서 AES-GCM 사용 예제** +```java +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; + +public class AesGcmExample { + public static void main(String[] args) throws Exception { + // 1. AES 키 생성 + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); // 256비트 키 + SecretKey key = keyGen.generateKey(); + + // 2. IV (Nonce) 생성 + byte[] iv = new byte[12]; // 12바이트 Nonce + SecureRandom random = new SecureRandom(); + random.nextBytes(iv); + + // 3. 암호화 설정 + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + GCMParameterSpec spec = new GCMParameterSpec(128, iv); // 128비트 태그 길이 + cipher.init(Cipher.ENCRYPT_MODE, key, spec); + + // 4. AAD 추가 (선택적) + byte[] aad = "AuthData".getBytes(StandardCharsets.UTF_8); + cipher.updateAAD(aad); + + // 5. 암호화 + byte[] plaintext = "Hello, AES-GCM!".getBytes(StandardCharsets.UTF_8); + byte[] ciphertext = cipher.doFinal(plaintext); + + // 결과 출력 + System.out.println("IV: " + bytesToHex(iv)); + System.out.println("Ciphertext (with tag): " + bytesToHex(ciphertext)); + + // 6. 복호화 + cipher.init(Cipher.DECRYPT_MODE, key, spec); + cipher.updateAAD(aad); // AAD 동일해야 함 + byte[] decrypted = cipher.doFinal(ciphertext); + System.out.println("Decrypted: " + new String(decrypted, StandardCharsets.UTF_8)); + } + + private static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } +} +``` + +--- + +### **장점** +1. **효율성**: 암호화와 인증을 단일 패스로 처리하여 속도가 빠름. +2. **보안성**: 인증 태그로 무결성과 출처 인증을 보장. +3. **유연성**: AAD를 통해 추가 데이터를 인증 가능. + +### **단점 및 주의사항** +1. **Nonce 재사용 금지**: 동일한 키와 Nonce를 재사용하면 보안이 완전히 무너질 수 있음 (키스트림 재사용 문제). +2. **태그 길이 조정 시 주의**: 짧은 태그(예: 64비트)는 충돌 위험이 증가할 수 있음. +3. **복잡성**: IV 관리와 AAD 처리가 추가적으로 필요. + +--- + +### **응용 사례** +- **TLS 1.2/1.3**: AES-GCM은 TLS에서 널리 사용되는 cipher suite입니다 (예: `TLS_AES_256_GCM_SHA384`). +- **디스크 암호화**: 인증과 함께 데이터 보호. +- **메시징 시스템**: 메시지 무결성과 기밀성 보장. + +--- + +AES-GCM은 현대 암호화에서 매우 강력하고 효율적인 선택이지만, IV 관리와 키 회전에 신경 써야 합니다. 추가로 궁금한 점이나 특정 부분에 대한 더 깊은 설명이 필요하면 말씀해주세요! \ No newline at end of file diff --git a/docs/security/jce.md b/docs/security/jce.md new file mode 100644 index 0000000..062a459 --- /dev/null +++ b/docs/security/jce.md @@ -0,0 +1,508 @@ +Java의 `java.security` 패키지는 **보안 관련 기능**을 제공하는 핵심 패키지야. 크게 다음과 같은 기능들로 분류할 수 있어: + +--- + +## 1. 암호화(Encryption) 및 복호화(Decryption) +암호화는 데이터를 보호하는 데 중요한 역할을 해. Java에서는 다양한 알고리즘을 지원하는 **JCA(Java Cryptography Architecture)** 및 **JCE(Java Cryptography Extension)**를 통해 암호화 기능을 제공해. + +- **주요 클래스 및 인터페이스** + | 클래스/인터페이스 | 설명 | + |------------------|------| + | `Cipher` | 암호화 및 복호화 작업을 수행하는 클래스 | + | `KeyGenerator` | 대칭 키를 생성하는 클래스 (AES, DES 등) | + | `SecretKey` | 대칭 키를 나타내는 인터페이스 | + | `KeyPairGenerator` | 공개 키 및 개인 키 쌍을 생성하는 클래스 | + | `PublicKey`, `PrivateKey` | 비대칭 키를 나타내는 인터페이스 | + +- **예제: AES 암호화 및 복호화** + ```java + import javax.crypto.Cipher; + import javax.crypto.KeyGenerator; + import javax.crypto.SecretKey; + import java.util.Base64; + + public class AESExample { + public static void main(String[] args) throws Exception { + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(128); // 128비트 키 생성 + SecretKey secretKey = keyGen.generateKey(); + + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + + String plaintext = "Hello, Security!"; + byte[] encrypted = cipher.doFinal(plaintext.getBytes()); + + System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(encrypted)); + + // 복호화 + cipher.init(Cipher.DECRYPT_MODE, secretKey); + byte[] decrypted = cipher.doFinal(encrypted); + System.out.println("Decrypted: " + new String(decrypted)); + } + } + ``` + +--- + +## 2. 키(Key) 및 키스토어(KeyStore) 관리 +보안 키를 안전하게 저장하고 관리할 수 있도록 **키스토어** 기능을 제공해. + +- **주요 클래스 및 인터페이스** + | 클래스/인터페이스 | 설명 | + |------------------|------| + | `KeyStore` | 키 및 인증서를 저장하는 저장소 | + | `KeyFactory` | 키 객체를 생성하는 클래스 | + | `KeyPair` | 공개 키와 개인 키를 함께 저장하는 클래스 | + +- **예제: KeyStore 생성 및 저장** + ```java + import java.io.FileOutputStream; + import java.security.KeyStore; + + public class KeyStoreExample { + public static void main(String[] args) throws Exception { + KeyStore keyStore = KeyStore.getInstance("JKS"); + keyStore.load(null, null); // 새로운 KeyStore 생성 + + try (FileOutputStream fos = new FileOutputStream("keystore.jks")) { + keyStore.store(fos, "password".toCharArray()); // 비밀번호와 함께 저장 + } + System.out.println("KeyStore 저장 완료"); + } + } + ``` + +--- + +## 3. 해시(Hashing) 및 메시지 다이제스트(Message Digest) +해시는 데이터를 변환하여 무결성을 검증하는 데 사용돼. 대표적인 알고리즘으로 **SHA-256**, **MD5** 등이 있어. + +- **주요 클래스** + | 클래스 | 설명 | + |--------|------| + | `MessageDigest` | 해시 값을 생성하는 클래스 | + | `DigestInputStream` | 스트림을 통해 해시 계산을 수행하는 클래스 | + +- **예제: SHA-256 해싱** + ```java + import java.security.MessageDigest; + import java.util.Base64; + + public class HashExample { + public static void main(String[] args) throws Exception { + String input = "password123"; + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(input.getBytes()); + + System.out.println("SHA-256 Hash: " + Base64.getEncoder().encodeToString(hash)); + } + } + ``` + +--- + +## 4. 전자서명(Digital Signature) +전자서명은 데이터의 **무결성을 검증**하고 **서명자의 신원**을 확인하는 데 사용돼. + +- **주요 클래스 및 인터페이스** + | 클래스/인터페이스 | 설명 | + |------------------|------| + | `Signature` | 전자서명을 생성하고 검증하는 클래스 | + | `KeyPairGenerator` | 전자서명을 위한 키 쌍을 생성하는 클래스 | + +- **예제: 전자서명 생성 및 검증** + ```java + import java.security.*; + + public class DigitalSignatureExample { + public static void main(String[] args) throws Exception { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(2048); + KeyPair keyPair = keyGen.generateKeyPair(); + + Signature signature = Signature.getInstance("SHA256withRSA"); + signature.initSign(keyPair.getPrivate()); + + String message = "This is a secure message."; + signature.update(message.getBytes()); + byte[] signedData = signature.sign(); + + // 검증 + signature.initVerify(keyPair.getPublic()); + signature.update(message.getBytes()); + boolean isVerified = signature.verify(signedData); + System.out.println("Signature Verified: " + isVerified); + } + } + ``` + +--- + +## 5. 인증(Authentication) 및 접근 제어(Access Control) +사용자의 인증 및 권한 관리를 할 수 있도록 지원해. + +- **주요 클래스 및 인터페이스** + | 클래스/인터페이스 | 설명 | + |------------------|------| + | `AccessController` | 접근 제어를 수행하는 클래스 | + | `Permission` | 특정 작업에 대한 권한을 나타내는 클래스 | + | `Policy` | 보안 정책을 관리하는 클래스 | + +- **예제: 접근 제어 실행** + ```java + import java.security.AccessController; + import java.security.PrivilegedAction; + + public class AccessControlExample { + public static void main(String[] args) { + String result = AccessController.doPrivileged((PrivilegedAction) () -> { + return System.getProperty("user.home"); + }); + System.out.println("User Home Directory: " + result); + } + } + ``` + +--- + +## 6. 난수 생성(Secure Random) +보안에 강한 난수를 생성하는 기능도 제공해. + +- **주요 클래스** + | 클래스 | 설명 | + |--------|------| + | `SecureRandom` | 보안 강도를 높인 난수 생성 클래스 | + +- **예제: 난수 생성** + ```java + import java.security.SecureRandom; + + public class SecureRandomExample { + public static void main(String[] args) { + SecureRandom random = new SecureRandom(); + int number = random.nextInt(100); + System.out.println("Secure Random Number: " + number); + } + } + ``` + +--- + +## 7. 보안 프로바이더(Security Provider) +Java는 다양한 보안 알고리즘을 제공하는 **보안 프로바이더** 개념을 사용해. + +- **주요 클래스 및 인터페이스** + | 클래스/인터페이스 | 설명 | + |------------------|------| + | `Security` | 보안 프로바이더를 관리하는 클래스 | + | `Provider` | 특정 보안 기능을 제공하는 클래스 | + +- **예제: 설치된 보안 프로바이더 목록 출력** + ```java + import java.security.Provider; + import java.security.Security; + + public class SecurityProviderExample { + public static void main(String[] args) { + for (Provider provider : Security.getProviders()) { + System.out.println("Provider: " + provider.getName()); + } + } + } + ``` + +--- + +## 결론 +Java의 `java.security` 패키지는 **암호화, 키 관리, 해싱, 전자서명, 인증, 난수 생성** 등 다양한 보안 기능을 제공해. +각 기능을 적절히 조합하면 **네트워크 보안, 파일 보호, 인증 시스템** 등을 구축할 수 있어! + + + + +--- + + + + +Java의 **JCA(Java Cryptography Architecture)** 및 **JCE(Java Cryptography Extension)**에서 지원하는 주요 알고리즘을 정리해볼게. + +JCA는 **암호화, 키 관리, 전자서명, 해싱** 등의 보안 기능을 정의하는 **프레임워크**이고, +JCE는 JCA를 확장하여 **대칭키 암호화, 메시지 인증 코드(MAC), 키 생성** 등을 추가 지원하는 **확장 라이브러리**야. + +--- + +## **1. 암호화(Encryption) 및 복호화(Decryption)** +암호화는 데이터를 보호하는 가장 기본적인 보안 기술이야. JCE에서는 **대칭키 및 비대칭키 암호화**를 지원해. + +| **알고리즘** | **설명** | **키 길이 (비트)** | **모드** | +|-------------|---------|-----------------|-------| +| AES (Advanced Encryption Standard) | 현대적인 대칭키 암호화 | 128, 192, 256 | ECB, CBC, CFB, OFB, GCM | +| DES (Data Encryption Standard) | 오래된 대칭키 암호화 (더 이상 안전하지 않음) | 56 | ECB, CBC, CFB, OFB | +| Triple DES (DESede) | DES를 3번 수행하여 보안성 강화 | 112, 168 | ECB, CBC, CFB, OFB | +| Blowfish | 빠르고 유연한 대칭키 알고리즘 | 32~448 | ECB, CBC, CFB, OFB | +| RSA | 비대칭키 암호화 (공개키 암호화) | 1024, 2048, 4096 | - | +| ElGamal | 공개키 기반 암호화 | 1024 이상 | - | +| ECIES (Elliptic Curve Integrated Encryption Scheme) | 타원 곡선 암호화 (ECC) | 192, 224, 256, 384, 521 | - | + +**예제: AES 암호화 및 복호화** +```java +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import java.util.Base64; + +public class AESExample { + public static void main(String[] args) throws Exception { + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(128); + SecretKey secretKey = keyGen.generateKey(); + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + + String plaintext = "Hello, JCE!"; + byte[] encrypted = cipher.doFinal(plaintext.getBytes()); + + System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(encrypted)); + } +} +``` + +--- + +## **2. 해시(Hash) 및 메시지 다이제스트(Message Digest)** +해시는 데이터를 변환하여 **무결성을 보장**하는 데 사용돼. + +| **알고리즘** | **설명** | **출력 크기 (비트)** | +|-------------|---------|-----------------| +| MD5 | 오래된 해시 알고리즘 (더 이상 안전하지 않음) | 128 | +| SHA-1 | 보안 취약점이 발견된 해시 알고리즘 | 160 | +| SHA-256 | 가장 널리 사용되는 SHA-2 계열 해시 | 256 | +| SHA-512 | SHA-256보다 더 강력한 해시 | 512 | +| SHA3-256 | 최신 SHA-3 계열 해시 | 256 | + +**예제: SHA-256 해싱** +```java +import java.security.MessageDigest; +import java.util.Base64; + +public class SHA256Example { + public static void main(String[] args) throws Exception { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest("password123".getBytes()); + System.out.println("SHA-256 Hash: " + Base64.getEncoder().encodeToString(hash)); + } +} +``` + +--- + +## **3. 전자서명(Digital Signature)** +전자서명은 데이터의 **무결성을 보장**하고 **서명자의 신원**을 확인하는 데 사용돼. + +| **알고리즘** | **설명** | **키 길이 (비트)** | +|-------------|---------|-----------------| +| SHA1withRSA | SHA-1 기반 RSA 서명 (보안 취약) | 1024, 2048, 4096 | +| SHA256withRSA | SHA-256 기반 RSA 서명 | 2048, 4096 | +| SHA512withRSA | SHA-512 기반 RSA 서명 | 2048, 4096 | +| SHA256withECDSA | 타원 곡선 기반 전자서명 | 256, 384, 521 | + +**예제: RSA 전자서명 생성 및 검증** +```java +import java.security.*; + +public class DigitalSignatureExample { + public static void main(String[] args) throws Exception { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(2048); + KeyPair keyPair = keyGen.generateKeyPair(); + + Signature signature = Signature.getInstance("SHA256withRSA"); + signature.initSign(keyPair.getPrivate()); + + String message = "Secure message"; + signature.update(message.getBytes()); + byte[] signedData = signature.sign(); + + // 검증 + signature.initVerify(keyPair.getPublic()); + signature.update(message.getBytes()); + boolean isVerified = signature.verify(signedData); + System.out.println("Signature Verified: " + isVerified); + } +} +``` + +--- + +## **4. 메시지 인증 코드(Message Authentication Code, MAC)** +MAC은 **데이터의 무결성과 인증을 보장**하는 데 사용돼. + +| **알고리즘** | **설명** | **출력 크기 (비트)** | +|-------------|---------|-----------------| +| HmacMD5 | MD5 기반 MAC | 128 | +| HmacSHA1 | SHA-1 기반 MAC | 160 | +| HmacSHA256 | SHA-256 기반 MAC | 256 | +| HmacSHA512 | SHA-512 기반 MAC | 512 | + +**예제: HmacSHA256 사용** +```java +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.util.Base64; + +public class HmacExample { + public static void main(String[] args) throws Exception { + String key = "secret"; + String message = "Hello, MAC"; + + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(key.getBytes(), "HmacSHA256")); + byte[] hmac = mac.doFinal(message.getBytes()); + + System.out.println("HMAC: " + Base64.getEncoder().encodeToString(hmac)); + } +} +``` + +--- + +## **5. 난수 생성(Secure Random)** +보안성이 높은 난수를 생성할 때 사용해. + +| **알고리즘** | **설명** | +|-------------|---------| +| SHA1PRNG | 보안성이 강화된 PRNG (의사 난수 생성기) | +| NativePRNG | OS 기본 난수 생성기 사용 | +| Windows-PRNG | Windows용 PRNG | + +**예제: 보안 난수 생성** +```java +import java.security.SecureRandom; + +public class SecureRandomExample { + public static void main(String[] args) { + SecureRandom random = new SecureRandom(); + int number = random.nextInt(100); + System.out.println("Secure Random Number: " + number); + } +} +``` + +--- + +## **결론** +JCA 및 JCE에서는 **암호화, 해시, 전자서명, MAC, 난수 생성** 등의 다양한 알고리즘을 제공해. +이들을 조합하면 **데이터 보호, 인증, 무결성 검증** 같은 강력한 보안 시스템을 구축할 수 있어! + + + + + + + +--- + + + + + + +자바의 JCA (Java Cryptography Architecture)와 JCE (Java Cryptography Extension)는 암호화와 관련된 다양한 알고리즘을 제공합니다. JCA는 기본적인 암호화 프레임워크를 제공하며, JCE는 이를 확장하여 더 강력한 암호화 기능을 추가합니다. 아래는 JCA와 JCE에서 지원되는 주요 알고리즘을 정리한 내용입니다. 이 알고리즘들은 JDK 버전에 따라 다를 수 있으니, 사용하는 JDK 버전(예: JDK 8, 11, 17 등)에 따라 지원 여부를 확인하는 것이 좋습니다. + +--- + +### 1. **대칭키 암호화 알고리즘 (Symmetric Key Algorithms)** +- 데이터를 암호화하고 복호화할 때 동일한 키를 사용하는 알고리즘입니다. +- 대표적인 알고리즘: + - **AES (Advanced Encryption Standard)**: 128, 192, 256비트 키 지원. + - 모드: CBC, ECB, CTR, GCM 등. + - 패딩: PKCS5Padding, NoPadding 등. + - **DES (Data Encryption Standard)**: 56비트 키 (현재는 취약하여 권장되지 않음). + - **DESede (Triple DES)**: DES를 3번 반복 적용, 168비트 키. + - **Blowfish**: 가변 길이 키(최대 448비트) 지원. + - **RC2**, **RC4**: 오래된 알고리즘으로 보안성이 낮아 권장되지 않음. + +--- + +### 2. **비대칭키 암호화 알고리즘 (Asymmetric Key Algorithms)** +- 공개키와 개인키 쌍을 사용하여 암호화와 복호화를 수행합니다. +- 대표적인 알고리즘: + - **RSA**: 키 교환, 디지털 서명, 암호화에 사용. 일반적으로 1024, 2048, 4096비트 키 길이. + - **DSA (Digital Signature Algorithm)**: 디지털 서명 전용, 1024비트 이상 권장. + - **EC (Elliptic Curve)**: 타원 곡선 암호화, 효율적인 키 크기(예: 256비트로 RSA 3072비트 수준 보안 제공). + - 예: ECDSA (서명), ECDH (키 교환). + +--- + +### 3. **메시지 다이제스트 (해시 함수) 알고리즘** +- 데이터 무결성을 확인하기 위해 고정된 길이의 해시 값을 생성합니다. +- 대표적인 알고리즘: + - **MD5**: 128비트 출력 (현재는 충돌 취약성 때문에 권장되지 않음). + - **SHA-1**: 160비트 출력 (취약하여 더 이상 권장되지 않음). + - **SHA-2**: SHA-224, SHA-256, SHA-384, SHA-512. + - **SHA-3**: 최신 해시 알고리즘, SHA-2와 다른 구조로 보안성 강화. + +--- + +### 4. **MAC (Message Authentication Code) 알고리즘** +- 데이터 무결성과 인증을 보장하기 위한 keyed 해시 함수입니다. +- 대표적인 알고리즘: + - **HmacMD5**: MD5 기반 HMAC (취약성 때문에 권장되지 않음). + - **HmacSHA1**: SHA-1 기반 HMAC (현재는 보안성 낮음). + - **HmacSHA256**, **HmacSHA384**, **HmacSHA512**: SHA-2 기반, 보안성 우수. + - **HmacSHA3-256**, **HmacSHA3-512**: SHA-3 기반 (JDK 9 이상에서 지원). + +--- + +### 5. **디지털 서명 알고리즘** +- 데이터의 무결성과 출처를 보장합니다. +- 대표적인 알고리즘: + - **RSA**: SHA-1, SHA-256 등과 결합 (예: SHA256withRSA). + - **DSA**: SHA-1, SHA-256 등과 결합 (예: SHA256withDSA). + - **ECDSA**: 타원 곡선 기반 서명 (예: SHA256withECDSA). + +--- + +### 6. **키 생성 및 키 교환 알고리즘** +- 암호화에 사용할 키를 생성하거나 교환합니다. +- 대표적인 알고리즘: + - **Diffie-Hellman (DH)**: 키 교환용. + - **ECDH**: 타원 곡선 기반 키 교환. + - 키 생성기: AES, DES, RSA, EC 등에 사용되는 `KeyGenerator` 및 `KeyPairGenerator`. + +--- + +### 7. **기타 유틸리티** +- **Cipher**: 암호화/복호화 작업을 위한 클래스 (위의 알고리즘과 모드/패딩 조합 사용). +- **KeyStore**: 키와 인증서를 저장/관리. +- **SecureRandom**: 암호화에 적합한 난수 생성 (예: SHA1PRNG). + +--- + +### 참고사항 +- **지원 여부 확인**: JDK 버전과 제공자(Provider, 예: SunJCE, Bouncy Castle 등)에 따라 지원되는 알고리즘이 다를 수 있습니다. `Security.getProviders()`를 호출해 확인 가능. +- **보안 권장**: MD5, SHA-1, DES 등은 취약하니 최신 애플리케이션에서는 SHA-2, SHA-3, AES, RSA(2048비트 이상) 등을 사용하는 것이 좋습니다. +- **예제 코드**: + ```java + import javax.crypto.Cipher; + import javax.crypto.KeyGenerator; + import java.security.Key; + + public class AesExample { + public static void main(String[] args) throws Exception { + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); // 256비트 키 생성 + Key key = keyGen.generateKey(); + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, key); + byte[] encrypted = cipher.doFinal("Hello, World!".getBytes()); + System.out.println(new String(encrypted)); + } + } + ``` + +필요하면 특정 알고리즘에 대해 더 깊이 설명하거나 예제 코드를 추가로 제공할 수 있습니다. 질문이 더 있으면 말씀해주세요! \ No newline at end of file diff --git a/docs/security/pbkd.md b/docs/security/pbkd.md new file mode 100644 index 0000000..8d1f1b1 --- /dev/null +++ b/docs/security/pbkd.md @@ -0,0 +1,164 @@ +패스워드 기반 키 생성(Password-Based Key Derivation, PBKD)은 사용자가 제공한 패스워드(일반적으로 짧고 사람이 기억하기 쉬운 문자열)를 기반으로 암호화에 사용할 수 있는 안전하고 고정된 길이의 암호화 키를 생성하는 방법입니다. 자바에서는 JCE(Java Cryptography Extension)를 통해 이를 구현할 수 있으며, 대표적으로 **PBKDF2**(Password-Based Key Derivation Function 2)가 널리 사용됩니다. + +아래에서 패스워드 기반 키 생성의 개념, 동작 원리, 주요 알고리즘, 자바에서의 구현 방법 등을 상세히 설명하겠습니다. + +--- + +### **패스워드 기반 키 생성의 개념** +- **문제점**: 패스워드는 보통 길이가 짧고 엔트로피(무작위성)가 낮아 직접 암호화 키로 사용하기에는 부적합합니다. 예를 들어, AES 키는 128비트(16바이트) 이상이어야 하지만, "password123" 같은 패스워드는 그보다 훨씬 짧고 예측 가능합니다. +- **해결책**: PBKD는 패스워드에 **솔트(Salt)**와 반복적인 해시 연산을 적용하여 안전하고 고정된 길이의 키를 생성합니다. +- **목적**: + 1. 패스워드의 엔트로피를 높여 무차별 대입 공격(Brute Force)이나 사전 공격(Dictionary Attack)을 어렵게 만듦. + 2. AES, RSA 등 암호화 알고리즘이 요구하는 특정 길이의 키(예: 256비트)를 생성. + +--- + +### **주요 구성 요소** +1. **패스워드(Password)**: + - 사용자가 제공한 문자열(예: "MySecretPass123"). + - 보통 유니코드 문자로 표현되며, 직접 키로 사용되지 않음. + +2. **솔트(Salt)**: + - 무작위로 생성된 바이트 배열. + - 동일한 패스워드라도 다른 키를 생성하도록 보장하며, 사전 공격(Precomputed Table, Rainbow Table)을 방지. + - 일반적으로 8바이트 이상(16바이트 권장). + +3. **반복 횟수(Iteration Count)**: + - 해시 함수를 반복 적용하는 횟수. + - 계산 비용을 높여 무차별 대입 공격을 느리게 만듦. + - 예: 10,000회 이상(현대 하드웨어 기준으로는 100,000회 이상 권장). + +4. **키 길이(Key Length)**: + - 출력할 키의 길이(예: AES 256비트 = 32바이트). + - 사용하려는 암호화 알고리즘에 맞게 지정. + +5. **해시 알고리즘**: + - 내부적으로 사용되는 암호화 해시 함수(예: SHA-256, SHA-512 등). + +--- + +### **대표 알고리즘: PBKDF2** +- **정의**: NIST와 RSA에서 표준화된 알고리즘으로, HMAC(Hash-based Message Authentication Code)을 기반으로 키를 생성. +- **동작 방식**: + 1. 패스워드와 솔트를 입력으로 HMAC 함수(예: HMAC-SHA256)에 넣음. + 2. 지정된 반복 횟수만큼 HMAC 연산을 반복. + 3. 결과로 고정된 길이의 키를 출력. +- **표기**: 자바에서는 `"PBKDF2WithHmacSHA256"`처럼 HMAC와 결합된 해시 알고리즘을 지정. + +#### **지원되는 해시 알고리즘** +- `PBKDF2WithHmacSHA1` (구형, 권장되지 않음). +- `PBKDF2WithHmacSHA256` (권장). +- `PBKDF2WithHmacSHA512` (더 높은 보안). + +--- + +### **자바에서 PBKDF2 구현 예제** +자바에서는 `PBEKeySpec`와 `SecretKeyFactory`를 사용하여 PBKDF2 기반 키를 생성할 수 있습니다. + +```java +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import java.security.SecureRandom; +import java.security.spec.KeySpec; +import java.util.Base64; + +public class Pbkdf2Example { + public static void main(String[] args) throws Exception { + // 1. 패스워드 정의 + String password = "MySecretPass123"; + + // 2. 솔트 생성 + SecureRandom random = new SecureRandom(); + byte[] salt = new byte[16]; // 16바이트 솔트 + random.nextBytes(salt); + + // 3. PBKDF2 매개변수 설정 + int iterationCount = 100000; // 반복 횟수 + int keyLength = 256; // 출력 키 길이 (AES 256비트) + KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterationCount, keyLength); + + // 4. PBKDF2 키 생성 + SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); + SecretKey key = factory.generateSecret(spec); + + // 5. 생성된 키 출력 + byte[] keyBytes = key.getEncoded(); + String keyBase64 = Base64.getEncoder().encodeToString(keyBytes); + System.out.println("Generated Key: " + keyBase64); + System.out.println("Salt: " + Base64.getEncoder().encodeToString(salt)); + } +} +``` + +#### **출력 예시** +``` +Generated Key: X7k... (32바이트 Base64 인코딩) +Salt: abC... (16바이트 Base64 인코딩) +``` + +--- + +### **AES와 결합한 예제** +생성된 키를 AES-GCM 암호화에 사용하는 예제입니다. + +```java +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; + +public class Pbkdf2AesGcmExample { + public static void main(String[] args) throws Exception { + // 1. PBKDF2로 키 생성 (위 예제에서 가져옴) + String password = "MySecretPass123"; + byte[] salt = new byte[16]; + SecureRandom random = new SecureRandom(); + random.nextBytes(salt); + PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 100000, 256); + SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); + SecretKey pbkdf2Key = factory.generateSecret(spec); + SecretKey key = new SecretKeySpec(pbkdf2Key.getEncoded(), "AES"); + + // 2. AES-GCM 설정 + byte[] iv = new byte[12]; // 12바이트 Nonce + random.nextBytes(iv); + GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv); // 128비트 태그 + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + cipher.init(Cipher.ENCRYPT_MODE, key, gcmSpec); + + // 3. 암호화 + byte[] plaintext = "Hello, PBKDF2!".getBytes(StandardCharsets.UTF_8); + byte[] ciphertext = cipher.doFinal(plaintext); + + // 출력 + System.out.println("Ciphertext: " + Base64.getEncoder().encodeToString(ciphertext)); + } +} +``` + +--- + +### **장점** +1. **보안성**: 솔트와 반복 연산으로 패스워드의 약점을 보완. +2. **유연성**: 출력 키 길이를 자유롭게 조정 가능. +3. **표준화**: PBKDF2는 NIST SP 800-132 등에서 권장. + +### **단점 및 주의사항** +1. **성능**: 반복 횟수가 많을수록 계산 비용 증가 (의도된 설계이나 최적화 필요). +2. **솔트 관리**: 솔트는 암호화된 데이터와 함께 저장해야 하며, 재사용 시 동일한 키를 생성해야 함. +3. **현대 대안**: Argon2, bcrypt, scrypt 등이 더 강력한 대안으로 주목받고 있음(자바 기본 JCE에서는 미지원, 외부 라이브러리 필요). + +--- + +### **권장 설정** +- **솔트**: 최소 16바이트, SecureRandom으로 생성. +- **반복 횟수**: 하드웨어 성능에 따라 100,000회 이상(예: 2025년 기준 1초 이내 처리 목표). +- **해시**: SHA-256 또는 SHA-512. +- **키 길이**: AES 사용 시 256비트 권장. + +--- + +패스워드 기반 키 생성에 대해 더 궁금한 점이나 특정 부분에 대한 추가 설명이 필요하면 말씀해주세요! \ No newline at end of file