자바 암호 프로그래밍 Java Cryptography Programming 2017. 3. 중부대학교 정보보호학과 이병천 교수
차례 1. 강의 개요 2. 암호와 정보보호 3. 자바프로그래밍 기초 4. 자바 네트워크 프로그래밍 5. JCA/JCE 암호 프로그래밍 6. 해쉬함수, MAC, 패스워드 기반 키생성 7. 대칭키 암호, 파일 암호화/복호화 8. 공개키 암호 9. 전자서명 10. 인증서와 공개키기반구조(PKI) 11. 암호 알고리즘/프로토콜 구현
5. JCA/JCE 프로그래밍
1. JCA/JCE 소개 자바에서의 암호 구현 패키지 JCA(Java Cryptography Architecture) Import java.security.* 미국의 수출규제를 통과할 수 있는 내용으로 구현 암호화 처리를 위한 표준 구조, 인터페이스, 팩토리 등을 정의 JCE(Java Cryptography Extension) Import javax.crypto.* JCA에서 부족한 내용을 보충하여 별도로 구현 암/복호화, 키 생성, 키 교환, MAC 등 실질적인 암호화 처리 기능을 제공 JCA와 JCE는 프로그래머들이 응용을 개발할 때 사용할 수 있는 암호프로그래밍의 추상 계층(abstraction layer)을 제공
JCA의 설계 원칙 구현 독립성 (Implementation Independence) 프로그래머는 알고리즘을 구현한 제공자가 누구인지 알 필요가 없이 동일한 API를 이용하여 암호화 서비스 이용 가능 구현 호환성 (Implementation Interoperability) 프로그래머가 서로 다른 프로바이더(provider)에 의해 제공되는 구현을 사용하더라도 상호 동작해야 함 알고리즘 확장성 (Algorithm Extensibility) 제공되지 않는 알고리즘은 쉽게 추가하여 동일한 API로 사용할 수 있어야 함
JCA와 프로바이더 JCA는 프로바이더 기반 체계 모든 프로바이더는 java.secirty.Provider 클래스의 구현체로, CSP (Cryptographic Service Provider)라고 부름 사용자가 특정 알고리즘의 인스턴스를 요청하면 JCA는 프로바이 더 저장소에서 해당 알고리즘에 적합한 구현체를 찾아 인스턴스 를 생성 동일한 알고리즘이 여러 프로바이더에 정의되어 있으면 저장소 의 선호 순서를 따름 명시적으로 특정 프로바이더에 인스턴스를 요청할 수도 있음
JCA와 프로바이더 MessageDigest md = MessageDigest.getInstance("MD5"); JCA는 등록된 CSP를 순차적으로 검색하여 MD5 알고리즘이 있는 프로바이더를 찾은 다음, 해당 프로바이더를 사용해서 메시지 다이제스트 인스턴스를 생성
JCA와 프로바이더 MessageDigest md = MessageDigest.getInstance("MD5", "ProviderC"); 특정 프로바이더를 명시
프로바이더 목록 Java.security 파일에 프로바이더 목록 존재 # # List of providers and their preference orders (see above): security.provider.1=sun.security.provider.Sun security.provider.2=sun.security.rsa.SunRsaSign security.provider.3=sun.security.ec.SunEC security.provider.4=com.sun.net.ssl.internal.ssl.Provider security.provider.5=com.sun.crypto.provider.SunJCE security.provider.6=sun.security.jgss.SunProvider security.provider.7=com.sun.security.sasl.Provider security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI security.provider.9=sun.security.smartcardio.SunPCSC security.provider.10=sun.security.mscapi.SunMSCAPI
프로바이더 추가하기 자바 실행환경에 추가하는 방법 어플리케이션 실행시 추가하는 방법 Java.security 파일에 프로바이더 추가 모든 어플리케이션 개발에 기본 사용 가능 어플리케이션 실행시 추가하는 방법 소스코드에서 프로바이더를 추가 추가한 프로바이더는 해당 어플리케이션에서만 사용 가능 외부 JAR 파일을 사용하도록 설정하는 방법
Bouncy Castle 프로바이더 등록하기 http://www.bouncycastle.org/example.html bcprov-jdk15on-156.jar 파일 다운로드하여 자바 실행 환경의 확 장 라이브러리 디렉터리에 복사 <JAVA_HOME>/jre/lib/ext <JRE_HOME>/lib/ext java.security 파일에 Bouncy Castle 프로바이더 등록 security.provider.N=org.bouncycastle.jce.provider.BouncyCastleP rovider 권한 문제로 Java.security 파일을 수정하기가 쉽지 않음
Bouncy Castle 프로바이더 사용하기 http://www.bouncycastle.org/example.html bcprov-jdk15on-156.jar 파일 다운로드하여 현재의 프로젝트 폴 더 등 편리한 곳에 저장 현재 프로젝트에서 위의 jar 파일을 사용하도록 설정 이클립스에서 외부 JAR 파일 추가하기 프로젝트폴더->오른쪽마우스->속성(Properties)->Java Build Path->Libraries->Add External JARs->다운로드 받은 jar파일 선 택->OK
알고리즘의 독립성 같은 종류의 여러 알고리즘을 동일한 메소드를 이용하여 암 호연산을 수행할 수 있음. 이를 위해 다음과 같이 암호연산을 분류한다. 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. 의사난수(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();
의사난수 생성 import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; public class SecureRandomGen { public static void main(String[] args) { try{ SecureRandom csprng = SecureRandom.getInstance("SHA1PRNG"); System.out.println("사용된 알고리즘: "+csprng.getAlgorithm()); boolean randBool = csprng.nextBoolean(); System.out.println("T/F 난수 출력: "+randBool); int randInt = csprng.nextInt(); System.out.println("정수 난수 출력: "+randInt); byte[] randBytes = new byte[8]; csprng.nextBytes(randBytes); System.out.print("바이트 난수 출력: "); for(byte b: randBytes) System.out.printf("%02X ", b); } catch(NoSuchAlgorithmException e){ e.printStackTrace(); 출력 사례 사용된 알고리즘: SHA1PRNG T/F 난수 출력: true 정수 난수 출력: 667469724 바이트 난수 출력: 30 FE D9 28 1C 55 82 BA