470 likes | 665 Views
6. Authentication. 데이타베이스 실험실 김희수 , 백주현. Contents. Message Digests MACs Signatures Certificates. Introduction. Authentication 신원을 증명하는 과정 사례 자동 현금 인출기 신용 카드 비디오 숍 Cryptographic concepts Message digests Digital signatures Certificates. Message Digest (1/6).
E N D
6. Authentication 데이타베이스 실험실 김희수, 백주현
Contents • Message Digests • MACs • Signatures • Certificates
Introduction • Authentication • 신원을 증명하는 과정 • 사례 • 자동 현금 인출기 • 신용 카드 • 비디오 숍 • Cryptographic concepts • Message digests • Digital signatures • Certificates
Message Digest (1/6) • 입력 데이타가 일방향 함수를 통해서 축약된 데이타 • Getting • public static MessageDigest getInstance(String algorithm) throws NoSuchAlgorithmException • public static MessageDigest getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException • Feeding • public void update(byte input) • public void update(byte[] input) • public void update(byte[] input, int offset, int len)
Message Digest (2/6) • Digesting • public byte[] digest( ) • public byte[] digest(byte[] input) • public void reset( ) • One, Two, Three! // Define byte[] inputData first. MessageDigest md = MessageDigest.getInstance(“SHA”) ; md.update(inputData) ; byte[] digest = md.digest( ) ;
Message Digest (3/6) • Digest Streams // Obtain a message digest object. MessageDigest md = MessageDigest.getInstance(“MD5”) ; // Calculate the digest for the given file. FileInputStream in = new FileInputStream(args[0]) ; byte[ ] buffer = new byte[8192] ; int length; while (( length = in.read(buffer)) != -1) md.update(buffer, 0 , length) ; byte[ ] raw = md.digest( ) ;
Message Digest (4/6) // Obtain a message digest object. MessageDigest md = MessageDigest.getInstance(“MD5”) ; // Calculate the digest for the given file. DigestInputStream in = new DigestInputStream(new FileInputStream(args[0], md) ; byte[ ] buffer = new byte[8192]; while (in.read(buffer) != -1) ; byte[ ] raw = md.digest( ) ;
Client Network name random number timestamp digest algorithm password Message Digest (5/6) • Protected Password Login • 클라이언트 • message digest 생성 및 전송 • 서버 • message digest 검증
import Protection ; public class ProtectedClient { public void sendAuthentication(String user, String password, OutputStream outStream) throws IOException, NoSuchAlgorithmException { DataOutputStream out = new DataoutputStream(outStream) ; long t1 = (new Date( ) ). getTime( ) ; double q1 = Math.random ( ) ; byte[ ] protected1 = Protection.makeDigest(user, password, t1, q1) ; out.writeUTF(user) ; out.writeLong(t1) ; out.writeDouble(q1) ; out.writeInt(protected1.length) ; out.write(protected1) ; out.flush( ) ; } // 클라이언트 프로그램 //
public static void main(String[ ] args) throws Exception { String host = args[0] ; int port = 7999 ; String user = “Jonathan” ; String password = “buendia” ; Socket s = new Socket(host, port) ; ProtectedClient client = new ProtectedClient( ) ; Client.sendAuthentication(user, password, s.getOutputStream( ) ) ; s.close( ) ; } }
public class Protection { public static byte[ ] makeDigest (String user, String password, long t1, double q1) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance(“SHA”) ; md.update(user.getBytes( ) ) ; md.update(password.getBytes( ) ) ; md.update(makeBytes ( t1, q1 ) ) ; return md.digest ( ) ; } public static byte[ ] makeBytes (long t, double q ) { try { ByteArrayOutputStream byteOut = new ByteArrayOutputStream( ) ; DataOutputStream dataOut = new DataOutputStream(byteOut) ; dataOut.writeLong ( t ) ; dataOut.writeDouble ( q ) ; return byteOut.toByteArray ( ) ; } catch (IOException e ) { return new byte [0] ; } } } // Protection 클래스 //
import Protection ; public class ProtectedServer { public boolean authenticate(InputStream inStream) throws IOException, NoSuchAlgorithmException { DataInputStream in = new DataInputStream(inStream) ; String user = in.readUTF ( ) ; long t1 = in.readLong ( ) ; double q1 = in.readDouble ( ) ; int length = in.readInt ( ) ; byte[ ] protected1 = new byte[length] ; in.readFully(protected1) ; String password = lookupPassword(user) ; byte[ ] local =Protection.makeDigest(user, password, t1, q1) ; return MessageDigest.isEqual(protected1, local) ; } // 서버 프로그램 //
protected String lookupPassword(String user) { return “buendia” ; } public static void main(String[ ] args ) throws Exception { int port = 7999 ; ServerSocket s = new ServerSocket( port ) ; Socket client = s.accept ( ) ; ProtectedServer server = new ProtectedServer ( ) ; if (server.authenticate (client.getInputStream ( ) ) ) System.out.println(“Client logged in. ”) ; else System.out.println(“Client failed to log in. ”) ; s.close ( ) ; } }
Network digest algorithm digest algorithm Message Digest (6/6) • Double-Strength Password Login Client name random number timestamp password random number 2 timestamp 2
public void sendAuthentication(String user, String password, OutputStream outStream) throws IOException, NoSuchAlgorithmException { DataOutputStream out = new DataoutputStream(outStream) ; long t1 = (new Date( ) ). getTime( ) ; double q1 = Math.random ( ) ; byte[ ] protected1 = Protection.makeDigest(user, password, t1, q1) ; long t2 = (new Date( ) ).getTime( ) ; double q2 = Math.random( ) ; byte[ ] protected2 = protection.makeDigest(protected1, t2, q2) ; out.writeUTF(user) ; out.writeLong(t1) ; out.writeDouble(q1) ; out.writeLong(t2) ; out.writeDouble(q2) ; out.writeInt(protected2.length) ; out.write(protected2) ; out.flush( ) ; } // 추가된 클라이언트 프로그램 //
public static byte[ ] makeDigest (byte[ ] mush, long t2, double q2) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance (“SHA” ) ; md.update(mush) ; md.update(makeBytes ( t2, q2 ) ) ; return md.digest ( ) ; } // 추가된 Protection 클래스 //
public boolean authenticate(InputStream inStream) throws IOException, NoSuchAlgorithmException { DataInputStream in = new DataInputStream(inStream) ; String user = in.readUTF ( ) ; long t1 = in.readLong ( ) ; double q1 = in.readDouble ( ) ; long t2 = in.readLong( ) ; double q2 = in.readDouble( ) ; int length = in.readInt ( ) ; byte[ ] protected2 = new byte[length] ; in.readFully(protected2) ; String password = lookupPassword(user) ; byte[ ] local1 = Protection.makeDigest(user, password, t1, q1) ; byte[ ] local2 = Protection.makeDigest(local1, t2, q2 ) ; return MessageDigest.isEqual(protected2, local2) ; } // 추가된 서버 프로그램 //
MACs(1/3) • 입력 데이타와 키를 기반으로 짧은 요약 값 생성 • Setting Up • public static final Mac getInstance(String algorithm) throws NoSuchAlgorithmException • public static final Mac getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException • public final void init(Key key) throws InvalidKeyException • public final void init(Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException
MACs (2/3) • Feeding • public final void update(byte input) throws IllegalStateException • public final void update(byte[ ] input) throws IllegalStateException • public final void update(byte[ ] input, int offset, int len) throws IllegalStateException • Calculating the Code • public final byte[ ] doFinal( ) throws IllegalStateException • public final void doFinal(byte[ ] output, int outOffset) throws IllegalStateException, ShortBufferException • public final byte[ ] doFinal(byte[ ] input) throws IllegalStateException • public final void reset( )
MACs (3/3) • For Instance SecureRandom sr = new SecureRandom( ) ; byte[ ] keyBytes = new byte[20] ; sr.nextBytes(keyBytes) ; SecretKey key = new SecretKeySpec(keyBytes, “HmacSHA1”) ; Mac m = Mac.getInstance(“HmacSHA1”) ; m.init(key) ; m.update(inputData) ; byte[ ] mac = m.doFinal( ) ;
Hash Functions • Converts a string of data of any size into a fixed-length hash • One-way funtion • Chances of any two strings of data hashing to the same value very, very small
MD5 SHA 다이제스트 길이 128 bits 160 bits 처리의 기본 단위 512 bits 512 bits 단계 수 64(16번의 4라운드) 80 최대 메시지 크기 ∞ 2 64 bits 기약 논리 함수 4 3 덧셈 상수 64 4 Hash Algorithms • MD5와 SHA의 비교
Signatures (1/6) • 정의 • 서명할 사람의 private key를 가지고 암호한 message digest • Authentication, Integrity 보장 • Java Security API • java.security.Signature • 연산 • Generating a Signature • Verifying a Signature
Signatures (2/6) • Generating a Signature 1. Signature 객체 생성 public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException public static Signature getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException 2. Signature 객체 초기화 public final void initSign(PrivateKey privateKey) throws InvalidKeyException 3. Signature 객체에 message의 데이타 추가 public final void update(byte input) throws SignatureException public final void update(byte[] input) throws SignatureException public final void update(byte[] input, int offset, int len) throws SignatureException 4.Signature 계산 public final byte[] sign() throws SignatureException
Signatures (3/6) • Verifying a Signature 1. Signature 객체 생성 2. Signature 객체 초기화 public final void initVerify(PublicKey publicKey) throws InvalidKeyException 3. Signature 객체에 message의 데이타 추가 4.Signature 검증 public final boolean verify(byte[] signature) throws SignatureException • Signature에 명세된 알고리즘 파라메타를 초기화 • public final void setParameter(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException
Signatures (4/6) • Hancock • Signature 생성 및 검증하는 프로그램 • 명령 라인 java Hancock -s|-v keystore storepass alias messagefile signaturefile -s : 서명, -v : 검증, keystore : keystore 파일, storepass : keystore에 접근하기 위한 비밀번호 alias : key를 검색하기 위한 별명, messagefile : 데이타 저장 파일 signaturefile : 서명한 signature 저장 화일 • 하나의 key pair 필요 • keytool 사용 (5장) • keystore 클래스 사용 (5장)
import java.io.* ; import java.security.* ; public class Hancock { public static void main ( String[ ] args) throws Exception { if (args.length != 6) { System.out.println ( “Usage : Hancock -s|-v keystore storepass alias messagefile signaturefile” ) ; return ; } String options = args[0] ; String keystorefile = args[1] ; String storepass = args[2] ; String alias = args[3] ; String messagefile = args[4] ; String signaturefile = args[5] ; Signature signature = Signature.getInstance(“DSA” ) ; KeyStore keystore = KeyStore.getInstance( ) ; keystore.load(new FileInputStream(keystroefile), storepass) ; // Hancock 프로그램 //
If (options.indexOf(“s”) != -1) signature.initSign(keystore.getPrivateKey(alias, storepass) ) ; else signature.initVerify(keystore.getCertificate(alias).getPublicKey( ) ) ; FileInputStream in = new FileInputStream(messagefile) ; byte[ ] buffer = new byte[8192] ; int length ; while (( length = in.read(buffer)) != -1 ) signature.update(buffer, 0, length) ; in.close ( ) ; if (options.indexOf(“s”) != -1) { FileOutputStream out = new FileOutputStream(signaturefile) ; byte[ ] raw = signature.sign( ) out.write(raw) ; out.close ( ) ; } else { FileInputStream sigIn = new FileInputStream(signaturef ile) ; byte[ ] raw = new byte[sigIn.available( ) ] ; sigIn.read(raw) ; sigIn.close( ) ; if ( signature.verify(raw) ) System.out.println(“The signature is good.”) ; else System.out.println(“The signature is bad.” ) ; } } }
Signatures (5/6) • Login, Again • 클라이언트 • Private key를 가지고 Signature 생성 및 전송 • 명령 라인 java StrongClient localhost c:\windows\.keystore buendia Jonathan • 서버 • Public key를 가지고 Signature를 검증 • 명령 라인 java StrongServer c:\windows\.keystore buendia
// 클라이언트 프로그램 // import Protection ; public class StrongClient { public void sendAuthentication(String user, PrivateKey key, OutputStream outStream) throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException { DataOutputStream out = new DataOutputStream(outStream) ; long t = (new Date( ) ).getTime( ) ; double q = Math.random( ) ; Signature s = Signature.getInstance(“DSA”) ; s.initSign(key) ; s.update(Protection.makeBytes(t, q) ) ; byte[ ] signature = s.sign( ) ; out.writeUTF(user) ; out.writeLong(t ) ; out.writeDouble(q) ; out.writeInt(signature.length) ; out.write(signature) ; out.flush( ) ; }
public static void main(String[ ] args) throws Exception { if (args.length != 5 ) { System.out.println ( “Usage : StrongClient host keystore storepass alias keypass”) ; return ; } String host = args[0] ; String keystorefile = args[1] ; String storepass = args[2] ; String alias = args[3] ; String keypass = args[4] ; int port = 7999 ; Socket s = new Socket(host, port) ; StrongClient client = new StrongClient( ) ; keystore.load(new FileInputStream(keystorefile), storepass) ; PrivateKey key = keystore.getPrivateKey(alias, keypass) ; client.sendAuthentication(alias, key, s.getOutputStream( ) ) ; s.close ( ) ; } }
// 서버 프로그램 // import Protection ; public class StrongServer { protected KeyStore mKeyStore ; public StrongServer(KeyStore keystore) {mKeyStore = keystore ; } public boolean authenticate(InputStream inStream) throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException { DataInputStream in = new DataInputStream(inStream) ; String user = in.readUTF( ) ; long t = in.readLong( ) ; double q = in.readDouble( ) ; int length = in.readInt( ) ; byte[ ] signature = new byte[length] ; in.readFully(signature) ; Signature s = Signature.getInstacne(“DSA”) ; s.initVerify(mKeyStore.getCertificate(user).getPublicKey( )) ; s.update(Protection.makeBytes(t,q ) ) ; return s.verify(signature) ; }
public static void main(String[ ] args) throws Exception { if (args.length != 2) { System.out.println(“Usage : StrongServer keystore storepass” ) ; return ; } String keystorefile = args[0] ; String storepass = args[1] ; int port = 7999 ; ServerSocket s = new ServerSocket(port) ; Socket client = s.accept( ) ; KeyStore keystore = KeyStore.getInstance( ) ; StrongServer server = new StrongServer(keystore) ; if (server.authenticate(client.getInputStream ( ) ) ) System.out.println(“Client logged in.” ) ; else System.out.println(“Client failed to log in.”) ; s.close( ) ; } }
Signatures (6/6) • SignedObject • JDK 1.2 • java.security.SignedObject • Serializable 객체와 매칭하는 signature를 포함 • 생성 • public SignedObject(Serializable object, PrivateKey signingKey, Signature signingEngine) throws IOException, SignatureException • 검증 • public final boolean verify(PublicKey verificationKey, Signature verificationEngine) throws InvalidKeyException, SignatureException • 검색 • public Object getObject() throws IOException, ClassNotFoundException
Certificates (1/9) • 정의 • 한 사람이 서명한 문장으로 다른 사람의 public key를 가지고 있음 • 사례 • 정부가 발생한 허가증 • 운전 면허증 • 주민등록증 • Certificate Authority (CA) • Certificate를 발생한 기관 및 사람
Certificates (2/9) • Certificate의 내용 • subject 정보 • subject의 public key • issuer 정보 • issuer의 signature
Certificates (3/9) • JDK 1.1 • Certificate 지원이 미흡했음 • java.security.Certificate interface 소개 • JDK 1.2 • java.security.cert.Certificate abstract class 소개 • public abstract PublicKey getPublicKey() • public abstract byte[] getEncoded() throws CertificateEncodingException • X.509v3 Certificates를 사용할 수 있음 • Certificate Revocation Lists(CRLs)
Certificates (4/9) • Generating a Certificate • X509Certificate 클래스 • getInstance() 함수를 사용하여 X.509 certificate를 로드 함 • JDK 1.1, JDK 1.2 혼동 주의 • Verifying a Certificate • public abstract void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException • public abstract void verify(PublicKey key, String sigProvider) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException
Certificates (5/9) • X.509 • International Telecommunications Union(ITU)에서 발표 • java.security.cert.X509Certificate 클래스 • 화일로부터 X.509 certificate 로드 • public static final X509Certificate getInstance(InputStream inStream) throws CertificateException • public static final X509Certificate getInstance(byte[] certData) throws CertificateException • java.security properties file에 다음 라인이 default로 설정 • cert.provider.x509=sun.security.X509CertImpl • DER-encoded certificate로부터 X509CertImpl 생성 (DER; Distinguished Encoding Rules)
Certificates (6/9) • X.509 Certificate 내용
Certificates (7/9) • Spill • RFC 1421 certificate representation • base64로 변환된 DER representation • header/footer line으로 구분 • 수행 작업 1. header/footer를 제거 => body 부부만 바이트 배열로 변환 (oreilly.jonathan.util.Base64 클래스 사용, 부록 B) 2. X509Certificate를 생성하기 위해 변환한 바이트 배열을 사용 (certificate에 대한 정보를 출력) 3. certificate fingerprints를 계산하여 출력
// Spill 프로그램 // import oreilly.jonathan.util.Base64 ; public class Spill { public static void main(String[ ] args) throws Exception { if (args.length != 1) { System.out.println(“Usage : Spill file” ) ; return ; } BufferedReader in = new BufferedReader(new FileReader(args[0] )) ; String begin = in.readLine( ) ; if (begin.equals(“-----BEGIN CERTIFICATE-----”) == false) throws new IOException(“Couldn’t find certificate beginning”) ; String base64 = new String( ) ; boolean trucking = true ; while (trucking) { String line = in.readLine ( ) ; if (line.startsWith(“-----”) ) trucking = false ; else base64 += line ; } in.close ( ) ; byte[ ] certificateData = Base64.decode(base64) ;
X509Certificate c = X509Certificate.getInstance(certificateData) ; System.out.println(“Subject: “ + c.getSubjectDN( ). getName( ) ) ; System.out.println(“Issuer : “ + c.getIssuerDN( ).getName( ) ) ; System.out.println(“Serial number: “ + c.getSerialNumber( ). toString(16) ); System.out.println(“Valid from “ + c.getNotBefore( ) + “ to ” + c.getNotAfter( ) ) ; System.out.println(“Fingerprints: ” ) ; doFingerprint(certificateData, “MD5” ) ; doFingerprint(certificateData, “SHA” ) ; } protected static void doFingerprint(byte[ ] certificateBytes, String algorithm) throws Exception { System.out.print(“ ” + algorithm + “ : ”) ; MessageDigest md = MessageDigest.getInstance(algorithm) ; md.update(certificateBytes) ; byte[ ] digest = md.digest( ) ; for (int i = 0; i < digest.length; i++) { if ( i != 0 ) System.out.print(“ : ”) ; int b = digest[i] & 0xff ; String hex = Integer.toHexString(b) ; if (hex.length( ) == 1) System.out.print( “0”) ; System.out.print(hex) ; } System.out.println( ) ; } }
// Spill 실행 결과 // C:\ java Spill ca1.x509 Subject: T=“+42 38 7747 361”, OID.1.2.840.113549.1.9.1=dostalek@pvt.net, CN=Libor Dostalek, OU=VCU, O=“PVT,a.s.”, L=Ceske Budejovice, S=2, C=CZ Issuer : OID.1.2.840.113549.1.9.1=ca-oper@p70x03.brn.pvt.cz, CN=CA-PVT1, O=PVT a.s., C=CZ Serial number: 2d Valid from Mon Aug 04 01:04:56 EDT 1997 to Tue Feb 03 00:04:56 EST 1998 Fingerprints: MD5: d9:6f:56:3e:e0:ec:35:70:94:bb:df:05:75:d6:32:0e SHA: db:be:df:e5:ff:ec:f9:53:98:dc:88:dd:6b:ba:cf:2e:2a:68:0c:44 C:\ keytool -printcert -file ca1.x509 Owner: T=“+42 38 7747 361”, OID.1.2.840.113549.1.9.1=dostalek@pvt.net, CN=Libor Dostalek, OU=VCU, O=“PVT,a.s.”, L=Ceske Budejovice, S=2, C=CZ Issuer : OID.1.2.840.113549.1.9.1=ca-oper@p70x03.brn.pvt.cz, CN=CA-PVT1, O=PVT a.s., C=CZ Serial number: 2d Valid from: Mon Aug 04 01:04:56 EDT 1997 to Tue Feb 03 00:04:56 EST 1998 Fingerprints: MD5: d9:6f:56:3e:e0:ec:35:70:94:bb:df:05:75:d6:32:0e SHA: db:be:df:e5:ff:ec:f9:53:98:dc:88:dd:6b:ba:cf:2e:2a:68:0c:44
Certificates (8/9) • Certificate Revocation Lists (CRL) • 더 이상 효력이 없는 certificate 리스트 • CRL을 발행하는 방법의 표준이 없음 • JDK 1.2. • X.509 표준의 CRL을 사용 • java.security.cert.X509CRL 클래스 사용 • java.security.cert.RevokedCertificate 클래스 사용
Certificates (9/9) • java.security.cert.X509CRL • 생성 • public static final X509CRL getInstance(InputStream inStream) throws CRLException, X509ExtensionException • public static final X509CRL getInstance(byte[] crlData) throws CRLException, X509ExtensionException • X509Certificate 클래스와 유사 • certificate의 무효화 여부 확인 • public abstract boolean isRevoked(BigInteger serialNumber) • java.security.cert.RevokedCertificate • public abstract RevokedCertificate getRevokedCertificate(BigInteger serialNumber) throws CRLException • public abstract Set getRevokedCertificate()