SSISO Community

시소당

자바보안과 암호화


Chapter  1  개념


■  환경  설정

개발  환경  설정에는  다음과  같이  3가지  방법이  있다.

  

1.  JSDK  1.3이하  버젼  &  JCE  1.2.1  글로벌  버전  JCE  1.2.1  버전은  http://java.sun.com  사이트에서  회원가입을  해야지  Down  받을수  있다.  JCE는  미국에서  무기로  관주  되기  때문에  글로벌  버전은  미국,  케나다  버전과  다르다.

2.  JSDK  1.4에는  Java  Cryptography  Extension  1.2.1  버전이  포함되어  있다.

3.  다운  받은  JCE의  압축을  풀고  lib방  밑에  있는  모든  jar파일을[JavaHome]\jre\lib\ext방으로  카피한다.  그리고  JCE  알고리즘을  사용하기  위해서  SunJCE  프로바이터를  설치  해야  한다.

    설치하기  위해서는  [JavaHome]\jre\lib\security\java.security  파일에  다음을  추가한다.

  

security.provider.1=sun.security.provider.Sun,

security.provider.2=com.sun.crypto.provider.SunJCE  

  

■  서로  다른  개념들

1.  보안  !=  암호  :  애플리케이션에  암호를  추가하는  것이  애플리케이션을  안전하게  하지  못한다.

2.  올바른  보안  모델  !=  버그가  없는  구현  :  훌륭한  보안  모델이라고  해도  구현  과정에서의  버그는  공겨자의  대상이  될  수  있다.

3.  테스트  !=  공식적인  증명

4.  컴포넌트  보안  !=  전반적인  시스템  보안

5.  자바  보안  !=  애플릿  통제

  

Base  64

Base64는  바이트  배열을  아스키  문자로  표현하기  위한  시스템이다.  Base64체계는  RFC1521의  Section5.2에  완전하게  기술되어  있다.  sun.misc.BASE64Encoder는  바이트  배열을  가지고  base64  disit를  가지  문자열을  생성한다.  이에  대응하는  클래스  BASE64Decoder는  문자열을  가지고  원래  바이트  배열을  생성한다.

Sun에서는  Base64를  지원할  의무가  없다.

  

  

■  예제  프로그램

  

//--  Masher  메시지  축약

package  test.crypto.part1;

import  java.security.*;

import  java.io.*;

import  sun.misc.*;

  

  

public  class  Masher    {

        public  Masher()  {

        }

  

        private  void  exec(String  targetFileName)  {

  

                try  {

                        //  MD5알고리즘을  이용한  메시지  축약  객체를  생성한다.

                        MessageDigest  md  =  MessageDigest.getInstance("MD5");

                        FileInputStream  fin  =  new  FileInputStream(targetFileName);

                        byte[]  buffer  =  new  byte[8192];

                        int  length;

                        while  (  (length  =  fin.read(buffer))  !=  -1  )  {

                                md.update(buffer,0,length);

                        }

                        byte[]  raw  =  md.digest();

  

                        //  출력  가능한  문자열로  변환한다.

                        BASE64Encoder  encoder  =  new  BASE64Encoder();

                        String  base64  =  encoder.encode(raw);

                        System.out.println(base64);

                }  catch(NoSuchAlgorithmException  nalgoe)  {

                        System.err.println(nalgoe);

                }  catch(FileNotFoundException  fnote)  {

                        System.err.println(fnote);

                }  catch(IOException  ioe)  {

                        System.err.println(ioe);

                }

        }

  

        public  static  void  main(String[]  args)  {

                if(args.length  <  1)  {

                        System.out.println("메시지  축약의  대상  파일을  선택하여  주십시요");

                        System.exit(0);

                }

                String  targetFileName  =    args[0];

                Masher  masher  =  new  Masher();

                masher.exec(targetFileName);

        }

}

  

매시지  축약은  데이터를  증명하지만,  메시지에  대해서는  전혀  알  수  없다.

  

  

//  DES알고리즘을  이용한  대칭키  암복호화

package  test.crypto.part1;

  

import  javax.crypto.*;

import  java.io.*;

  

import  java.security.*;

import  sun.misc.*;

  

public  class  SecretWriting    {

        public  SecretWriting()  {

        }

  

        public  void  exec(String  args[])  throws  Exception{

                //  key를  얻어  생성한다.

                Key  key;

                try{

                        ObjectInputStream  in  =  new  ObjectInputStream(new  FileInputStream("SecretKey.ser"));

                        key  =  (Key)in.readObject();

                        in.close();

                }  catch  (FileNotFoundException  fnote)  {

                        //  ser  Key  파일이  없으면  실행된다.

                        //  DES  대칭키  알고리즘을  정의해서  키  제너레이터를  생성한다.

                        KeyGenerator  keygenerator  =  KeyGenerator.getInstance("DES");

                        //  랜덤  함수로  초기화한다.

                        keygenerator.init(new  SecureRandom());

                        //  키를  생성한다.

                        key  =  keygenerator.generateKey();

                        //  생성된  키  객체를  바이널리  파일로  저장한다.

                        ObjectOutputStream  out  =  new  ObjectOutputStream(new  FileOutputStream("SecretKey.ser"));

                        out.writeObject(key);

                        out.close();

                }

                Cipher  cipher  =  Cipher.getInstance("DES/ECB/PKCS5Padding");

  

                //  -e문자열이  없으면  복호화  한다.  다음은  암호화  한다.

                if(args[0].indexOf("e")  !=  -1)  {

                        cipher.init(Cipher.ENCRYPT_MODE,key);

                        String  amalgam  =  args[1];

                        for(int  i  =  2;  i  <  args.length;  i++)  {

                                amalgam  +=  "  "+args[i];

                        }

                        byte[]  stringBytes  =  amalgam.getBytes("UTF8");

                        byte[]  raw  =  cipher.doFinal(stringBytes);

                        BASE64Encoder  encoder  =  new  BASE64Encoder();

                        String  base64  =  encoder.encode(raw);

                        System.out.println(base64);

                }  else  if(args[0].indexOf("d")  !=  -1)  {

cipher.init(Cipher.DECRYPT_MODE,key);

                        BASE64Decoder  decoder  =  new  BASE64Decoder();

                        byte[]  raw  =  decoder.decodeBuffer(args[1]);

                        byte[]  stringBytes  =  cipher.doFinal(raw);

                        String  result  =  new  String(stringBytes,  "UTF8");

                        System.out.println(result);

                }

        }

    

public  static  void  main(String[]  args)  throws  Exception{

                if(args.length  <  2)  {

                        System.out.println("사용예  java  tesst.crypto.part1.SecretWriting  -[e|d]  STRING1  STRING2  ...");

                        System.exit(0);

                }

                SecretWriting  secretWriting  =  new  SecretWriting();

                secretWriting.exec(args);

        }

}

  

DES  알고리즘은  동일한  키를  생성하여  암호화와  복호화가  이루워지는  대칭키  방식이다.

  

  

Chapter  2  기본기

■  보안의  3대  규칙

1.  기밀성(Confidentially)  :  비인가  된  사람은  내용을  볼  수  없어야  한다.

  

①  대칭암호화  :  송신측과  수신측이  동일한  키를  사용한다.(비밀키,  개인키  방식)

  

②  비대칭  암호화  :  A의  공개키로  암호화  한  내용은  A의  개인키로만  풀  수  있다.  비대칭  암호화는  대칭  암호화에  비해  상당히  느리다.

  

  

  

2.  무결성(Integrity)  :  Date가  불법수정되지  못하게  보장한다.  암호화된  메시지  축약을  서명(signature)이라고  한다.

  

  

3.  인증(Authentication)  :  상호  교신하는  사람이  각각  믿을수  있는  객체임을  보장한다.

인증서는  한  사람에  의해  발급되는  문장으로  다른  사람의  공개키를  가지는  어떤  값이다.  필수적으로  인증서는  서명된  공개키이다.

  

  

■  알고리즘

비대칭  암호화와  서명은  다양한  키  크기를  가진다.  적절한  키  크기를  선태가하는  것은  사용자와  애플리케이션에  달려  있다.

  

  

명    칭


타    입


비    고

MD-5


메시지  축약


128비트  메시지  축약  생성

저항력에  약간의  허점을  발견

SHA-1


메시지  축약


160비트의  메시지  축약  생성

저항력이  증가

HmacMD5와  HmacSHA1


메시지  인증  코드


  

DSA


서명


512  ~  1024비트  까지의  키  생성

ElGamal  서명


서명


  

DES


대칭  암호화


  

DESede


대칭  암호화


  

PBEWithMD5AndDES


대칭  암호화


  

ElGamal  암호


비대칭  암호화


  

DH


키  교환


  

표)  암호화  알고리즘

  

클래스/인터페이스


정의

java.security.cert.Certificate


암호인증

javax.crypto.Cipher


암호화

java.security.Key.  java.security.PrivateKey,  java.security.PublicKey,  javax.crypto.SecretKey


서명이나  암호화에  사용되는키

javax.crypto.KeyAgreement


비밀키  교환  프로토콜

java.security.KeyFActory


공개키와  비밀키의  형식  변환

javax.crypto.KeyGenerator


대칭암호문에  사용될  키  생성

java.security.KeyPairGenerator


암호화와  인증에  사용된  공개키와  비밀키  생성

javax.crypto.Mac


메시지  인증  코드(MAC)

java.security.MessageDigest


암호화  해시함수

javax.crypto.SecretKeyFactory


비밀키의  형식  변환

java.security.SecureRandom


난수생성

java.security.Signature


전자서명

표)  JDK와  JCE에  포함된  암호화  클래스

  

개념클래스


Sun이  지원하는  암호화  알고리즘


SunJCE가  지원하는  암호화  알고리즘

Cipher


  


DES,  Desede,  PBEWithMD5AndDES

KeyAgreement


  


DH

KeyFactory


DSA


  

KeyGenerator


  


DES,DESede

KeyPairGenerator  Mac


DSA


  

Mac


  


HmacMD5,  HmacSHA1

MessageDigest


MD5,  SHA-1


  

SecretKeyFactory


  


DES,  Desede,  PBEWithMD5AndDES

Signature


DSA


  

표)  표준  알고리즘  이름

  

Chapter  3  난수

  

Chapter  4  키관리

  

■  Key  인터페이스

1.  java.security.Key  인터페이스(  암호화  키를  캡슐화  )

-  public  String  getAlgorithm()  :  키가  사용된  암호  알고리즘  이름을  리턴

-  public  byte[]  getEncoded()  :  키의  암호화  값을  구할  수  있다.

-  public  String  getFormat()  :  암호화  하는데  사용된  키  포맷의  이름을  리턴한다.

-  자식  인터페이스  :  java.security.PublicKey,  java.security.PrivateKey,

                                      javax.crypto.SecretKey(JCE)

  

2  java.security.KeyPair  클래스(  공개키와  개인키  )

-  publicKeyPair(PublicKey  publicKey,  PrivateKey,  privateKey)  :  주어진  공개키와  개인키로  KeyPair를  생성한다.

-  public  PublicKey  getPublic()  :  공개키를  리턴한다.

-  public  PrivateKey  getPrivate()  :  개인키를  리턴한다.

  

■  키  생성기

1.  java.security.KeyPairGenerator(  비대칭  방식  JDK에  포함  )

  

-  public  KeyPair  generateKeyPair  ()  :  열쇠  페어를  생성합니다.  

-  public  final  KeyPair  genKeyPair  ()  :  열쇠  페어를  생성합니다.  

-  public  String    getAlgorithm  ()  :  이  열쇠  페어  제네레이터의  알고리즘의  표준명을  돌려줍니다.  

-  public  static  KeyPairGenerator  getInstance  (String    algorithm)  :  지정된  다이제스트  알고리즘을  구현하는  KeyPairGenerator  오브젝트를  작성합니다.  

-  public  static  KeyPairGenerator  getInstance  (String    algorithm,  String    provider)  :  지정된  프로바이더로부터  지정된  알고리즘이  사용  가능한  경우에,  그  프로바이더가  제공한  알고리즘을  구현하는  KeyPairGenerator  오브젝트를  작성합니다.  

-  public  final  Provider  getProvider  ()  :  이  열쇠  페어  제네레이터  오브젝트의  프로바이더를  돌려줍니다.  

-  pubic  void  initialize  (AlgorithmParameterSpec    params)  :  제공된  파라미터를  사용하여  KeyPairGenerator를  초기화  한다.

-  public  void  initialize  (AlgorithmParameterSpec    params,  SecureRandom    random)  :  제공된  파라미터를  사용하여  KeyPairGenerator를  초기화  한다.

-  public  void  initialize  (int  keysize)  :  랜덤  비트의  소스  역할을  하는  새로운  SecureRandom을  생성하는  것을  제외하고  임의의  키  사이즈에  대하여  열쇠  페어  제네리이터를  초기화합니다.

-  pubic  void  initialize  (int  keysize,  SecureRandom    random)  :  제공된  랜덤  비트  소스를  사용하여  임의의  키  사이즈  대하는  열쇠  페어  제네레이터를  초기화합니다.

  

KeyPairGenerator  kpg  =  KeyPairGenerator.getInstance("DSA");

kpg.initialize(1024);

KeyPair  pair  =  kpg.getKeyPair();

  

  

  

2.  javax.crypto.KeyGenerator(  대칭  방식  JCE에  포함  )

  

-  public  final  SecretKey  generateKey()  :  새로운  랜덤  SecretKey를  생성한다.

-  public  String  getAlgorithm()  :  KeyGenerator  객체에  사용된  알고리즘의  이름을  리턴합니다.

-  public  static  KeyGenerator  getInstance(.String  algorithm)  :  주어진  알고리즘으로  인스턴스  생성

-  pubic  static  KeyGenerator  getInstance(String  algorithm,  String  provider)  :  주어진  알고리즘과  프로바이터로  인스턴스  생성

-  pubic  Provider  getProvider()  :  사용된  프로바이터  리턴

-  public  void  init(AlgorithmParameterSpec  params)  :  제공된  파라미터를  사용하여  초기화  한다.

-  public  void  init(AlgorithmParameterSpec  params,  SecureRandom  random)  :  제공된  파라미터를  사용하여  초기화  한다.

-  public  void  init(int  keysize)  :  주어진  크기로  키를  생성하기  위하여  초기화한다.

-  public  void  init(int  keysize,  SecureRandom  random)  :  주어진  키와  랜덤소스로  초기화  한다.

-  public  void  init(java.security.SecureRandom  random)  :  주어진  랜덤소스로  초기화  한다.

  

KeyGenerator  kg  =  KeyGenerator.getInstance("DES");

kg.init(new  SecureRandom());

SecretKey  key  =  kg.generateKey()

  

  

  

■  키  해석기

키를  저장하는  방법중  하나는  키를  직렬화  하여  저장하는것과  단순히  바이트의  배열과  같이  키를  저장하거나  전송하는  방법이  있다.  키  객체를  바이트로  또는  역으로  변환하는  방법이  다음의  클래스에  정의  되어있다.

  

1.  javax.crypto.spec.SecretKeySpec(  바이트  배열을  비밀키로  변환하는  가장  간단한  방법  )

-  SecretKeySpec(byte[]  key,  int  offset,  int  len,  String  algorithm)  :  offset과  제공된  바이트의  배열의  len  바이트를  사용하여  SecretKeySpec을  생성한다.  키는  제공된  알고리즘을  따른다.

-  SecretKeySpec(byte[]  key,  String  algorithm)  :  제공된  바이트  배열을  사용하여  SecretKeySpec을  생성한다.  키는  제공된  알고리즘을  따른다.

  

SecureRandom  sr  =  new  SecureRandom();

byte[]  keyBytes  =  new  byte[20];

sr.nextBytes(keyBytes);

SecretKey  key  =  new  SecretKeySpec(keyBytes,  "HmacSHA1");

  

  

  

2.  javax.crypto.SecretKeyFactory

-  public  static  final  SecretKeyFactory  getInstance(String  algorithm)  :  주어진  알고리즘에  대하여  새로운  SecretKeyFactory를  생성한다  알고리즘은  “DES"와  같은  대칭  암호  알고리즘이다.

-  pubic  static  final  SecretKeyFactory  getInstance(String  algorithm,  String  provider)  :  주어진  프로바이더로  SecretKeyFActory를  생성한다.

-  public  final  SecretKey  generateSecret(KeySpec  keySpec)  :  KeySpec를  SecretKey로  변환하기  위하여  사용된다.

public  SecertKey  makeDESKey(byte[]  input,  int  offset)

throws  NoSuchAlgorithmException,  InvalidkeyException,  InvalidkeySpecException{

              SecretKeyFactory  desFactory  =  SecretKeyFactory.getInstance("DES");

              KeySpec  spec  =  new  DESKeySpec(input,  offset);

              return  desFactory.generateSecret(spec);

}

  

  

-  public  final  KeySpec  getKeySpec(SecretKey  key,  java.lang.Class  keySpec)  :  주어진  SecretKey로부터  KeySpec을  생성한다.

  

public  byte[]  makeBytesFromDESKey  (SecretKey  key)

throw  NoSuchAlgorithmException,  InvaildKeySpecException  {

              SecretKeyFactory  desFactory  =  SecretKeyFactory.getInstance("DES");

              DESKeySpec  spec  =

              (DESKeySpec)desFactory.getKeySpec(Key,  DESKeySpec.class);

              return  spec.getKey();

}

  

  

3.  java.security.KeyFactory

  -  public  static  final  KeyFactory    getInstance  (String    algorithm)  :  지정된  다이제스트  알고리즘을  구현하는  KeyFactory  오브젝트를  작성합니다.  알고리즘  이름은  비대칭  암호  알고리즘  이름이거나  “DSA"와  같은  서명  알고리즘  이어야  합니다.

-  public  static  final  KeyFactory    getInstance  (String    algorithm,  String    provider)  :  지정된  프로바이더로부터,  지정된  알고리즘의  KeyFactory  오브젝트를  작성합니다.  

-  public  final  PrivateKey    generatePrivate  (KeySpec    keySpec)  :  지정된  열쇠  사양  (열쇠  데이터)으로부터  개인키를  생성하는데  사용

-  public  final  PublicKey    generatePublic  (KeySpec    keySpec)  :  지정된  열쇠  사양  (열쇠  데이터)으로부터  공개키를  생성하는데  사용

-  public  final  KeySpec    getKeySpec  (Key    key,  Class    keySpec)  :  주어진  키로부터  키  스펙을  생성한다.

  

■  키  교환  프로토콜

1.  javax.crypto.KeyAgreement

-  public  static  final  KeyAgreement  getInstance(String  algorithm)  :  주어진  알고리즘을  사용하여  새로운  KeyAgreement를  생성한다.  이름은  “DH"와  같은  키교환  알고리즘이어야  한다.

-  public  static  final  KeyAgreement  getInstance(String  algorithm,  String  provider)  :  주어진  알고리즘과  프로바이더로  새로운  KeyAgreement를  생성한다.

-  public  final  void  init(Key  key)  :  제공된  키를  사용하는  KeyAgreement를  초기화  한다.

-  public  final  void  init(Key  key,  AlgorithmParameterSpec  params)  :  주어진  키와  알고리즘  지정  파라미터를  사용하여  KeyAgreement를  초기화  한다.

-  public  final  void  init(.Key  key,  AlgorithmParameterSpec  params,  SecureRandom  random)  :  주어진  키와  알고리즘  지정  파라미터  그리고  랜덤  소스를  사용해서  KeyAgreement를  초기화  한다.

-  public  final  void  init(Key  key,  SecureRandom  random)

-  public  final  Key  doPhase(Key  key,  boolean  lastPhase)

-  public  final  byte[]  generateSecret()

-  public  final  int  generateSecret(byte[]  sharedSecret,  int  offset)

-  public  final  SecretKey  generateSecret(java.lang.String  algorithm)

-  public  final  String  getAlgorithm()

-  public  final  Provider  getProvider()

  

//  --<  Skip  Server  >

package  test.crypto.part5;

import  java.security.*;

import  java.net.*;

import  java.io.*;

import  java.security.spec.*;

import  javax.crypto.*;

import  sun.misc.*;

  

public  class  SkipServer    {

        public  SkipServer()  {

        }

  

        public  void  exec(int  port)  throws  Exception  {

  

                //Diffie-Hellman  키  쌍  생성

                KeyPairGenerator  kpg  =  KeyPairGenerator.getInstance("DH");

                kpg.initialize(Skip.sDHParameterSpec);

                KeyPair  keypair  =  kpg.genKeyPair();

  

                //  연결을  기다린다.

                ServerSocket  ss  =  new  ServerSocket(port);

                System.out.println("요청을  기다리고  있습니다....  port  :  "+port);

                Socket  s  =  ss.accept();

                DataOutputStream  out  =  new  DataOutputStream(s.getOutputStream());

                      DataInputStream    in    =  new  DataInputStream(s.getInputStream());

/**

                  *  첫번째  클라이언트는  서버에  바이트  배열의  코드화된

                  *  Difie-Hellman공개키를  보낸다.

                  *  KeyFactory가  그  키를  재구성하기  위해  사용된다.

                  */

                //  공개키를  받는다.

                byte[]  keyBytes  =  new  byte[in.readInt()];

                in.readFully(keyBytes);

                KeyFactory  kf  =  KeyFactory.getInstance("DH");

                X509EncodedKeySpec  x509Spec  =  new  X509EncodedKeySpec(keyBytes);

                PublicKey  theirPublicKey  =  kf.generatePublic(x509Spec);

  

                //  우리의  키를  클라이언트에게  보낸다.

                keyBytes  =  keypair.getPublic().getEncoded();

                out.writeInt(keyBytes.length);

                out.write(keyBytes);

  

                /**

                  *  이제  개인키와  클라이언트의  공개키를  사용해서  보안값을  계산할수  있다.

                  *  그  보안  값은  Diffie-Hellman  키를  생성

                  *  하기  위해  사용된  계수만큼  길다.  이  경우  보안값은

              

  *  1024비트  길이를  가진다.

                  */

                  KeyAgreement  ka  =  KeyAgreement.getInstance("DH");

                  ka.init(keypair.getPrivate());

                  ka.doPhase(theirPublicKey,true);

                  byte[]  secret  =  ka.generateSecret();

                  out.close();

                  in.close();

                  BASE64Encoder  encoder  =  new  BASE64Encoder();

                  System.out.println(encoder.encode(secret));

        }

      

        public  static  void  main(String[]  args)  throws  Exception  {

      

                if(args.length  <  1)  {

                        System.out.println("포트  번호를  입력해주셔야  합니다...");

                        System.exit(0);

                }

                SkipServer  skipServer  =  new  SkipServer();

                skipServer.exec(Integer.parseInt(args[0]));

        }

}

  

  

  

  

//---  <  Skip  Client  >

package  test.crypto.part5;

import  java.security.*;

import  java.net.*;

import  java.io.*;

import  java.security.spec.*;

import  javax.crypto.*;

import  sun.misc.*;

  

public  class  SkipClient    {

        public  SkipClient()  {

        }

  

        public  void  exec(String  ip,  int  port)  throws  Exception  {

  

                //Diffie-Hellman  키  쌍  생성

                KeyPairGenerator  kpg  =  KeyPairGenerator.getInstance("DH");

                kpg.initialize(Skip.sDHParameterSpec);

                KeyPair  keypair  =  kpg.genKeyPair();

  

                //  네트워크  연결

                Socket  s  =  new  Socket(ip,  port);

                DataOutputStream  out  =  new  DataOutputStream(s.getOutputStream());

                DataInputStream    in    =  new  DataInputStream(s.getInputStream());

  

  

                //  공개키  전송

                byte[]  keyBytes  =  keypair.getPublic().getEncoded();

                out.writeInt(keyBytes.length);

                out.write(keyBytes);

  

  

                //  공개키  수신

                keyBytes  =  new  byte[in.readInt()];

                in.readFully(keyBytes);

                KeyFactory  kf  =  KeyFactory.getInstance("DH");

                X509EncodedKeySpec  x509Spec  =  new  X509EncodedKeySpec(keyBytes);

                PublicKey  theirPublicKey  =  kf.generatePublic(x509Spec);

  

  

                /**

                  *  이제  개인키와  클라이언트의  공개키를  사용해서  보안값을  계산할수  있다.  그  보안  값은  Diffie-Hellman  키를  생성

                  *  하기  위해  사용된  계수만큼  길다.  이  경우  보안값은  1024비트  길이를  가진다.

                  */

                  KeyAgreement  ka  =  KeyAgreement.getInstance("DH");

                  ka.init(keypair.getPrivate());

                  ka.doPhase(theirPublicKey,true);

                        byte[]  secret  =  ka.generateSecret();

out.close();

                  in.close();

                  BASE64Encoder  encoder  =  new  BASE64Encoder();

                  System.out.println(encoder.encode(secret));

        }

      

        public  static  void  main(String[]  args)  throws  Exception  {

      

                if(args.length  <  2)  {

                        System.out.println("서버  아이피와  포트  번호를  입력해주셔야  합니다...");

                        System.exit(0);

                }

                SkipClient  skipClient  =  new  SkipClient();

                skipClient.exec(args[0],  Integer.parseInt(args[1]));

        }

}

  

  

  

  

■  KeyStore  클래스의  키  관리  패러다임

1.  인스턴스  생성

-  public  static  final  KeyStore    getInstance  (String    type)  :  지정된  타입의  키  스토어  오브젝트를  작성합니다.  KeyStore  ks  =  KeyStore.getInstance("JKS");

-  public  static  final  KeyStore    getInstance  (String    type,  String    provider)  :  지정된  프로바이더로부터,  지정된  키  스토어  타입의  키  스토어  오브젝트를  작성합니다.  KeyStore  ks  =  KeyStore.getInstance("JKS",  "SUN");

2.  로딩과  저장

-  public  final  void  load  (InputStream    stream,  char[]  password)  :  지정된  입력  Stream로부터  이  키  스토어를  로드합니다.  

-  public  final  void  store  (OutputStream    stream,  char[]  password)  :  지정된  출력  Stream에  이  키  스토어를  격납  해,  지정된  패스워드로  그  완전성을  보호합니다

  

향후  내용  추가  요망....

  

  

Chapter  5  인증

인증에  유요한  세가지  암호화  개념

-  메시지  축약(message  digest)은  대용량  데이터  집합을  나타내는  식별자를  생성한다.

-  전자  서명(digital  signature)은  데이터의  무결성을  증명하는데  사용한다.

-  인증서(certificate)는  암호적으로  공개키의  안전한  컨테이너로  사용된다.

  

■  변경된  메시지  축약

  

package  test.crypto.part6;

import  java.security.*;

import  java.io.*;

import  sun.misc.*;

  

public  class  MessageDigestTester    {

        public  MessageDigestTester()  {

        }

  

        private  void  exec(String  targetFileName)  {

  

                try  {

                        //  MD5알고리즘을  이용한  메시지  축약  객체를  생성한다.

                        MessageDigest  md  =  MessageDigest.getInstance("MD5");

  

                        //  주어진  파일에  대한  축약  값  계산

                        DigestInputStream  in  =  new  DigestInputStream(new  FileInputStream(targetFileName),  md);

                        byte[]  buffer  =  new  byte[8192];

                        while  (  in.read(buffer)  !=  -1  )  {

                        }

                        byte[]  raw  =  md.digest();

  

                        //  출력  가능한  문자열로  변환한다.

                        BASE64Encoder  encoder  =  new  BASE64Encoder();

                        String  base64  =  encoder.encode(raw);

                        System.out.println(base64);

                }  catch(NoSuchAlgorithmException  nalgoe)  {

                        System.err.println(nalgoe);

                }  catch(FileNotFoundException  fnote)  {

                        System.err.println(fnote);

                }  catch(IOException  ioe)  {

                        System.err.println(ioe);

                }

        }

        public  static  void  main(String[]  args)  {

                if(args.length  <  1)  {

                        System.out.println("메시지  축약의  대상  파일을  선택하여  주십시요");

                        System.exit(0);

                }

                String  targetFileName  =    args[0];

                MessageDigestTester  masher  =  new  MessageDigestTester();

                masher.exec(targetFileName);

        }

}

  

  

■  암호화된  패스워드  로그인

클라이언트에서  서버로  평문을  전송하는  것을  피하기  위해서,  클라이언트는  평문  대신에  패스워드  메시지를  축약하여  보내게  되며,  서버는  보유하고  있는  패스워드  사본의  메시지  축약을  비교하여  두  개의  메시지  축약  내용이  같을  경우에  클라이  언트를  인증하게  된다.

  

//---  <  masher  Server  >

package  test.crypto.part6;

import  java.util.*;

import  java.net.*;

import  java.io.*;

import  java.security.*;

  

public  class  MasherServer  {

  

        public  MasherServer()  {

        }

  

        public  void  exec(int  port)  throws  Exception  {

  

                ServerSocket  ss  =  new  ServerSocket(port);

                System.out.println("요청을  기다리고  있습니다....  port  :  "+port);

                Socket  s  =  ss.accept();

                DataInputStream  in  =  new  DataInputStream(s.getInputStream());

  

                //  클라이언트가  보낸  순서로받는다.

                String  user  =  in.readUTF();

                long  time  =  in.readLong();

                double  randomQ  =  in.readDouble();

                int  leng  =  in.readInt();

                byte[]  masherBytesIn  =  new  byte[leng];

                in.readFully(masherBytesIn);

                byte[]  masherBytesOut  =  userMasher.makeDigest(user,  getPassword(),  time,  randomQ);

  

                if(isUser(masherBytesIn,  masherBytesOut))  {

                        System.out.println("Login");

                }  else  {

                        System.out.println("No  password");

                }

                in.close();

        }

  

        private  String  getPassword()  {

                return  "rlarudwls";

        }

  

        private  boolean  isUser(byte[]  inBytes,  byte[]  outBytes){

                return  MessageDigest.isEqual(inBytes,  outBytes);

        }

  

  

  

  

  

  

public  static  void  main(String[]  args)  throws  Exception  {

                if(args.length  <  1)  {

                        System.out.print("포트를  입력하여  주십시요....");

                        System.exit(0);

                }

                MasherServer  ms  =  new  MasherServer();

                ms.exec(Integer.parseInt(args[0]));

        }

}

  

//---<  masherClient  >

package  test.crypto.part6;

import  java.util.*;

import  java.net.*;

import  java.io.*;

  

public  class  MasherClient    {

  

        public  MasherClient()  {

        }

  

        public  void  exec(String  user,  String  password,  String  host,  int  port)  throws  Exception  {

                Date  date  =  new  Date();

                long  time  =  date.getTime();

                double  randomQ  =  Math.random();

                byte[]  masherBytes  =  userMasher.makeDigest(user,  password,  time,  randomQ);

                Socket  s  =  new  Socket(host,  port);

                DataOutputStream  out  =  new  DataOutputStream(s.getOutputStream());

                out.writeUTF(user);

                out.writeLong(time);

                out.writeDouble(randomQ);

                out.writeInt(masherBytes.length);

                out.write(masherBytes);

                out.flush();

                out.close();

        }

        public  static  void  main(String[]  args)  throws  Exception  {

                if(args.length  <  2)  {

                        System.out.print("서버  주소와  포트를  입력하여  주십시요....");

                        System.exit(0);

                }

                String  user  =  "inter999";

                String  password  =  "rlarudwls";

                MasherClient  mc  =  new  MasherClient();

                mc.exec(user,  password,  args[0],  Integer.parseInt(args[1]));

        }

}

  

  

package  test.crypto.part6;

import  java.io.*;

import  java.security.*;

  

public  class  userMasher    {

        public  static  byte[]  makeDigest(String  user,  String  password,  long  time,  double  randomQ)

        throws  NoSuchAlgorithmException  {

                MessageDigest  md  =  MessageDigest.getInstance("SHA");

                md.update(user.getBytes());

                md.update(password.getBytes());

                md.update(makeBytes(time,  randomQ));

                return  md.digest();

        }

  

        public  static  byte[]  makeBytes(long  time,  double  randomQ)  {

                try  {

                        ByteArrayOutputStream  byteout  =  new  ByteArrayOutputStream();

                        DataOutputStream  dataout  =  new  DataOutputStream(byteout);

                        dataout.writeLong(time);

                        dataout.writeDouble(randomQ);

                        return  byteout.toByteArray();

                }  catch  (IOException  ioe)  {

                        return  new  byte[0];

                }

        }

}

  

■  이중  암호화  패스워드  로그인

메시지  축약을  사용하여  패스워드  정보를  보호하는  강력한  방법으로  이중  암호화  기법이  있는데,  이의  구성은  “암호화  패스워드  로그인”에  추가적으로  타임스템프와  난수를  포함한다.  즉  두  번째  축약에서  처음  축약메시지와  타임스템프,  난수를  이용하여  축약한다.

  

  

■  MAC

이  클래스는  메시지  인증  코드(MAC)에  대한  API를  정의한다.  MAC은  비밀키를  공유하는  두  집단  사이에서  전송되는  정보의  무결성을  검사할  수  있다.  MAC은  공개키/개인키가  아니라  비밀키와  함께  생성된다는  점을  제외하면  디지털  서명과  비슷하다.  MAC  클래스는  알고리즘과  무관하며  제공자-기반이다.  정적  getInstance()  팩토리  메소드  중  하나를  호출하여  희망하는  MAC  알고리즘의  이름을  지정하여  MAC  객체를  얻는다.

“SunJCE"제공자는  ”HmacMD5",  "HmacSHA1"이라는  두  개의  알고리즘을  구현한다.

  

1.  Mac  객체를  얻은  후에는  init()  메소드를  호출하여  SecretKey를  지정하여  이  Mac  객체를  초기화  한다.

2.  Mac  객체를  얻고  초기화  한  후에는,  Mac이  계산될  데이터를  지정한다.  단순히  단일  바이트  배열을  처리  할때는  doFinal()에  전달하고,  스트리밍이나  다양한  위치에  저장된다면  update()를  여러번  호출하여  처리한다.

  

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();

  

  

  

■  서명(java.security.Signature)

서명은  두  가지  보안  서비스(인증과  무결성)  즉,  메시지가  변조되어  오지  않는  것과  메시지가  어떤  사람으로부터  보내졌는지를  보장해준다.  서명은  서명한  사람의  개인키를  가지고  암호화한  메시지  축약이다.  서명한  사람의  공개키만이  서명을  복호화  할  수  있으며,  이것이  인증을  제공한다.  메시지  축약이  서명으로부터  복호화한  메시지  축약과  같다면,  무결성  역시  보장되는  것이다.

  

1.  Signature  객체는  정적  팩토리  메소드인  getInstance()중의  하나를  원하는  전자  서명  알고리즘과  선택적으로  알고리즘의  제공자를  지정하면서  호출하여  얻을  수있다.

2.  전자  서명은  본질적으로  공개키  암호화  알고리즘으로  암호화된  메시지  축약이다.  따라서  전자  서명  알고리즘을  지정하려면,  축약  알고리즘과,  암호화  알고리즘을  모두  지정해야한다.

3.  기본  “SUN"제공자에서  지원되는  유일한  알고리즘은  ”SHA1WwithDSA"이다.

4.  전자  서명의  생성을  위한  초기화를  하려면  initSign()을  호출하고  서명  생성을  위한  개인키를  지정해야한다.

5.  서명의  검증을  위한  초기화를  하려면  initVerify()를  호출하고  사인자(signer)의  공개키를  지정해야  한다.

6.  Signature  객체가  초기화  되었으면  update()를  한번  이상  호출하여  사인되거나  검증될  바이트를  지정한다.

7.  마지막으로  전자  서명을  생성하기  위해  sign()을  호출하면서  사인이  저장될  바이트  배열을  넘겨준다.

  

  

  

//  핼퍼클래스

package  acdpu.pki;

import  java.io.Serializable;

import  java.security.PrivateKey;

import  java.security.PublicKey;

  

public  class  PKIHelper  implements  Serializable    {

        private  String  userId;

        private  String  passwd;

        private  String  createDate;

        private  String  destroyDate;

        private  PrivateKey  privatekey;

        private  PublicKey  publickey;

  

        public  String  getUserId()  {

                return  userId;

        }

  

        public  void  setUserId(String  newUserId)  {

                userId  =  newUserId;

        }

  

        public  String  getPasswd()  {

                return  passwd;

        }

  

        public  void  setPasswd(String  newPasswd)  {

                passwd  =  newPasswd;

        }

  

        public  String  getCreateDate()  {

                return  createDate;

        }

  

        public  void  setCreateDate(String  newCreateDate)  {

                createDate  =  newCreateDate;

        }

  

        public  String  getDestroyDate()  {

                return  destroyDate;

        }

  

        public  void  setDestroyDate(String  newDestroyDate)  {

                destroyDate  =  newDestroyDate;

        }

  

        public  PrivateKey  getPrivatekey()  {

                return  privatekey;

        }

  

        public  void  setPrivatekey(PrivateKey  newPrivatekey)  {

                privatekey  =  newPrivatekey;

        }

  

        public  PublicKey  getPublickey()  {

                return  publickey;

        }

  

        public  void  setPublickey(PublicKey  newPublickey)  {

                publickey  =  newPublickey;

        }

}

  

  

//  컨트롤러

package  acdpu.pki;

  

import  java.security.*;

import  acdpu.pki.exception.*;

  

public  class  PKIController    {

        public  PKIController()  {

        }

  

        public  PrivateKey  createKeyPair(String  userid,  String  passwd)

        throws  PKICreateException,  IncorrectUserException,  TermExpirationException,  PKIDBHandlerException  {

                try{

                        KeyPairGenerator  kpg  =  KeyPairGenerator.getInstance("DSA",  "SUN");

                        kpg.initialize(1024,SecureRandom.getInstance("SHA1PRNG"));

                        KeyPair  keypair  =  kpg.genKeyPair();

                        PKIDBHandler.userConfirm(userid,  passwd);

                        PKIHelper  pkihelper  =  new  PKIHelper();

                        pkihelper.setUserId(userid);

                        pkihelper.setPasswd(passwd);

                        pkihelper.setPrivatekey(keypair.getPrivate());

                        pkihelper.setPublickey(keypair.getPublic());

                        PKIDBHandler.saveKeyPair(pkihelper);

                        return  pkihelper.getPrivatekey();

                }  catch  (NoSuchProviderException  nope)  {

                        throw  new  PKICreateException("NoSuchProvider");

                      

                }  catch  (NoSuchAlgorithmException  noae)  {

                        throw  new  PKICreateException("NoSuchAlgorithm");

                }

        }

  

        public  void  loginPKI(String  userid,  String  passwd,  byte[]  signature)

        throws  PKIInvalidException,  IncorrectUserException,  TermExpirationException,  PKIDBHandlerException  {

                PKIDBHandler.userConfirm(userid,  passwd);

                PKIDBHandler.verify(userid,  passwd,  signature);

        }

  

        public  static  void  main(String[]  args)  {

                PKIController  pKIController  =  new  PKIController();

        }

}

  

  

  

//  데이터  모델

package  acdpu.pki;

  

import  java.sql.*;

import  java.io.*;

import  acdpu.pki.exception.*;

import  java.security.*;

import  java.security.spec.*;

  

public  class  PKIDBHandler    {

  

        public  static  boolean  saveKeyPair(PKIHelper  pkihelper)

        throws  PKIDBHandlerException  {

                Connection  con  =  null;

                PreparedStatement  pstmt  =  null;

                ResultSet  rs  =  null;

  

                try  {

                        Class.forName("oracle.jdbc.driver.OracleDriver");                      

                        con  =  DriverManager.getConnection("jdbc:oracle:thin:@  218.145.231.3:1522:ora8",  "itdev",  "itdev");

                        con.setAutoCommit(false);

  

                        StringBuffer  sbSQL  =  new  StringBuffer();

                        sbSQL.append("update  TB_PKI  set  privatekey  =  ?,  publickey  =  ?,  indate=sysdate  where  userid='"+pkihelper.getUserId()+"'");

                        pstmt  =  con.prepareStatement(sbSQL.toString());

                        ByteArrayInputStream  privateKeywriter    =  new  ByteArrayInputStream(pkihelper.getPrivatekey().getEncoded());

                        ByteArrayInputStream  publicKeywriter      =  new  ByteArrayInputStream(pkihelper.getPublickey().getEncoded());

                        pstmt.setBinaryStream(1,privateKeywriter,privateKeywriter.available());

                        pstmt.setBinaryStream(2,publicKeywriter,publicKeywriter.available());

                      

                        pstmt.executeUpdate();

                        privateKeywriter.close();

                        publicKeywriter.close();

                        con.commit();

                        return  true;

                }  catch(ClassNotFoundException  cnote)  {

                        throw  new  PKIDBHandlerException("PKIDBHandler.saveKeyPair  Method  Error  :  Message  =  "+cnote.getMessage());

                }  catch(IOException  io)  {

                        throw  new  PKIDBHandlerException("PKIDBHandler.saveKeyPair  Method  Error  :  Message  =  "+io.getMessage());

                }  catch(SQLException  e)  {

                        try{

                                con.rollback();

                                con.setAutoCommit(true);

                        }catch(Exception  er){}

                        throw  new  PKIDBHandlerException("PKIDBHandler.saveKeyPair  Method  Error  :  Message  =  "+e.getMessage());

                }  finally  {

                        try  {

                                con.setAutoCommit(true);

                                if(rs  !=null  )  {

                                        rs.close();

                                        rs=null;                      

                                }

                                if(pstmt  !=null  )  {

                                        pstmt.close();

                                        pstmt  =  null;

                                }

                                if(con!=null  &&  !con.isClosed())  {

                                        con.close();

                                        con  =null;

                                }  else  {

                                        con=null;

                                }

                        }  catch(Exception  e)  {

                                rs  =  null;

                                pstmt  =  null;

                                con  =  null;

                        }

                }

        }

  

        public  static  void  verify(String  userid,  String  passwd,  byte[]  signature)

        throws  PKIInvalidException,  PKIDBHandlerException  {      

                Connection  con  =  null;

                PreparedStatement  pstmt  =  null;

                ResultSet  rs  =  null;

  

                try  {

                        Class.forName("oracle.jdbc.driver.OracleDriver");                      

                        con  =  DriverManager.getConnection("jdbc:oracle:thin:@  218.145.231.3:1522:ora8",  "itdev",  "itdev");

                        StringBuffer  sbSQL  =  new  StringBuffer();

                        sbSQL.append("select  publickey  from  TB_PKI  where  userid  ='"+userid+"'");

                        pstmt  =  con.prepareStatement(sbSQL.toString());

                        rs  =  pstmt.executeQuery();

                        if(rs.next())  {

                                byte[]  publicbyte  =  rs.getBlob(1).getBytes(1,1024);

                                System.out.println(publicbyte.length);

                                KeyFactory  kf  =  KeyFactory.getInstance("DSA");

                                X509EncodedKeySpec  x509Spec  =  new  X509EncodedKeySpec(publicbyte);

                                PublicKey  publickey  =  kf.generatePublic(x509Spec);

  

                                Signature  sign  =  Signature.getInstance("DSA");

                                sign.initVerify(publickey);

                                sign.update((userid+passwd).getBytes());

                                if(!sign.verify(signature)){

                                        throw  new  PKIInvalidException("The  signature  is  badd");

                                }

                        }

                }  catch(ClassNotFoundException  cnote)  {

                        throw  new  PKIDBHandlerException("PKIDBHandler.saveKeyPair  Method  Error  :  Message  =  "+cnote.getMessage());

                }  catch(SQLException  e)  {

                        throw  new  PKIDBHandlerException("PKIDBHandler.saveKeyPair  Method  Error  :  Message  =  "+e.getMessage());

                }  catch(NoSuchAlgorithmException  noale)  {

                        throw  new  PKIDBHandlerException("PKIDBHandler.saveKeyPair  Method  Error  :  Message  =  "+noale.getMessage());

                }  catch(InvalidKeyException  inkeye)  {

                        throw  new  PKIDBHandlerException("PKIDBHandler.saveKeyPair  Method  Error  :  Message  =  "+inkeye.getMessage());

                }  catch(InvalidKeySpecException  inkeyse)  {

                        throw  new  PKIDBHandlerException("PKIDBHandler.saveKeyPair  Method  Error  :  Message  =  "+inkeyse.getMessage());                        

                }  catch(SignatureException  sie)  {

                        throw  new  PKIDBHandlerException("PKIDBHandler.saveKeyPair  Method  Error  :  Message  =  "+sie.getMessage());                      

                }  finally  {

                        try  {

                                if(rs  !=null  )  {

                                        rs.close();

                                        rs=null;                      

                                }

                                if(pstmt  !=null  )  {

                                        pstmt.close();

                                        pstmt  =  null;

                                }

                                if(con!=null  &&  !con.isClosed())  {

                                        con.close();

                                        con  =null;

                                }  else  {

                                        con=null;

                                }

                        }  catch(Exception  e)  {

                                rs  =  null;

                                pstmt  =  null;

                                con  =  null;

                        }

                }

  

        }

  

        public  static  boolean  userConfirm(String  userid,  String  passwd)

        throws  IncorrectUserException,  TermExpirationException,  PKIDBHandlerException  {

                Connection  con  =  null;

                PreparedStatement  pstmt  =  null;

                ResultSet  rs  =  null;

  

                try  {

                        Class.forName("oracle.jdbc.driver.OracleDriver");                      

                        con  =  DriverManager.getConnection("jdbc:oracle:thin:@  218.145.231.3:1522:ora8",  "itdev",  "itdev");

  

                        StringBuffer  sbSQL  =  new  StringBuffer();

                        sbSQL.append("select  passwd,  \n");

                        sbSQL.append("    nvl((select  'usein'  from  tb_pki  \n");

                        sbSQL.append("    where  userid='"+userid+"'  \n");

                        sbSQL.append("    and  to_char(sysdate,'YYYYMMDD')  between  to_char(createdate,'YYYYMMDD')  and  to_char(destroydate,'YYYYMMDD')),'useout')  term  \n");

                        sbSQL.append("from  tb_pki  where  userid='"+userid+"'");

                        pstmt  =  con.prepareStatement(sbSQL.toString());

                        rs  =  pstmt.executeQuery();

                        if(rs.next()){

                                String  term  =  rs.getString(2);

                                if(!passwd.equals(rs.getString(1))){

                                        throw  new    IncorrectUserException("The  password  is  imaccurate");

                                }

                                if(!"usein".equals(rs.getString(2)))  {

                                        throw  new  TermExpirationException("Be  not  the  period");

                                }

                              

                        }  else  {

                                throw  new  IncorrectUserException("Not  find  the  user");

                        }

                        return  true;

                }  catch(ClassNotFoundException  cnote)  {

                        throw  new  PKIDBHandlerException("PKIDBHandler.userConfirm  Method  Error  :  Message  =  "+cnote.getMessage());                      

                }  catch(SQLException  e)  {

                        try{

                        }catch(Exception  er){}

                        throw  new  PKIDBHandlerException("PKIDBHandler.userConfirm  Method  Error  :  Message  =  "+e.getMessage());

                }  finally  {

                        try  {

                                if(rs  !=null  )  {

                                        rs.close();

                                        rs=null;                      

                                }

                                if(pstmt  !=null  )  {

                                        pstmt.close();

                                        pstmt  =  null;

                                }

                                if(con!=null  &&  !con.isClosed())  {

                                        con.close();

                                        con  =null;

                                }  else  {

                                        con=null;

                                }

                        }  catch(Exception  e)  {

                                rs  =  null;

                                pstmt  =  null;

                                con  =  null;

                        }

                }

        }      

  

        public  static  boolean  destroyKeyPair(String  userid,  byte[]  signature)  {

                return  true;

        }

}

  

  

  

//  인증서  생성  클라이언트

package  acdpu.pki.applet;

import  javax.swing.JApplet;

import  java.awt.Dimension;

import  java.awt.Toolkit;

import  java.awt.BorderLayout;

import  javax.swing.JFrame;

import  javax.swing.UIManager;

import  javax.swing.JLabel;

import  java.awt.Rectangle;

import  javax.swing.JPanel;

import  javax.swing.BorderFactory;

import  javax.swing.JScrollPane;

import  javax.swing.JTextPane;

import  javax.swing.JTextField;

import  javax.swing.JButton;

import  javax.swing.JPasswordField;

import  java.awt.event.ActionListener;

import  java.awt.event.ActionEvent;

import  java.net.*;

import  java.io.*;

import  java.security.*;

  

public  class  createPKIApplet  extends  JApplet    {

  

        //  객체  생성

        private  JLabel  topLabel  =  new  JLabel();    //  상단  라벨

        private  JScrollPane  messageScrollPane  =  new  JScrollPane();  //  하단  메시지창  스크롤

        private  JTextPane  messageTextPane  =  new  JTextPane();  //  하단  메시지창

        private  JTextField  userid  =  new  JTextField();  //  사용자  아이디  입력

        private  JPasswordField  passwd  =  new  JPasswordField();  //  사용자  암호  입력

        private  JButton  submit  =  new  JButton();  //  전송  버튼

        private  JButton  reset  =  new  JButton();    //  리셋

  

        public  createPKIApplet()  {

        }

  

        public  void  init()  {

      

                try  {

                        jbInit();

                }  catch(Exception  e)  {

                        e.printStackTrace();

                }

        }

  

        private  void  jbInit()  throws  Exception  {

                this.getContentPane().setLayout(null);

                this.setSize(new  Dimension(524,  397));

  

                //  상단  라벨

                topLabel.setText("인증키생성");

                topLabel.setBounds(new  Rectangle(0,  0,  525,  30));

  

                //  사용자  아이디

                userid.setBounds(new  Rectangle(15,  35,  280,  65));

                userid.setBorder(BorderFactory.createTitledBorder("UserId"));

  

                //  사용자  암호

                passwd.setBounds(new  Rectangle(15,  115,  280,  60));

                passwd.setBorder(BorderFactory.createTitledBorder("PassWord"));

  

                //  전송  버튼

                submit.setText("전송");

                submit.setBounds(new  Rectangle(85,  215,  125,  40));

                submit.addActionListener(new  ActionListener()  {

                                public  void  actionPerformed(ActionEvent  e)  {

                                        submit_actionPerformed(e);

                                }

                        });

  

                //  리렛  버튼

                reset.setText("재입력");

                reset.setBounds(new  Rectangle(305,  215,  125,  40));

                reset.addActionListener(new  createPKIApplet_reset_actionAdapter(this));

  

                //  스크롤  상자

                messageScrollPane.setBounds(new  Rectangle(10,  290,  505,  80));

                messageScrollPane.setBorder(BorderFactory.createTitledBorder("Message"));

                messageScrollPane.setAutoscrolls(true);

  

                //  메시지  창

                messageTextPane.setText("인증  서버연결  준비중...");

                messageTextPane.setEditable(false);

                messageScrollPane.getViewport().add(messageTextPane,  null);

  

                this.getContentPane().add(passwd,  null);

                this.getContentPane().add(reset,  null);

                this.getContentPane().add(submit,  null);

                this.getContentPane().add(userid,  null);

                this.getContentPane().add(messageScrollPane,  null);

                this.getContentPane().add(topLabel,  null);

        }

  

        static      {

                try  {

                        //  UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

                        //  UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());

                }  catch(Exception  e)  {

                }

        }

  

        void  reset_actionPerformed(ActionEvent  e)  {

                userid.setText("");

                passwd.setText("");

                userid.setEditable(true);

                passwd.setEditable(true);

                setMessage("입력  창이  초기화  되었습니다.");

        }

  

        private  void  setMessage(String  message)  {

                messageTextPane.setText(messageTextPane.getText()+"\n"+message);

        }

  

        private  void  submit_actionPerformed(ActionEvent  e)  {

                userid.setEditable(false);

                passwd.setEditable(false);

                String  userEnterText  =  userid.getText();

                String  passEnterText  =  new  String(passwd.getPassword());

                setMessage("인증서버에  접속중입니다....  ");

                

                try{

                        URL  url  =  new  URL("http","218.145.231.120",7001,"/PKI/createpki?userid="+userEnterText+"&passwd="+passEnterText);

                        URLConnection  urlcon  =  url.openConnection();

                        String  contentType  =  urlcon.getContentType();

  

                        //  테스트  출력

                        //setMessage(contentType);

  

                        InputStream  in  =  urlcon.getInputStream();

                      

                        if(contentType.equalsIgnoreCase("text/html;euc-kr"))  {

                        //  인증서가  정상적으로  발급되지  않은  경우  실행

                                BufferedReader  inre  =  new  BufferedReader(new  InputStreamReader(in));

                                setMessage("ERROR)  :  다음과  같은  에러가  발생하였습니다.");

                                String  errorMessage  =  inre.readLine();

  

                                if(errorMessage.equals("1"))

                                        setMessage("인증성  생성에  실패  하였습니다.");

                                else  if(errorMessage.equals("2"))

                                        setMessage("사용자가  틀림니다.  아이디와  비밀번호를  확인해  주십시요.");

                                else  if(errorMessage.equals("3"))

                                        setMessage("사용기간이  지났거나  시작되지  않았습니다.");

                                else

                                        setMessage("인증서버  접속에  실패하였습니다.  관리자에  문의하십시요.");

                                in.close();

                              

                        }  else  {

                                //  인증서  클라이언트  PC에  저장

                                String  filePath  =  "C:/ACDPUPKIKEY";

                                File  file  =  new  File(filePath);

                                if(!file.exists()){

                                        file.mkdir();

                                }

                                ObjectInputStream  obin  =  new  ObjectInputStream(in);

                                PrivateKey  privatekey  =  (PrivateKey)obin.readObject();

                                ObjectOutputStream  out  =  new  ObjectOutputStream(new  FileOutputStream(new  File(file,userEnterText+"PRI.ser")));

                                out.writeObject(privatekey);

                                obin.close();

                                in.close();

                                out.close();

                                setMessage("인증키  발급이  성공되었습니다.  다음과  위치에  인증키가  저장되었습니다.");

                                setMessage(filePath+"/"+userEnterText+"PRI.ser");

                        }

                }  catch  (MalformedURLException  mfurle)  {

                        setMessage(mfurle.getMessage());

                }  catch  (IOException  ioe)  {

                        setMessage(ioe.getMessage());

                }  catch  (ClassNotFoundException  cnote)  {

                        setMessage(cnote.getMessage());

                }

        }

}

class  createPKIApplet_reset_actionAdapter  implements  ActionListener    {

        createPKIApplet  adaptee;

  

        createPKIApplet_reset_actionAdapter(createPKIApplet  adaptee)  {

                this.adaptee  =  adaptee;

        }

  

        public  void  actionPerformed(ActionEvent  e)  {

                adaptee.reset_actionPerformed(e);

        }

}

  

  

  

//  로그인  클라이언트

package  acdpu.pki.applet;

import  javax.swing.JApplet;

import  java.awt.Dimension;

import  java.awt.Toolkit;

import  java.awt.BorderLayout;

import  javax.swing.JFrame;

import  javax.swing.UIManager;

import  javax.swing.JLabel;

import  java.awt.Rectangle;

import  javax.swing.JPanel;

import  javax.swing.BorderFactory;

import  javax.swing.JScrollPane;

import  javax.swing.JTextPane;

import  javax.swing.JTextField;

import  javax.swing.JButton;

import  javax.swing.JPasswordField;

import  java.awt.event.ActionListener;

import  java.awt.event.ActionEvent;

import  java.net.*;

import  java.io.*;

import  java.security.*;

import  acdpu.pki.util.*;

  

public  class  loginPKIApplet  extends  JApplet    {

  

        //  객체  생성

        private  JLabel  topLabel  =  new  JLabel();    //  상단  라벨

        private  JScrollPane  messageScrollPane  =  new  JScrollPane();  //  하단  메시지창  스크롤

        private  JTextPane  messageTextPane  =  new  JTextPane();  //  하단  메시지창

        private  JTextField  userid  =  new  JTextField();  //  사용자  아이디  입력

        private  JPasswordField  passwd  =  new  JPasswordField();  //  사용자  암호  입력

        private  JButton  submit  =  new  JButton();  //  전송  버튼

        private  JButton  reset  =  new  JButton();    //  리셋

  

        public  loginPKIApplet()  {

        }

  

        public  void  init()  {

      

                try  {

                        jbInit();

                }  catch(Exception  e)  {

                        e.printStackTrace();

                }

        }

  

        private  void  jbInit()  throws  Exception  {

                this.getContentPane().setLayout(null);

                this.setSize(new  Dimension(524,  397));

  

                //  상단  라벨

                topLabel.setText("PKI  로그인");

                topLabel.setBounds(new  Rectangle(0,  0,  525,  30));

  

                //  사용자  아이디

                userid.setBounds(new  Rectangle(15,  35,  280,  65));

                userid.setBorder(BorderFactory.createTitledBorder("UserId"));

  

                //  사용자  암호

                passwd.setBounds(new  Rectangle(15,  115,  280,  60));

                passwd.setBorder(BorderFactory.createTitledBorder("PassWord"));

  

                //  전송  버튼

                submit.setText("로그인");

                submit.setBounds(new  Rectangle(85,  215,  125,  40));

                submit.addActionListener(new  ActionListener()  {

                                public  void  actionPerformed(ActionEvent  e)  {

                                        submit_actionPerformed(e);

                                }

                        });

  

                //  리렛  버튼

                reset.setText("재입력");

                reset.setBounds(new  Rectangle(305,  215,  125,  40));

                reset.addActionListener(new  loginPKIApplet_reset_actionAdapter(this));

  

                //  스크롤  상자

                messageScrollPane.setBounds(new  Rectangle(10,  290,  505,  80));

                messageScrollPane.setBorder(BorderFactory.createTitledBorder("Message"));

                messageScrollPane.setAutoscrolls(true);

  

                //  메시지  창

                messageTextPane.setText("사용자  아이디와  비밀번호를  입력하여  주십시요...");

                messageTextPane.setEditable(false);

                messageScrollPane.getViewport().add(messageTextPane,  null);

  

                this.getContentPane().add(passwd,  null);

                this.getContentPane().add(reset,  null);

                this.getContentPane().add(submit,  null);

                this.getContentPane().add(userid,  null);

                this.getContentPane().add(messageScrollPane,  null);

                this.getContentPane().add(topLabel,  null);

        }

  

        static      {

                try  {

                        //  UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

                        //  UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());

                }  catch(Exception  e)  {

                }

        }

  

        void  reset_actionPerformed(ActionEvent  e)  {

                userid.setText("");

                passwd.setText("");

                userid.setEditable(true);

                passwd.setEditable(true);

                setMessage("입력  창이  초기화  되었습니다.");

        }

  

        private  void  setMessage(String  message)  {

                messageTextPane.setText(messageTextPane.getText()+"\n"+message);

        }

  

        private  void  submit_actionPerformed(ActionEvent  e)  {

                userid.setEditable(false);

                passwd.setEditable(false);

                String  userEnterText  =  userid.getText();

                String  passEnterText  =  new  String(passwd.getPassword());

                setMessage("인증서버에  접속중입니다....  ");

  

                try{

                        URL  url  =  new  URL("http","218.145.231.120",7001,"/PKI/loginpki");

                        URLConnection  urlcon  =  url.openConnection();

                        urlcon.setDoInput(true);

                        urlcon.setDoOutput(true);

                        urlcon.setUseCaches(false);

  

                        String  privateKeyFile  =  "C:/ACDPUPKIKEY/"+userEnterText+"PRI.ser";

                        File  file  =  new  File(privateKeyFile);

                        byte[]  signningrow  =  null;

                        if(!file.exists()){

                                setMessage("인증서가  존재하지  않습니다.");

                                //System.exit(0);

                        }  else  {

                                setMessage("sign  데이터  생성중입니다.  ");

                                try  {

                                        Signature  signning  =  Signature.getInstance("DSA");

                                        ObjectInputStream  keyin  =  new  ObjectInputStream(new  FileInputStream(file));

                                        PrivateKey  privatekey  =  (PrivateKey)keyin.readObject();

                                        keyin.close();

                                        signning.initSign(privatekey);

                                        signning.update((userEnterText+passEnterText).getBytes());

                                        signningrow  =  signning.sign();

                                        BASE64Encoder  encoder  =  new  BASE64Encoder();

                                        String  base64Signning  =  encoder.encode(signningrow);

                                        urlcon.setRequestProperty("userid",userEnterText);

                                        urlcon.setRequestProperty("passwd",passEnterText);

                                        urlcon.setRequestProperty("signningdata",base64Signning);

                                        urlcon.connect();

  

                                        setMessage("sign  데이터를  전송중입니다....  ");

                                }  catch(NoSuchAlgorithmException  noalgoe)  {

                                        setMessage("signning  알고리즘이  없습니다.");

                                        //System.exit(0);

                                }  catch(ClassNotFoundException  cnotfe)  {

                                        setMessage("PC에  저장된  개인키를  생성할수  없습니다.");

                                        //System.exit(0);

                                }  catch(InvalidKeyException  inkeye)  {

                                        setMessage("부적합한  개인키를  소유하고  있습니다.");

                                        //System.exit(0);

                                }  catch(SignatureException  signe)  {

                                        setMessage("개인키  서명중  에러가  발생하였습니다.");

                                        //System.exit(0);

                                }

                        }

  

                        BufferedReader  inre  =  new  BufferedReader(new  InputStreamReader(urlcon.getInputStream()));

                        String  receiveMessage  =  inre.readLine();

  

  

                        if(receiveMessage.equals("0"))

                                setMessage("정상적으로  로그인  되었씁니다.");

                        else  if(receiveMessage.equals("1"))

                                setMessage("인증서가  구형이거나  정상적인  인증서가  아님니다.");

                        else  if(receiveMessage.equals("2"))

                                setMessage("사용자가  틀림니다.  아이디와  비밀번호를  확인해  주십시요.");

                        else  if(receiveMessage.equals("3"))

                                setMessage("사용기간이  지났거나  시작되지  않았습니다.");

                        else

                                setMessage("인증서버  접속에  실패하였습니다.  관리자에  문의하십시요.");

                        inre.close();

                }  catch  (MalformedURLException  mfurle)  {

                        setMessage(mfurle.getMessage());

                }  catch  (IOException  ioe)  {

                        setMessage(ioe.getMessage());

                }              

        }

}

class  loginPKIApplet_reset_actionAdapter  implements  ActionListener    {

        loginPKIApplet  adaptee;

  

        loginPKIApplet_reset_actionAdapter(loginPKIApplet  adaptee)  {

                this.adaptee  =  adaptee;

        }

  

        public  void  actionPerformed(ActionEvent  e)  {

                adaptee.reset_actionPerformed(e);

        }

}

  

  

  

//  인증서  생성  서버

package  acdpu.pki.servlet;

  

import  acdpu.pki.*;

import  acdpu.pki.exception.*;

import  javax.servlet.*;

import  javax.servlet.http.*;

import  java.io.*;

import  java.security.*;

  

public  class  createPKIServlet  extends  HttpServlet    {

  

        public  void  init(ServletConfig  config)  throws  ServletException  {

                super.init(config);

        }

  

        public  void  doGet(HttpServletRequest  request,  HttpServletResponse  response)  throws  ServletException,  IOException  {

                String  userid  =  request.getParameter("userid");

                String  passwd  =  request.getParameter("passwd");

                PKIController  pKIController  =  new  PKIController();

                try  {

                        PrivateKey  privatekey  =  pKIController.createKeyPair(userid,  passwd);

                        response.setContentType("application/octet-stream");

                        response.setHeader("Content-Disposition",  "attachment;  filename="+userid+"PRI.ser");

                        ObjectOutputStream  out  =  new  ObjectOutputStream(response.getOutputStream());

                        out.writeObject(privatekey);

                        out.close();                      

                }  catch  (PKICreateException  e)  {

                        System.err.println(e);

                        response.reset();

                        response.setContentType("text/html;euc-kr");

                        PrintWriter  out  =  new  PrintWriter(new  OutputStreamWriter(response.getOutputStream(),  "ksc5601"));

                        out.println("1");

                        out.close();

                }  catch  (IncorrectUserException  e)  {

                        System.err.println(e);

                        response.reset();

                        response.setContentType("text/html;euc-kr");

                        PrintWriter  out  =  new  PrintWriter(new  OutputStreamWriter(response.getOutputStream(),  "ksc5601"));

                        out.println("2");

                        out.close();

                }  catch  (TermExpirationException  e)  {

                        System.err.println(e);

                        response.reset();

                        response.setContentType("text/html;euc-kr");

                        PrintWriter  out  =  new  PrintWriter(new  OutputStreamWriter(response.getOutputStream(),  "ksc5601"));

                        out.println("3");

                        out.close();

                }  catch  (PKIDBHandlerException  e)  {

                        System.err.println(e);

                        response.reset();

                        response.setContentType("text/html;euc-kr");

                        PrintWriter  out  =  new  PrintWriter(new  OutputStreamWriter(response.getOutputStream(),  "ksc5601"));

                        out.println("4");

                        out.close();

                }

        }

}

  

  

  

//  로그인  검증  서버

package  acdpu.pki.servlet;

  

import  acdpu.pki.*;

import  acdpu.pki.exception.*;

import  javax.servlet.*;

import  javax.servlet.http.*;

import  java.io.*;

import  java.security.*;

import  java.util.*;

import  acdpu.pki.util.*;

  

public  class  loginPKIServlet  extends  HttpServlet    {

  

        public  void  init(ServletConfig  config)  throws  ServletException  {

                super.init(config);

        }

  

        public  void  doGet(HttpServletRequest  request,  HttpServletResponse  response)  throws  ServletException,  IOException  {

  

                response.setContentType("text/html;euc-kr");

                String  userid  =  request.getHeader("userid");

                String  passwd  =  request.getHeader("passwd");

                String  signningdata  =  request.getHeader("signningdata");

              

                PKIController  pKIController  =  new  PKIController();

                PrintWriter  out  =  new  PrintWriter(new  OutputStreamWriter(response.getOutputStream(),  "ksc5601"));

              

                BASE64Decoder  decoder  =  new  BASE64Decoder();

                byte[]  signature  =  decoder.decodeBuffer(signningdata);

                System.out.println(userid);

                System.out.println(passwd);

                System.out.println(signningdata);

  

                try  {

                        pKIController.loginPKI(userid,  passwd,  signature);

                        out.println("0");

                        out.close();

                }  catch  (PKIInvalidException  e)  {

                        System.err.println(e);

                        out.println("1");

                        out.close();

                }  catch  (IncorrectUserException  e)  {

                        System.err.println(e);

                        out.println("2");

                        out.close();

                }  catch  (TermExpirationException  e)  {

                        System.err.println(e);

                        out.println("3");

                        out.close();

                }  catch  (PKIDBHandlerException  e)  {

                        System.err.println(e);

                        out.println("4");

                        out.close();

                }

        }

}

  

  

  

//  데이터  인코딩  유틸

package  acdpu.pki.util;

  

public  class  Base64  {

    public  static  String  encode(byte[]  raw)  {

        StringBuffer  encoded  =  new  StringBuffer();

        for  (int  i  =  0;  i  <  raw.length;  i  +=  3)  {

            encoded.append(encodeBlock(raw,  i));

        }

        return  encoded.toString();

    }

  

    protected  static  char[]  encodeBlock(byte[]  raw,  int  offset)  {

        int  block  =  0;

        int  slack  =  raw.length  -  offset  -  1;

        int  end  =  (slack  >=  2)  ?  2  :  slack;

        for  (int  i  =  0;  i  <=  end;  i++)  {

            byte  b  =  raw[offset  +  i];

            int  neuter  =  (b  <  0)  ?  b  +  256  :  b;

            block  +=  neuter  <<  (8  *  (2  -  i));

        }

        char[]  base64  =  new  char[4];

        for  (int  i  =  0;  i  <  4;  i++)  {

            int  sixbit  =  (block  >>>  (6  *  (3  -  i)))  &  0x3f;

            base64[i]  =  getChar(sixbit);

        }

        if  (slack  <  1)  base64[2]  =  '=';

        if  (slack  <  2)  base64[3]  =  '=';

        return  base64;

    }

  

    protected  static  char  getChar(int  sixBit)  {

        if  (sixBit  >=  0  &&  sixBit  <=  25)

            return  (char)('A'  +  sixBit);

        if  (sixBit  >=  26  &&  sixBit  <=  51)

            return  (char)('a'  +  (sixBit  -  26));

        if  (sixBit  >=  52  &&  sixBit  <=  61)

            return  (char)('0'  +  (sixBit  -  52));

        if  (sixBit  ==  62)  return  '+';

        if  (sixBit  ==  63)  return  '/';

        return  '?';

    }

  

    public  static  byte[]  decode(String  base64)  {

        int  pad  =  0;

        for  (int  i  =  base64.length()  -  1;  base64.charAt(i)  ==  '=';  i--)

            pad++;

        int  length  =  base64.length()  *  6  /  8  -  pad;

        byte[]  raw  =  new  byte[length];

        int  rawIndex  =  0;

        for  (int  i  =  0;  i  <  base64.length();  i  +=  4)  {

            int  block  =  (getValue(base64.charAt(i))  <<  18)

                    +  (getValue(base64.charAt(i  +  1))  <<  12)

                    +  (getValue(base64.charAt(i  +  2))  <<  6)

                    +  (getValue(base64.charAt(i  +  3)));

            for  (int  j  =  0;  j  <  3  &&  rawIndex  +  j  <  raw.length;  j++)

                raw[rawIndex  +  j]  =  (byte)((block  >>  (8  *  (2  -  j)))  &  0xff);

            rawIndex  +=  3;

        }

        return  raw;

    }

  

    protected  static  int  getValue(char  c)  {

        if  (c  >=  'A'  &&  c  <=  'Z')  return  c  -  'A';

        if  (c  >=  'a'  &&  c  <=  'z')  return  c  -  'a'  +  26;

        if  (c  >=  '0'  &&  c  <=  '9')  return  c  -  '0'  +  52;

        if  (c  ==  '+')  return  62;

        if  (c  ==  '/')  return  63;

        if  (c  ==  '=')  return  0;

        return  -1;

    }

}

  

package  acdpu.pki.util;

  

public  class  BASE64Decoder  {

    public  byte[]  decodeBuffer(String  base64)  {

        return  Base64.decode(base64);

    }

}

  

package  acdpu.pki.util;

  

public  class  BASE64Encoder  {

    public  String  encode(byte[]  raw)  {

        return  Base64.encode(raw);

    }

}

  

  

  

  

chapter  7  암호화

l                  암호화의  종류

n                대칭  또는  개인키  :  암복호화에  하나의  개인키를  사용한다.

n                비대칭  또는  공개키  :  개인키로  암호화하고  공개키로  검증한다.

n                하이브리드(hybrid)  :  비대칭  암호는  소위  개인키를  교환하기  위해  사용된다.  개인키는  데이터  암호화  및  복호화를  위해  대칭  암호화와  함께  사용된다.

l                  대칭암호의  종류

n                블록  암호  :  고정된  크기의  데이터  블록을  암호화  하고  복호화한다.

n                스트림  암호  :  비트나  바이트의  스트림상에  작동한다.(블록암호화의  CFB모드  사용)

l                  Padding  :  데이터를  일정크기(64비트)로  나눈  후  마지막  불완전한  블록을  보정하는  것  일반적으로  PKCS#5를  일반적으로  사용한다.

l                  암호  모드

모    드


설    명


비    고

ECB


가장  단순  모든  동일한  평문은  동일한  암호문이  된다.


  

CBC


ECB의  단점보안  가장  일반적임


  

PCBC


CBC와  유사


  

CFBn


블록암호가  스트림처럼  동작하도록한다.


  

OFBn


CFB모드와  유사


  

  

사용예)

Cipher  cipher  =  Cipher.getInstance(“DES/ECB/PKCS5Padding”);

//알고리즘-블록암호화  알고리즘  &#8211;  패딩기법

  

  

Chapter  8  서명된  에플릿

  

1.  Microsoft  SDK  for  JAVA(http://www.microsoft.com/java/)를  다운  로드  한  후  설치한다.

  

2.  설치한  Microsoft  SDK  for  JAVA의  bin  디렉토리를  path에  설정해  준다.

예,  path  =  %path%;E:\Program  Files\Microsoft  SDK  for  Java  4.0\bin

  

3.  makecert  명령어를  사용하여  인증서를  생성한다.

                          makecert  -sk  [인증서  별명]  -n  "CN=[인증  이름]"  [인증서  화일명]

-.  공개키와  비밀키  쌍이  생성되어지고,  비밀키는  레지스트리에  저장된다.

-.  인증서가  주어진  파일명으로  생성된다.

예,  makecert  -sk  RayCertification  -n  "CN=Raytrust  Org."  RayCertification.cer

                          &#232;  RayCertification.cer  파일이  생성된다

  

makecert  명령어의  option  설명

·      -sk  "KeyName"
보관되어  있는  키  이름.
없을  경우  이  이름으로  레지스트리에  키를  생성한다.

·      -ss  "Store"
인증서의  보관소  명

·      -sr  "Location"
레지스트리  내의  인증서의  보관소  위치를  나타냄.
(  CurrentUser  |  LocalMachine  )  중  하나

·      -#  "Number"
1~130사이의  수.

·      -$  "Authority"
인증서를  발급한  기관  형태  (  individual  |  commercial  )  중  하나

·      -n  "X.509  name"
X.500의  구분되는  이름  (  예  :  CN=Chungnam  )

·      -?
기본  옵션의  목록  설명

·      -!
확장  옵션의  목록  설명

4.  java  코드에  sign을  할  때,  .spc  형식의  서명  파일이  필요하므로  cert2spc  명령을  사용하여  .cer  서명  파일에서  .spc  형식의  서명  파일을  만든다.

                          cert2spc  [인증서  화일명]  [.spc  화일]

예  >  cert2spc  RayCertification.cer  RayCertification.spc

                          &#232;  RayCertification.spc  파일이  생성된다.

  

5.  서명이  필요한  파일들을  dubuild  명령을  사용하여  cab  형식의  파일로  만든다.

                          dubuild  [.cab  파일]  [path]  /D  [“frindlyname”]  /I  [pattern]  /V  [version]

예  >  dubuild  SignedRayApplet.cab  .  /D  "RaySignTest"  /I  *.class  /V  1,1,1,1

                          &#232;  SignedRayApplet.cab  파일이  생성된다.

  

dubuild  명령어의  option  설명

n    /H  또는  /?
도움이  되는  텍스트를  보여준다.

n    /D  “friendlyname”
Distribution  Unit의  친근한  이름  설정  (  예  :  …  /D  “RaySignTest”  …)

n    /P  oldDUName.cab
이전  Distribution  Unit의  파일  이름.

n    /M
multi-CAB  Distribution  Unit을  만든다.

n    /I  {pattern}
{pattern}에  매칭되는  파일들을  포함한다.

n    /X  {pattern}
{pattern}에  매칭되는  파일들을  배제한다.

n    /N  “namespace”
Distribution  Unit의  namespace.

n    /B  {beaninfo}
각각의  bean에  대한  정보.

n    /V  {version}
기본적인  버전  숫자를  설정한다.  (  예:  ….  /V  1,1,1,1  …  )

n    /Z
IE  3.0과  호환  가능한  MSZIP  압축을  사용한다.

n    더  자세한  정보는  /H  또는  /?를  사용하여  확인하기  바란다.

  

  

6.  signcode  명령어를  사용하여  앞에서  만든  인증서를  cab  파일에  포함  시키고,  레지스트리의  비밀키로  서명을  한다.

                          signcode  -j  javasign.dll  -jp  [레벨]  -spc  [.spc  파일]  &#8211;k  [key  이름]  [.cab  파일]

예  >  signcode  -j  javasign.dll  -jp  LowX  -spc  RayCertification.spc  -k  RayCertification  SignedRayApplet.cab

                          &#232;  Sign된  SignedRayApplet.cab  파일이  된다.

  

signcode  명령어의  option  설명

n      -spc  "file"
SPC를  포함하는  파일명

n      -v  "pvkFile"
비밀키를  포함하고  있는  파일명

n      -k  "KeyName"
레지스트리  내의  키  이름

n      -n  "name"
사인할  내용에  대한  텍스트  이름

n      -l  "info"
사인할  내용에  대한  부가  설명이  있는  장소  (  예:  URL  )

n      -p  "provider"
시스템  내의  암호화  시스템  제공자  이름

n      -y  "type"
시스템  내의  암호화  시스템  제공자  형태

n      -ky  "keyType"
키의  종류  (  signature  |  exchange  |  정수  )  중  하나

n      -$  "authority"
인증서를  인증한  기관의  종류  (  individual  |  commercial  )  중  하나

n      -a  "algorithm"
사인에  이용된  해쉬  알고리즘.  (  md5  |  sha1  )  중  하나.  기본값  :  md5

n      -t  "URL"
타임스탬프를  찍어줄  서버의  HTTP주소

n      -tr  "number"
타임스탬프  서버  접속  실패시  재시도  횟수.  기본은  1회

n      -tw  "number"
타임스탬프간  간격  (초단위).  기본은  0초

n      -j  "dllName"
사인에  필요한  부가  특성들을  포함하는  DLL  파일명  (  예  :  보안  레벨  )

n      -jp  "param"
DLL파일에  넘길  파라미터

n      -c  "file"
인코딩된  SPC를  포함한  X.509파일명

n      -s  "Store"
인증서를  가지고  있는  인증서  보관소명  .  기본은  mystore

n      -r  "location"
레지스트리  내의  인증서  보관소의  위치  (  localMachine  |  currentUser  )중  하나.  기본은  currentUser

n      -sp  "policy"
인증서  검증에  필요한  모든  인증서를  포함할  것인가  아니면  SPC보관소에  들어있는  인증서가  나올  때까지  포함할  것인가에  대한  정책.  (  chain  |  spcstore  )중  하나.  기본은  spcstore

n      -cn  "name"
인증서  일반  이름  (별명)

n      -x
사인하지  말고  타임스탬프만  받을  것을  명시

7.  html  페이지에  다음과  같이  넣는다.

            <applet  code="org.raytrust.RayApplet.class"  width=320  height=270>

                <param  name=useslibrary  value='RaySignTest'>              

                <param  name=useslibraryversion  value='1,1,1,1'>

                <param  name=useslibrarycodebase  value='SignedRayApplet.cab'>

</applet>

        ****  주의!!!!  ****

위의  html  코드에서  음영으로  표시된  부분들은  적절하게  바꾸어줘야  한다.

첫번째의  경우  정확하게  사용한  패키지명을  적어주면  된다.

두번째의  경우  dubuild.exe  명령  사용시  /D  옵션으로  주었던  friendlyname과  일치해야  한다.

셋번째의  경우  dubuild.exe  명령  사용시  /V  옵션으로  주었던  version과  일치해야  한다.

네번째의  경우  dubuild.exe  명령  사용시  이용했던  cab  파일  이름과  일치해야  한다.

8.  위와  같이  하면,  클라이언트가  연결  되었을  때  윈도우가  뜨면서  인증할  것인지를  물어  봅니다.  여기서,  YES를  해주면  모든  권한을  가지게  된다.

    일부의  권한만을  주기  위해서는  프로그램  내부에서  다음과  같이  해  주면  된다.

  

if  (Class.forName("com.ms.security.PolicyEngine")!=null)  {

                              PolicyEngine.assertPermission(PermissionID.FILEIO);

}

    위의  예제  중에서  다음  부분에  여러  가지  권한들을  부여할  수  있다.

PolicyEngine.assertPermission(PermissionID.???????);

    ”???????”  부분은  다음과  같은  ID가  올  수  있습니다.

1.  SYSTEM
2.  FILEIO
3.  NETIO
4.  THREAD
5.  PROPERTY
6.  EXEC
7.  REFLECTION
8.  PRINTING
9.  SECURITY
10.  REGISTRY
11.  CLIENTSTORE
12.  UI
13.  SYSSTREAMS
14.  USERFILEIO
15.  MULTIMEDIA

  

l  배치  파일의  내용
1:  makecert  -sk  RayCertification  -n  "CN=Raytrust  Org."  RayCertification.cer
2:  cert2spc  RayCertification.cer  RayCertification.spc
3:  dubuild  SignedRayApplet.cab  .  /D  "RaySignTest"  /I  *.class  /V  1,1,1,1
4:  signcode  -j  javasign.dll  -jp  LowX  -spc  RayCertification.spc
-k  RayCertification  SignedRayApplet.cab


출처  :  http://capture.blog.theple.com/joeinfo/capture/all.html?uid=312

838 view

4.0 stars