자바 암호 프로그래밍 Java Cryptography Programming

Slides:



Advertisements
Similar presentations
멘토링 2 주차 장 프로그래밍을 위한 자바의 자료형  값이 변하지 않는 상수  메모리 기억공간인 변수.
Advertisements

SSL (Secure Socket Layer) 중부대학교 정보보호학과 이병천 교수. 웹 보안 구현방법  네트워크 계층에서의 구현방법  특징  IP 계층에 보안 기능을 둠  IP Sec  응용계층의 모든 응용서비스에 보안성 제공  VPN(Virtual Private.
명품 JAVA Programming 제 3 장 반복문, 배열, 예외처리.
어서와 Java는 처음이지! 제3장선택과 반복.
제 7주 2015년 1학기 강원대학교 컴퓨터학부 담당교수: 정충교
어서와 Java는 처음이지! 제2장 자바 프로그래밍 기초.
웹 어플리케이션 보안 2016년 2학기 12. Cryptography.
컴퓨터 응용 및 실습 Part1. OOP&Java Programming data type Review
자바 암호화 프로그래밍 전자상거래보안.
어서와 Java는 처음이지! 제2장 자바 프로그래밍 기초.
7장 배열 ②.
어서와 Java는 처음이지! 제4장 배열.
Programming for the java Virtual machine
(c) Byoungcheon Lee, Joongbu Univ.
자바 암호 프로그래밍 Java Cryptography Programming
명품 JAVA Programming.
자바 암호 프로그래밍 Java Cryptography Programming
자바 암호 프로그래밍 Java Cryptography Programming
자바란 무엇인가? JDK의 다운로드 및 설치 방법 Hello, Java 프로그램의 작성 자바 프로그램의 작동 원리
자바 암호 프로그래밍 Java Cryptography Programming
전자상거래 보안 (암호학과 네트워크보안) Chul Ho Rhee
공개키 기반구조 (Public Key Infrastructure)
제 10장 인증서 공개 키를 이용한 디지털 서명.
Chapter 3. Architecture AI & HCI Lab 김 주 영.
Chapter 02 자바 기본구조 자바 프로그래밍의 기초적인 문법을 소개
Chapter 8 목차 8.1 네트워크 보안이란 무엇인가? 8.2 암호학의 원리 8.3 메시지 무결성 8.4 종단점 인증
[ 단원 08 ] 예외처리와 스레드.
2강. JAVA 프로그래밍이란?-II & 변수 JAVA 프로그램 환경설정과 실행 방법 변수란?
명품 JAVA Essential.
제 4장 블록 암호 모드.
8장 자바 입출력.
Power Java 제10장 배열.
자바 암호 프로그래밍 Java Cryptography Programming
Choi, Namseok Java 기초 (Java의 제어문과 배열) Choi, Namseok
자바 암호 프로그래밍 Java Cryptography Programming
08장 암호의 이해: 숨기고자 하는 이들의 싸움.
10장 SafeTalk 시스템 소프트웨어 연구실 성순화 이재일
명품 JAVA Programming 제 8 장 입출력 스트림과 파일 입출력.
명품 JAVA Essential.
명품 Java Programming.
Key and Certificate Management Using Keystores
제 1장 소 개 컴퓨터네트워크실험실 우 준.
2장 자바환경과 자바 프로그램 2.1 자바 개발 환경 2.2 자바 통합환경 2.3 자바 응용 프로그램과 애플릿 프로그램
주소록 프로그램.
2 : 대칭암호화 소제목 : 기본적인 대칭암호화.
목 차 PGP S/MIME. 전자우편 보안 Security 목 차 PGP S/MIME.
제 4주 2014년 1학기 강원대학교 컴퓨터학부 담당교수: 정충교
4장 Random Number 프로그래밍 언어 실험실 석사 3학기 박중기
Chapter6 : JVM과 메모리 6.1 JVM의 구조와 메모리 모델 6.2 프로그램 실행과 메모리 6.3 객체생성과 메모리
자바 암호 프로그래밍 Java Cryptography Programming
03. 안드로이드를 위한 Java 문법 제목. 03. 안드로이드를 위한 Java 문법 제목.
WAP Java Seminar
Ch.1 Iterator Pattern <<interface>> Aggregate +iterator
전자상거래보안 전자우편보안 ( Security) 중부대학교 정보보호학과 이병천 교수
제 2장 어휘구조와 자료형 토 큰 리 터 럴 주 석 자 료 형 배 열 형.
Use of a Broken or Risky Cryptographic Algorithm
컴퓨터공학실습(I) 3주 인공지능연구실.
2. CONCEPTS 컴퓨터 네트워크 실험실 석사 1학기 강 동 호.
내부 클래스와 내부 인터페이스에 대하여 내부 클래스의 선언 방법과 이용 방법 내부 인터페이스의 선언 방법과 이용 방법
자바 암호 프로그래밍 Java Cryptography Programming
자바 5.0 프로그래밍.
Java 3장. 자바의 기본 구조 I : 변수, 자료형, 연산자 public class SumTest {
JVM의 구조와 메모리 모델 JVM의 내부 구조 클래스 파일 클래스 로더 메소드(method) 영역 힙(heap) 영역
자바 5.0 프로그래밍.
자바 암호 프로그래밍 Java Cryptography Programming
C# 10장. 참조형.
자바 암호 프로그래밍 Java Cryptography Programming
Choi Younghwan CSE HUFS
자바 암호 프로그래밍 Java Cryptography Programming
자바 암호 프로그래밍 Java Cryptography Programming
Presentation transcript:

자바 암호 프로그래밍 Java Cryptography Programming 2015. 9. 중부대학교 정보보호학과 이병천 교수

차례 1. 암호 핵심 개념 2. 자바 암호 프로그래밍 3. 인증서와 PKI JCA/JCE 소개 난수 생성 해쉬함수 MAC 패스워드 기반 키생성 대칭키 암호, 파일 암호화/복호화 공개키 암호 전자서명 3. 인증서와 PKI

1. 암호 핵심 개념

1.1 암호의 개념 암호(cryptography) 현대 암호가 제공해야 하는 정보보호 기능 암호학 암호의 어원: 그리스어 Cryptos 평문을 해독 불가능한 형태로 변형하거나 또는 암호화된 통신문 을 원래의 해독 가능한 상태로 복구하는 것 현대 암호가 제공해야 하는 정보보호 기능 기밀성: 정보를 타인이 보지 못하도록 감춤 (암호화) 무결성: 정보의 불법 변조 여부를 확인 (해쉬함수) 부인방지: 사용자의 행위를 부인하지 못함 (전자서명) 인증, 접근통제: 정보에 대한 적법한 권한을 가지고 있는지 확인 암호학 암호학이란 이와 같은 기능들을 구현하기 위한 모든 수학적인 원 리, 수단, 방법 등의 기반기술을 말함 암호를 사용하지 않고 궁극적인 정보보호를 성취하는 것은 불가 능

암호 시스템의 구성 도청자 (eavesdropper) 공격자 (attacker) 송신자 (sender) 수신자 (receiver)

암호 관련 용어 설명 도청자(eavesdropper) 공격자(attacker) 암호설계(cryptography) 암호해독(cryptanalysis) 수동공격(passive attack) 능동공격(active attack)

1.2 암호 알고리즘 대칭키 암호(비밀키 암호) 1) 블록 암호 2) 스트림 암호 암호화와 복호화 알고리즘에 동일한 키가 사용되는 방식의 암호 비밀키는 제3자에게 알려지면 안되므로 송신자와 수신자는 사용 되는 키를 비밀리에 공유하고 안전하게 보관해야 한다. 1) 블록 암호 대칭키 암호의 일종으로 암호화와 복호화시 특정 크기의 블록 단 위로 암호화/복호화 연산을 하는 방식의 암호 각 블록의 암호화와 복호화에는 동일한 키가 사용됨 2) 스트림 암호 블럭의 크기를 1로 하여 블록 마다 각각 다른 키를 사용하여 암 호문을 생성하는 방식 암호화와 복호화시 키스트림 생성기를 이용하여 키스트림을 생 성하며 이것을 평문과 연산하여 암호화하고 거꾸로 이것을 암호 문과 연산하여 평문을 얻어낸다.

암호 알고리즘 비대칭키 암호(공개키 암호) 하나의 쌍이 되는 두 개의 키를 생성하여 하나는 암호화에 사용 하고 다른 하나는 복호화에 사용한다. 암호화에 사용하는 키는 공개할 수 있어서 공개키라고 부르고 복 호화에 사용하는 키는 사용자만이 안전하게 보관해야 하므로 개 인키(비밀키)라고 부른다. 두 개의 키가 서로 다르므로 비대칭키 암호라고 부르며 하나의 키를 공개하므로 공개키 암호라고도 부른다. 공개키를 공개하더라도 이것으로부터 개인키를 계산해내는 것은 수학적으로 어려운 문제이다.

암호 알고리즘 해쉬함수 임의의 길이의 정보(비트스트링)를 입력으로 하여 고정된 길이의 출력값인 해쉬코드를 생성해내는 함수 임의의 길이의 정보(비트스트링)를 입력으로 하여 고정된 길이의 출력값인 해쉬코드를 생성해내는 함수 해쉬값은 입력정보에 대한 변조할 수 없는 특징값을 나타내며 통 신 중에 정보의 변조가 있었는지 여부를 확인하는 용도에 사용된 다. 이런 용도로 사용될 수 있기 위해서 해쉬함수는 같은 해쉬값을 가지는 두 개의 입력 메시지를 찾는 것이 계산적으로 불가능해야 한다. 해쉬함수에는 키를 사용하지 않는다.

암호 알고리즘 메시지인증코드(MAC : Message Authentication Code) 데이터가 변조(수정, 삭제, 삽입 등)되었는지를 검증할 수 있도록 데이터에 덧붙이는 코드 원래의 데이터로만 생성할 수 있는 값을 데이터에 덧붙여서 확인 하도록 하는 것 송신자와 수신자는 비밀키를 공유하고 있으며 MAC 계산에 비밀 키를 사용한다

암호 알고리즘 전자서명 전자문서에 대한 전자적인 방식에 의한 서명으로 서명자만이 생 성할 수 있고 누구나 서명의 유효성을 검증할 수 있다. 전자서명은 공개키 암호 방식의 일종이다. 개인키로 서명하고 공개키로 검증한다. 개인키는 해당 서명자만이 가지고 있으므로 다른 사람이 서명을 위조할 수 없으며 전자서명은 서명자의 정당한 서명으로 인정된 다.

암호 알고리즘 난수 생성 예측하기 어려운 난수를 생성하는 것이 매우 중요 암호키는 공격자가 예측 불가능하게 만들어져야 함

암호 알고리즘 키합의 공개키 암호는 속도가 느리기 때문에 실제의 데이터를 암호화, 복호화하는 용도에 사용하지 않는다. 공개키 암호는 속도가 느리기 때문에 실제의 데이터를 암호화, 복호화하는 용도에 사용하지 않는다. 송신자와 수신자가 비밀키 암호를 사용하기 위해서는 미리 비밀 키를 공유하거나 안전한 통신 채널을 사용하여 세션키를 전송하 는 것이 필요하다. 송신자와 수신자가 직접 만나지 않고도 공개된 통신채널을 통해 서 특정한 방법으로 세션키를 안전하게 공유하는 방식을 키합의 라고 한다.

2. 자바 암호 프로그래밍

2.1 JCA/JCE 소개 자바에서의 암호 구현 패키지 JCA(Java Cryptography Architecture) Import java.security.* 미국의 수출규제를 통과할 수 있는 내용으로 구현 JCE(Java Cryptography Extension) Import javax.crypto.* JCA에서 부족한 내용을 보충하여 별도로 구현 JCA와 JCE는 프로그래머들이 응용을 개발할 때 사용할 수 있는 암호프로그래밍의 추상 계층(abstraction layer) 을 제공

JCA JCA는 제공자 기반 구조(provider-based architecture) 라 하며,다음과 같은 원리를 기반으로 설계되었다. 알고리즘 독립성 알고리즘 확장성: 새 알고리즘을 쉽게 추가할 수 있는 구조라는 것을 말한다. 구현 독립성: 프로그래머는 알고리즘을 구현한 제공자가 누구인 지 알 필요가 없다. 구현간 상호운영: 프로그래머가 서로 다른 제공자에 의해 제공되 는 구현을 사용하더라도 동작해야 한다는 것을 말한다.

알고리즘의 독립성 같은 종류의 여러 알고리즘을 동일한 메소드를 이용하여 암 호연산을 수행할 수 있음. 이를 위해 다음과 같이 암호연산을 분류한다. MessageDigest: 해쉬함수 Signature: 전자서명 KeyPairGenerator: 전자서명을 위한 키 쌍 생성 KeyFactory KeyStore: 다양한 암호키 관리 SecureRandom: 의사난수 비트 생성 AlgorithmParameters AlgorithmParameterGenerator CertificateFactory: 인증서와 인증서폐지목록을 생성 CertPathBuilder CertStore

알고리즘의 독립성 같은 인터페이스에 알고리즘 이름만 바꾸어 사용할 수 있도록 구현 try{ 같은 인터페이스에 알고리즘 이름만 바꾸어 사용할 수 있도록 구현 try{ MessageDigest md5 = MessageDigest.getInstance(“MD5”); // MessageDigest md5 = MessageDigest.getInstance(“SHA-1”); md5.update(buffer); byte[] digest = md5.digest(); for(int i=0; i<digest.length; i++) System.out.printf(“%02X ”, digest[i]); } catch(NoSuchAlgorithmException e){ e.printStackTrace();

JCE JCE는 JCA를 확장한 것으로, 다음과 같은 엔진을 추가 로 제공한다. Cipher: 암호화/복호화 KeyGenerator: Cipher를 위한 비밀키 생성 SecretKeyFactory KeyAgreement: 키 동의 프로토콜을 위한 클래스 Mac: 메시지 인증 코드 JCE의 엔진은 javax.crypto 패키지에 포함되어 있다. JDK 1.4부터 JCA/JCE 모두 기본적으로 포함되어 있다.

2.2 의사난수(pseudo random number) 생성 난수생성의 중요성 암호에서 사용하는 키는 일반적으로 난수를 이용하여 생성해야 안전함. 사람이 선택하는 패스워드는 암호키로 사용하지 않음 자바에서의 난수 보통 java.lang.Math에 정의된 random() 메소드나 java.util.Random 클래스를 사용하는데 이들은 암호학적으로 안 전하지 못함 JCA에서는 java.security.SecureRandom 엔진을 사용. 이 엔진 은 java.util.Random 클래스를 상속받고 있어, nextInt()와 같은 매우 편리한 메소드들을 제공하고 있다. 의사난수 비트 생성은 보통 실제 랜덤한 seed를 사용한 다. 이를 위해 사용자가 직접 setSeed 메소드를 사용할 수 있지만 일반적으로는 엔진이 안전한 seed를 자동으 로 선택하도록 하는 것이 바람직하다.

의사난수 생성 사례 try{ SecureRandom csprng = SecureRandom.getInstance("SHA1PRNG"); boolean randBool = csprng.nextBoolean(); int randInt = csprng.nextInt(); byte[] randBytes = new byte[3]; csprng.nextBytes(randomBytes); } catch(NoSuchAlgorithmException e){ e.printStackTrace();

2.3 해쉬함수 해쉬함수란? 해쉬함수의 요구조건 입력값에 대한 고정된 길이의 특징값을 출력하는 함수. 암호키를 사용하지 않는 공개된 함수 해쉬함수의 요구조건 일방향성 충돌회피성

해쉬함수 기본적으로 지원하는 해쉬함수들 해쉬값의 비교 MD2 (RFC 1319) MD5 (RFC 1321) SHA-1 (NIST FIPS 180-1) SHA-256, SHA-384, SHA-512: SHA-1의 해쉬값의 길이를 증가 시켜 충돌회피성을 높이고자 제안된 해쉬함수 해쉬값의 비교 isEqual 메소드 이용: 두 개의 바이트 배열을 비교한다. java.util.Array.equals()을 이용할 수도 있다.

해쉬함수 java.security.MessageDigest 엔진을 사용 try{ MessageDigest md5 = MessageDigest.getInstance("MD5"); md5.update(plaintext.getBytes()); byte[] digest01 = md5.digest(); for(byte b: digest01) System.out.printf("%02X ", b); System.out.println(); byte[] digest02 = md5.digest(); System.out.printf("Verified = %s%n", MessageDigest.isEqual(digest01, digest02)); } catch(NoSuchAlgorithmException e){ e.printStackTrace();

두 메시지의 해쉬값 비교 public class DigestTest { public static void main(String[] args) { String plaintext01 = "This is a simple message."; String plaintext02 = "This is a simple message"; try{ MessageDigest md5 = MessageDigest.getInstance("MD5"); md5.update(plaintext01.getBytes()); byte[] digest01 = md5.digest(); for(byte b: digest01) System.out.printf("%02X ", b); System.out.println(); md5.update(plaintext02.getBytes()); byte[] digest02 = md5.digest(); for(byte b: digest02) System.out.printf("%02X ", b); System.out.printf("Verified = %s%n", MessageDigest.isEqual(digest01, digest02)); } catch(NoSuchAlgorithmException e){ e.printStackTrace(); } // main } // DigestTest

2.4 MAC MAC(메시지인증코드)란? 기본적으로 제공되는 MAC 알고리즘 해쉬함수와 공유된 대칭키를 이용하여 송수신하는 메시지를 인 증하는데 사용 해쉬함수 기반의 MAC은 javax.crypto.Mac 엔진을 사용 MAC은 대칭 암호알고리즘처럼 암호키가 필요하다. 자바 라이브러리에서는 기존 대칭키를 MAC에 적합하도록 변환 하여 사용한다. 기본적으로 제공되는 MAC 알고리즘 HmacMD5, HmacSHA1, HmacSHA256, HmacSHA384, HmacSHA512

MAC 사례 try{ KeyGenerator kg = KeyGenerator.getInstance("AES"); SecretKey key = kg.generateKey(); SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "HmacSHA1"); Mac mac = Mac.getInstance("HmacSHA1"); mac.init(keySpec); mac.update(plaintext.getBytes()); byte[] digest01 = mac.doFinal(); for(byte b: digest01) System.out.printf("%02X ", b); System.out.println(); byte[] digest02 = mac.doFinal(); System.out.printf("Verified = %s%n", MessageDigest.isEqual(digest01, digest02)); } catch(NoSuchAlgorithmException e){ e.printStackTrace();

2.5 대칭키 암호 비밀키 생성 Key Spec 변환 채우기 암호화 모드 Cipher 객체의 선언 및 초기화 암호화/복호화

비밀키의 생성 비밀키는 알고리즘에 따라 키 길이가 다르다. 자바에서는 사용자가 키 길이를 별도로 제시하지 않아 도 선택한 알고리즘에 필요한 비밀키를 생성하여 준다. 필요하면 특정한 알고리즘을 사용하여 키를 생성하도록 설정할 수도 있다. (init 메소드 이용) init(int keySize) init(SecureRandom random) init(int keySize, SecureRandom random) javax.crypto.KeyGenerator 엔진을 사용 KeyGenerator kg = KeyGenerator.getInstance("AES"); 키의 실제 생성은 generateKey 메소드를 이용하며, 그 결과는 SecretKey 클래스에 유지된다.

Key Spec 변환 generateKey() 메소드를 이용하여 생성된 키를 바로 알고리즘에 사용할 수 없다. 이것을 key specification으로 변환해야 한다. 이 변환은 생성된 키가 알고리즘에 사용하기에 보다 적합하도록 변환하는 것이다. javax.crypto.spec.SecretKeySpec 엔진을 사용 KeyGenerator kg = KeyGenerator.getInstance("DES"); SecretKey key = kg.generateKey(); SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "DES");

채우기 암호화 모드 블록 암호 방식에서는 마지막 블록을 완전 블록으로 만들기 위해 채우기가 필요하다. JCE는 4가지 채우기 방법을 제공 none: 사용자가 완전 블록임을 보장해 주어야 한다. PKCS5Padding SSL3Padding (예약만 되어 있고, 실제 구현되어 있지 않음) OAEPWith<digest>And<mgf>Padding 암호화 모드 ECB, CBC, CFB, CTR 모드 제공

암호화/복호화 Cipher 엔진 Cipher 엔진은 비밀키 방식의 암호화/복호화를 하기 위해 사용 된다. 이 엔진을 사용하기 위해서는 먼저 사용할 알고리즘을 지정하여 야 한다. 이 때 알고리즘 이름 뿐만 아니라 암호화 모드, 채우기 방식을 함 께 지정할 수 있다. 암호화 모드와 채우기 방식을 지정하지 않으면 제공자에 의해 결 정된 모드와 채우기 방식으로 암호화가 이루어진다. Cipher DESCipher = Cipher.getInstance("DES"); Cipher DESCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");

Cipher 엔진의 동작모드 (opmode) 객체의 초기화 public void init(int opmode, Key key) Cipher 엔진의 동작모드 (opmode) Cipher.ENCRYPT_MODE: 암호화 연산을 사용하고자 할 때 Cipher.DECRYPT_MODE: 복호화 연산을 사용하고자 할 때

암호화 방법1. doFinal() 메소드만 호출 암호화하고자 하는 평문의 크기가 작을 경우 방법2.일련의 update() 메소드를 호출한 후에 doFinal() 메소드 호출 암호화하고자 하는 평문의 크기가 크거나 나누어져 있을 경우 String plaintext = "This is a secret message!"; byte[] ciphertext = cipher.doFinal(plaintext.getBytes()); byte[] ciphertext = new byte[cipher.getOutputSize(input.length)]; int ctLength = cipher.update(myByteArray01, 0, myByteArray01.length, ciphertext, 0); ctLength += cipher.update(myByteArray02, 0, myByteArray02.length, ciphertext, ctLength); ctLength += cipher.doFinal(ciphertext, ctLength);

DES 암호화 종합 예제 try{ KeyGenerator kg = KeyGenerator.getInstance("DES"); SecretKey key = kg.generateKey(); SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "DES"); Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, keySpec); String plaintext = "This is a secret message!"; byte[] ciphertext = cipher.doFinal(plaintext.getBytes()); for(int i=0; i<ciphertext.length; i++){ System.out.printf("%02X ", ciphertext[i]); } System.out.println(); cipher.init(Cipher.DECRYPT_MODE,keySpec); byte[] cleartext = cipher.doFinal(ciphertext); for(int i=0; i<cleartext.length; i++){ System.out.print((char)cleartext[i]); catch(){

2.6 파일 암호화/복호화 파일을 암호화: CipherInputStream 이용 파일은 FileInputStream 이용하여 입력 암호는 Cipher 객체로 입력

파일 암호화 FileInputStream inFile = new FileInputStream(new File("input.txt")); KeyGenerator kg = KeyGenerator.getInstance("AES"); SecretKey key = kg.generateKey(); SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, keySpec); final int BLOCKSIZE = cipher.getBlockSize(); CipherInputStream cinFile = new CipherInputStream(inFile,cipher); FileOutputStream encryptOutFile = new FileOutputStream(new File("output")); byte[] block = new byte[BLOCKSIZE]; int length = cinFile.read(block); while(length!=-1){ encryptOutFile.write(block,0,length); length = cinFile.read(block); } encryptOutFile.close(); inFile.close(); cinFile.close();

파일 복호화 암호화된 파일을 복호화 : CipherOutputStream 이용 cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, keySpec); FileInputStream encryptInFile = new FileInputStream(new File("output")); FileOutputStream outFile = new FileOutputStream(new File("output.txt")); CipherOutputStream coutFile = new CipherOutputStream(outFile,cipher); length = encryptInFile.read(block); while(length!=-1){ coutFile.write(block,0,length); } coutFile.close(); encryptInFile.close(); outFile.close();

2.7 공개키 암호 키쌍의 생성 키의 인코딩 공개키/개인키의 파일 처리 RSA 암호

키쌍의 생성 java.security.KeyPairGenerator를 이용 생성된 공개키 쌍은 getPublic(), getPrivate() 메소드를 이용하 여 접근할 수 있다. 공개키와 개인키는 java.security.PublicKey, java.security.PrivateKey 객체로 유지할 수 있다. KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(1024); KeyPair keyPair = kpg.genKeyPair(); PublicKey pubKey = keyPair.getPublic(); PrivateKey privKey = keyPair.getPrivate();

키의 인코딩 대칭키는 특별한 인코딩을 사용하지 않지만 공개키들은 특별한 인코딩을 사용한다. 이와 같은 인코딩이 필요한 이유는 유지해야 하는 정보가 복잡하기 때문이다. RSA의 경우에는 개인키/공개키가 두 개의 정수로 구성 공개키: (n,e) 개인키: (n,d) RSA 알고리즘의 경우 공개키는 X.509 인코딩을 사용. 공개키는 인증서와 함께 파일시 스템에 저장 개인키는 PKCS8 인코딩을 사용. 개인키는 패스워드 기반 암호방 식을 통해 암호화된 상태로 저장

공개키/개인키의 파일 처리 KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(1024); KeyPair keyPair = kpg.genKeyPair(); PublicKey pubKey = keyPair.getPublic(); PrivateKey privKey = keyPair.getPrivate(); FileOutputStream publicFos = new FileOutputStream(pubKeyFile); publicFos.write(pubKey.getEncoded()); publicFos.close(); FileOutputStream privateFos = new FileOutputStream(privKeyFile); privateFos.write(privKey.getEncoded()); privateFos.close(); FileInputStream privateFis = new FileInputStream(privKeyFile); ByteArrayOutputStream privKeyBaos = new ByteArrayOutputStream(); int curByte = 0; while((curByte = privateFis.read())!=-1){ privKeyBaos.write(curByte); } PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyBaos.toByteArray()); privKeyBaos.close();

RSA 암호 예제 try{ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(1024); KeyPair keyPair = kpg.genKeyPair(); PublicKey pubKey = keyPair.getPublic(); PrivateKey privKey = keyPair.getPrivate(); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, pubKey); String plaintext = "This is a secret message!"; byte[] ciphertext = cipher.doFinal(plaintext.getBytes()); for(byte b: ciphertext) System.out.printf("%02X ", b); System.out.println(); cipher.init(Cipher.DECRYPT_MODE, privKey); byte[] cleartext = cipher.doFinal(ciphertext); for(byte b: cleartext) System.out.print((char)b); } catch(){

2.8 전자서명 전자문서에 대한 공개키 암호기술을 이용한 서명 java.security.Signature 엔진을 사용 기본적으로 제공되는 전자서명 알고리즘 ECDSA, MD2withRSA, MD5withRSA, NONEwithDSA, SHA1withDSA, SHA1withRSA

전자서명 생성 try{ … Signature signatureEngine = Signature.getInstance("MD5withRSA"); signatureEngine.initSign(privKey); String plaintext = "This is my message!"; signatureEngine.update(plaintext.getBytes()); byte[] signature = signatureEngine.sign(); for(byte b: signature) System.out.printf("%02X ", b); } catch(){

전자서명 검증 try{ … Signature signatureEngine = Signature.getInstance("MD5withRSA"); String plaintext = "This is my message!"; signatureEngine.initVerify(pubKey); signatureEngine.update(plaintext.getBytes()); boolean isVerified = signatureEngine.verify(signature); System.out.println(isVerified); } catch(){

3. 인증서와 PKI

3.1 인증서 인증서의 구성

인증서의 확장 필드 발급자키식별자(Authority Key Identifier): 이 인증서를 확인할 때 사용할 발급자의 공개키를 독특하게 식별하는 식별자 자체 서명 인증서를 제외한 모든 인증서의 필수 요소 주체키식별자(Subject Key Identifier): 이 인증서에 포함된 공개키 를 독특하게 식별하는 식별자 인증기관 인증서의 경우에는 필수 요소 키용도(Key Usage): 이 인증서의 바인딩되어 있는 공개키의 사용용 도를 한정하기 위해 사용 전자서명, 부인방지, 키 암호화, 데이터 암호화, 키 동의 등 인증기관의 경우 keyCertSign, cRLSign이 설정되어 있어함 CRL 분배점(CRL distribution point): 이 인증서의 폐지 여부를 확 인하기 위한 인증서 폐지 목록이 있는 위치 Basic-Constraints: 이 인증서가 인증기관의 인증서임을 나타내기 위해 사용됨

X.500 DN 명명법 DN(Distinguished Name) 명명법: 계층구조 형태 사용 C: Country (국가) O: Organization (소속기관) OU: Organizational unit (부서) CN: Common Name (이름) 예 C=KR, O=중부대학교, OU=정보보호학과, CN=이병천

3.2 BouncyCastle 패키지 JCE는 인증서를 생성하는 방법을 제공하지 않는다. org.bouncycastle.x509.X509V3CertificateGenerator 엔진 제 공 http://www.bouncycastle.org/download/bcprov-jdk15on-149.jar 파일을 다운로드하여 Add External JARs로 등록하여 사용

인증기관 인증서 X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis())); certGen.setIssuerDN(new X500Principal("C=KR,CN=Root")); certGen.setSubjectDN(new X500Principal("C=KR,CN=Root")); GregorianCalendar currentDate = new GregorianCalendar(); GregorianCalendar expiredDate = new GregorianCalendar(currentDate.get(Calendar.YEAR)+1, currentDate.get(Calendar.MONTH), currentDate.get(Calendar.DAY_OF_MONTH)); certGen.setNotBefore(currentDate.getTime()); certGen.setNotAfter(expiredDate.getTime()); certGen.setPublicKey(pubKey); certGen.setSignatureAlgorithm("SHA1withRSAEncryption"); certGen.addExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(0)); certGen.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign)); X509Certificate rootCert = (X509Certificate)certGen.generate(signatureKey,"BC");

일반 사용자 인증서 X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); … certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(caCert)); certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(pubKey)); certGen.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment)); X509Certificate aliceCert = (X509Certificate)certGen.generate(signatureKey,"BC");

인증서 검증 인증서의 서명 확인 인증서의 유효기간 확인 인증서의 사용 용도 확인 인증서의 폐지 여부 확인 void verify(PublicKey key) 문제가 있으면 각 종 예외 발생 인증서의 유효기간 확인 void checkValidity() 인증서의 사용 용도 확인 인증서의 폐지 여부 확인

인증서 저장 인증서 저장 저장된 인증서 불러오기 java.security.cert.CertificateFactory 엔진 이용 FileOutputStream fos = new FileOutputStream(new File("aliceCert.der")); fos.write(aliceCert.getEncoded()); fos.close(); CertificateFactory cf = CertificateFactory.getInstance("X.509"); FileInputStream fis = new FileInputStream(new File("aliceCert.der")); X509Certificate cert = (X509Certificate)cf.generateCertificate(fis); fis.close();

개인키 저장 java.security.KeyStore 엔진 사용 KeyStore는 패스워드를 이용하여 저장할 키를 보호함 개인키를 저장할 경우에는 인증경로를 제공해야 함 인증경로 배열은 계층구조 트리에서 아래부터 위쪽으로 만듬 개인키를 식별하기 위한 정보 Alias 정보 이용 “AlicePrivateKeyAlias” char[] code = {'s','e','c','r','e','t','c','o','d','e'}; KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(null,null); X509Certificate[] chain = new X509Certificate[3]; chain[0] = aliceCert; chain[0] = interCert; chain[1] = rootCert; ks.setKeyEntry("AlicePrivateKeyAlias",alicePrivKey,code,chain); FileOutputStream fos = new FileOutputStream(new File("alicePriv.key")); ks.store(fos,code); fos.close();

인증서 폐지 목록

인증서 폐지 목록 BouncyCastle org.bouncycastle.x509.X509V2CRLGenerator 엔진 이용 X509V2CRLGenerator crlGen = new X509V2CRLGenerator(); crlGen.setIssuerDN(caCert.getSubjectX500Principal()); GregorianCalendar currentDate = new GregorianCalendar(); GregorianCalendar nextDate = new GregorianCalendar(currentDate.get(Calendar.YEAR)+1, (currentDate.get(Calendar.MONTH)+1)%12, currentDate.get(Calendar.DAY_OF_MONTH)); crlGen.setThisUpdate(currentDate.getTime()); crlGen.setNextUpdate(nextDate.getTime()); crlGen.setSignatureAlgorithm("SHA1withRSAEncryption"); crlGen.addCRLEntry(revokeCert.getSerialNumber(), currentDate.getTime(), CRLReason.superseded); X509CRL crl = crlGen.generate(signatureKey,"BC");

인증서 폐지 목록 인증서 폐지 사유

인증서 폐지 여부 확인 crl이 Bob의 인증서가 폐지될 경우에 이 정보를 유지하는 crl이라 하자. getRevokedCertificate() 메소드를 호출하여 이 값이 null이 면 해당 인증서는 폐지되지 않았다는 것을 의미한다. 폐지된 경우 getCertificateIssuer() 메소드를 통해 폐지된 인증서의 발급자 정보 를 획득할 수 있다. 이 때 이 값이 null이면 CRL 발급자가 인증서의 발급자라는 것을 나타낸다. X509Entry entry = crl.getRevokedCertificate(bobCert.getSerialNumber()); if(entry!=null){ System.out.printf("인증서번호: %d%n", entry.getSerialNumber()); if(entry.getCertificateIssuer()==null) System.out.printf("발급자: %s%n", crl.getIssuerX500Principal()); else System.out.printf("발급자: %s%n", entry.getCertificateIssuer()); }

인증서 폐지 목록의 저장 및 활용 CRL 저장 저장된 CRL 불러오기 FileOutputStream fos = new FileOutputStream(new File("normal.crl")); fos.write(crl.getEncoded()); fos.close(); CertificateFactory cf = CertificateFactory.getInstance("X.509"); FileInputStream fis = new FileInputStream(new File(“normal.crl")); X509CRL crl = (X509CRL)cf.generateCRL(fis); fis.close();

인증서 디렉토리 java.security.cert.CertStore를 이용하여 생성할 수 있음 List list = new ArrayList(); list.add(rootCert); list.add(interCert); list.add(aliceCert); list.add(bobCert); list.add(rootCRL); list.add(interCRL); CollectionCertStoreParameters params = new CollectionCertStoreParameters(list); CertStore store = CertStore.getInstance("Collection",params);

인증 경로 java.security.cert.CertPath를 이용하여 인증경로 생성 java.security.CertPathValidator를 이용하여 인증 경로 를 유효성을 검증 CertificateFactory cf = CertificateFactory.getInstance("X.509"); List<Certificate> certChain = new ArrayList(); certChain.add(bobCert); certChain.add(interCert); CertPath certPath = cf.generateCertPath(certChain); Set trust = Collections.singleton(new TrustAnchor(rootCert,null)); CertPathValidator validator = CertPathValidator.getInstance("PKIX","BC"); PKIXParameters param = new PKIXParameters(trust); param.addCertStore(store); param.setDate(new Date()); try{ PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)validator.validate(certPath,param); } catch(CertPathValidatorException e){ System.out.println("validation failed "+e.getIndex()+" detail: "+e.getMessage());