전자서명

UP! 2015. 11. 5. 11:00

전자서명

 

     내용

가)    개인 키와 함께 생성된 메시지 다이제스트

나)    서명

 

다)    서명 검증

 

 

     목적

가)    무결성

     데이터에 대해서 바뀌지 않았다는 것을 증명

     데이터와 메시지 다이제스트 두 개를 다 바꿀 수 있음

     다이제스트를 개인키로 서명하면 이것은 불가능해 짐

나)    인증

     개인 키의 소유자만이 데이터에 서명할 수 있음

     키가 안전하다면 사용자가 실제로 서명했다는 것을 확신할 수 있음

 

     활용

가)    계약서에 서명

     1999 7월부터 전자서명법이 발효됨

     기존의 일반 종이문서에 사용되는 인감이나 서명과 같은 법적 효력을 갖게 됨

나)    이메일 서명

     S/MIME PGP를 사용해서 개인 키로 이메일을 서명할 수 있음

다)    타임서버 생성

     타임 스탬프는 데이터에 시간과 함께 서명해서 어떤 특정 시간에 정보가 존재했는지를 증명

라)    서버 승인

     요청에 서명을 하면 사용자가 서버가 특정한 개인 키를 가졌는지 확인 가능

 

     RSA vs. DSA

가)    RSA

     서명을 검증하는데 빠름

 

나)    DSA(Digital Signature Algorithm)

     RSA에서 서명하는 것과 비슷하지만 암호화 기능은 없음

     서명을 만드는데 빠름

 

     자바의 전자 서명

가)    java.security.Signature

     getInstance() : 알고리즘 이름을 인자로 해서 객체의 인스턴스 획득

     initSign() : 개인 키를 인자로 서명

     initVerify() : 공개 키를 인자로 검증

     update() : 데이터를 전달하여 서명/검증을 수행

     sign() : 전자서명을 반환

     verify() : 전자서명의 유효성을 반환

 

     간단한 전자서명 예제

import java.security.KeyPair;

import java.security.KeyPairGenerator;

import java.security.Signature;

import java.security.SignatureException;

 

import com.Ostermiller.util.Base64;

 

public class SignatureExample {

 

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

             //RSA 생성

             System.out.println("RSA 생성...");

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

             kpg.initialize(1024);

             KeyPair keyPair = kpg.genKeyPair();

             System.out.println("RSA 생성 완료");

            

             // 서명할 데이터

             byte[] data = "i love you.".getBytes("UTF-8");

            

             // 서명을 위해 Signatrue 객체 생성 개인 키로 초기화

             Signature sig = Signature.getInstance("MD5WithRSA");

             sig.initSign(keyPair.getPrivate());

             sig.update(data);

             // 실제 서명

             byte[] signaturedBytes = sig.sign();

             System.out.println("전자서명된 데이타 : " + Base64.encode(signaturedBytes));

            

             // 전자서명 검증

             sig.initVerify(keyPair.getPublic());

             sig.update(data);

             boolean verified = false;

             try {

                    verified = sig.verify(signaturedBytes);

             } catch (SignatureException e) {

                    verified = false;

                    System.out.println("전자서명 형식에 문제가 발생하였습니다.");

                    e.printStackTrace();

             }

            

             if(verified)

                    System.out.println("전자서명 검증 성공");

             else

                    System.out.println("전자서명 검증 실패");

 

       }

 

}

 

     전자 서명의 한계

가)    검증을 위해서 공개 키가 필요

나)    공개 키의 소유자를 확신하기가 힘듬

다)    전자 인증서로 문제 해결

 

Posted by 으랏차
,

MAC

UP!/Crypto 2015. 11. 5. 10:59

메시지 인증 코드(MAC)

 

     내용

가)    키가 있는 메시지 다이제스트

나)    안전하지 않은 네트워크를 통해 수신된 데이터를 인증할 때

다)    수신자와 송신자가 비밀 키를 교환하여 이 키를 이용하여 검증

라)    SSL에 많이 사용됨

마)    비밀 키를 공유해야 하는 것이 문제

바)    수신측에서 데이터 검증

사)    HMAC(Hashed Message Authentication Code)라 불리는 암호화 해쉬 함수에 기반

아)    Sun JCE에서 제공하는 HMAC 함수

     HmacMD5

     HmacSHA1

 

     사용방법

가)    javax.crypto.Mac

     Cipher MessageDigest가 합쳐진 것

 

나)    예제

import java.security.SecureRandom;

import javax.crypto.Mac;

import javax.crypto.spec.SecretKeySpec;

import com.Ostermiller.util.Base64;

 

public class MACExample {

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

             SecureRandom random = new SecureRandom();

             byte[] keyBytes = new byte[20];

             random.nextBytes(keyBytes);

             SecretKeySpec key = new SecretKeySpec(keyBytes, "HMACSHA1");

             System.out.println("Key: " + Base64.encode(key.getEncoded()));

             //Mac 인스턴스를 획득하고 초기화한다.

             Mac mac = Mac.getInstance("HmacSHA1");

             mac.init(key);

             mac.update("I LOVE YOU!".getBytes("UTF8"));

             byte[] result = mac.doFinal();

            

             System.out.println("MAC: " + Base64.encode(result));

       }

}

 

'UP! > Crypto' 카테고리의 다른 글

MessageDigest  (0) 2015.11.05
Session key  (0) 2015.11.05
대칭키 암호화  (0) 2015.11.05
패스워드 기반 암호화  (0) 2015.11.05
JCA, JCE  (0) 2015.11.05
Posted by 으랏차
,

MessageDigest

UP!/Crypto 2015. 11. 5. 10:58

자세한 내용을 알고 싶은 분은 다음의 블로그를 참조하세요

http://blog.naver.com/dury00?Redirect=Log&logNo=130044978311

 

     내용

가)    일종의 데이터 지문

나)    데이터가 바뀌지 않았다는 것을 증명

다)    데이터의 길이에 상관없이 보통 16 또는 20byte

라)    FTP파일 검증에 많이 사용

마)    해쉬를 이용

바)    한 방향 변환이고 역으로는 불가능

 

     자바에서의 메시지 다이제스트 사용

가)    java.security.MessageDigest

     getInstance()로 인자 생성

     MD5, SHA-1이 주로 사용됨

 

나)    update()

     데이터를 해쉬 함

 

다)    digest()

     바이트 배열로 해쉬를 반환

     적은 데이터일 경우 digest에 직접 입력 가능

 

라)    파일의 메시지 다이제스트 계산

import java.io.BufferedInputStream;

import java.io.FileInputStream;

import java.io.IOException;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

 

import com.Ostermiller.util.Base64;

 

public class DigestFile {

 

       public static void main(String[] args) throws NoSuchAlgorithmException, IOException {

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

             BufferedInputStream in = new BufferedInputStream(new FileInputStream("c:\\test.txt"));

            

             int theByte = 0;

             while((theByte = in.read()) != -1)

                    md.update((byte)theByte);

            

             in.close();

             byte[] theDigest = md.digest();

            

             System.out.println(Base64.encode(theDigest));

 

       }

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 마)    실행결과

     test.txt 파일에는 ‘this is a test file’이 들어 있음 : [B@1a758

     ‘this is a test file.’로 수정한 결과 : [B@1b67f74

 

바)    스트림에서의 메시지 다이제스트

     DigestInputStream & DigestOutputStream

MessageDigest messageDigest = MessageDigest.getInstance(“MD5”);

DigestOutputStream output = new

DigestOutputStream(existingOutputStream, messageDigest);

 

     출력에 쓰는 모든 바이트가 자동으로 메시지 다이제스트를 계산할 때 사용됨

     예제

import java.io.BufferedInputStream;

import java.io.FileInputStream;

import java.security.DigestInputStream;

import java.security.MessageDigest;

 

import com.Ostermiller.util.Base64;

 

public class DigestStreamExample {

 

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

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

             BufferedInputStream in = new BufferedInputStream(new FileInputStream("c:\\test.txt"));

            

             //DigestInputStream 생성한다.

             DigestInputStream digestIn = new DigestInputStream(in, md);

             // 모든 데이터를 읽어들인다.

             while(digestIn.read() != -1);

             byte[] theDigest = md.digest();

            

             System.out.println(Base64.encode(theDigest));

       }

}

 

 

     패스워드 인증

가)    의미

     패스워드를 해쉬하여 저장할 경우 복호화는 불가능하지만 모든 가능한 패스워드를 해쉬한 다음 비교해서 추즉하는게 가능함

     이런 공격을 막기 위해 salt와 패스워드를 같이 저장해야 함

     서버가 실제 패스워드를 알 필요 없이 사용자가 정한 패스워드를 검증하는게 목적

 

 

나)    패스워드 저장

     랜덤 salt 생성하여 패스워드 앞에 붙임

     이것을 해쉬함

     패스워드 입력될 때마다 비교를 위해 salt와 해쉬 결과를 붙여서 저장

 

 

다)    패스워드 인증

     저장된 패스워드의 salt와 사용자가 입력한 패스워드를 합친다.

     salt와 패스워드를 해쉬한다.

     결과 해쉬값을 파일에 저장된 것을 비교한다. 같다면 패스워드가 같은 것이다.

 

라)    예제

import java.io.ByteArrayOutputStream;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.security.MessageDigest;

import java.security.SecureRandom;

import java.util.Arrays;

 

public class Passwordauthenticator {

 

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

             createPassword("iloveyou");

             authenticatePassword("iloveyou");

 

       }

      

       private static void createPassword(String password) throws Exception {

             // salt 생성

             SecureRandom random = new SecureRandom();

             byte[] salt = new byte[12];

             random.nextBytes(salt);

            

             // salt 패스워드를 붙여서 해쉬한다.

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

             md.update(salt);

             md.update(password.getBytes("UTF-8"));

             byte[] digest = md.digest();

            

             // salt 해쉬 결과를 파일에 저장한다.

             FileOutputStream fos = new FileOutputStream("c:\\password.txt");

             fos.write(salt);

             fos.write(digest);

             fos.close();

       }

      

       private static void authenticatePassword(String password) throws Exception {

             // 파일을 읽어들인다.

             ByteArrayOutputStream baos = new ByteArrayOutputStream();

             FileInputStream fis = new FileInputStream("c:\\password.txt");

             int theByte = 0;

             while((theByte = fis.read()) != -1)

                    baos.write(theByte);

             fis.close();

             byte[] hashedPasswordWithSalt = baos.toByteArray();

             baos.reset();

            

             //salt 얻는다.

             byte[] salt = new byte[12];

             System.arraycopy(hashedPasswordWithSalt, 0, salt, 0, 12);

            

             // salt 입력한 패스워드를 붙여서 해쉬한다.

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

             md.update(salt);

             md.update(password.getBytes("UTF-8"));

              byte[] digest = md.digest();

            

             // 파일에 있는 내용과 비교한다.

             byte[] digestInFile = new byte[hashedPasswordWithSalt.length-12];

             System.arraycopy(hashedPasswordWithSalt, 12, digestInFile, 0, hashedPasswordWithSalt.length-12);

            

             if(Arrays.equals(digest, digestInFile))

                    System.out.println("Password matches.");

             else

                    System.out.println("Password does not matches.");

       }

}

 

'UP! > Crypto' 카테고리의 다른 글

MAC  (0) 2015.11.05
Session key  (0) 2015.11.05
대칭키 암호화  (0) 2015.11.05
패스워드 기반 암호화  (0) 2015.11.05
JCA, JCE  (0) 2015.11.05
Posted by 으랏차
,