오늘은 어디로 갈까...

전자서명(Digital Signature) 본문

낙서

전자서명(Digital Signature)

剛宇 2009. 3. 11. 11:31
 전자서명에 널리 이용되는 알고리즘은 DSA(Digital Signature Algorithm)과 RSA의 PKCS#7이다.
 DSA는 전자사명의 생성과 검증을 목적으로 만들어진 알고리즘으로서 이산대수문제(Discrete logarithm problem)를 수학적 기반으로 사용한다. 자세한 사항을 FIPS-186(http://www.itl.nist.gov/fipspubs/fip186.htm)를 참고하길 바란다.

 JDK 1.5에서 기본적으로 지원하는 Signature 알고리즘은, DSA (SHA1withDSA), MD5withRSA, MD5withRSA, SHA1withRSA, SHA256withRSA 등이 있다.
 Signature 클래스를 이용해서 해당 알고리즘에 맞는 인스턴스를 생성한 다음 사용하면 된다.

1. DSA로 전자서명하기.
package test.security;

import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;

import kr.kangwoo.util.ByteUtils;

public class SignatureTest {

	public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException, InvalidKeySpecException {
		String msg = "하늘에는 달이 없고, 땅에는 바람이 없습니다.\n사람들은 소리가 없고, 나는 마음이 없습니다.\n\n우주는 죽음인가요.\n인생은 잠인가요.";
		KeyPairGenerator generator = KeyPairGenerator.getInstance("DSA");
		KeyPair keyPair = generator.generateKeyPair();
		PublicKey publicKey = keyPair.getPublic();
		PrivateKey privateKey = keyPair.getPrivate();
		
		// 전자서명하기
		Signature signatureA = Signature.getInstance("DSA");
		signatureA.initSign(privateKey);
		signatureA.update(msg.getBytes());
		byte[] sign = signatureA.sign();
		System.out.println("signature : " + ByteUtils.toHexString(sign));
		
		// 전사서명 검증하기
		String msgB = msg;
		Signature signatureB = Signature.getInstance("DSA");
		signatureB.initVerify(publicKey);
		signatureB.update(msgB.getBytes());
		boolean verifty = signatureB.verify(sign);
		System.out.println("검증 결과 : " + verifty);
		
		// 전사서명 검증하기2		
		System.out.println(publicKey);
		KeyFactory keyFactory = KeyFactory.getInstance("DSA");
		// 같은 키에 대해서는 호환성이 있는 복수의 키 사양(Key Spec)이 존재한다.
		// 예를 들어, DSA 공개키는 DSAPublicKeySpec 또는 X509EncodedKeySpec을 사용할 수 있다는 뜻이다.
		// KeyFactory를 사용하면 호환성이 있는 키 사양(Key Spec)간에 변환을 할 수 있다.
		X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(publicKey.getEncoded());
		PublicKey publicKeyC = keyFactory.generatePublic(pubKeySpec);
		Signature signatureC = Signature.getInstance("DSA");
		signatureC.initVerify(publicKeyC);
		signatureC.update(msgB.getBytes());
		boolean veriftyC = signatureC.verify(sign);
		System.out.println("검증 결과 : " + veriftyC);
	}
}
* 실행 결과
signature : 302d02150093a2e47e2e4635ed88503784590bd5401d326eed021433a16be1e89ed22b75bac60d6e53835974424127
검증 결과 : true
Sun DSA Public Key
    Parameters:
    p:
    fd7f5381 1d751229 52df4a9c 2eece4e7 f611b752 3cef4400 c31e3f80 b6512669
    455d4022 51fb593d 8d58fabf c5f5ba30 f6cb9b55 6cd7813b 801d346f f26660b7
    6b9950a5 a49f9fe8 047b1022 c24fbba9 d7feb7c6 1bf83b57 e7c6a8a6 150f04fb
    83f6d3c5 1ec30235 54135a16 9132f675 f3ae2b61 d72aeff2 2203199d d14801c7
    q:
    9760508f 15230bcc b292b982 a2eb840b f0581cf5
    g:
    f7e1a085 d69b3dde cbbcab5c 36b857b9 7994afbb fa3aea82 f9574c0b 3d078267
    5159578e bad4594f e6710710 8180b449 167123e8 4c281613 b7cf0932 8cc8a6e1
    3c167a8b 547c8d28 e0a3ae1e 2bb3a675 916ea37f 0bfa2135 62f1fb62 7a01243b
    cca4f1be a8519089 a883dfe1 5ae59f06 928b665e 807b5525 64014c3b fecf492a

  y:
    9ae4887a 99d4dc2a 5386c9e8 f59256b6 d7697952 6f8368de 8ab95cf9 3c7a47f7
    a70f9364 15454183 e2428c71 7f97fb1c 8e7c8437 8b3c683d 98928ac5 bb5288e9
    77cfb31f 3635799f 724326cd 61506e55 ef1ffeea 96eb12de b904f669 8748b24e
    03f22969 8c5257c3 6c7b92c8 1aaaca6d 77900277 f3dfde43 ee42130e 4ff6c6cd

검증 결과 : true


2. RSA로 전자서명하기.
package test.security;

import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;

import kr.kangwoo.util.ByteUtils;
import sun.security.rsa.RSAPublicKeyImpl;

public class Signature2Test {

	public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException, InvalidKeySpecException {
		String msg = "하늘에는 달이 없고, 땅에는 바람이 없습니다.\n사람들은 소리가 없고, 나는 마음이 없습니다.\n\n우주는 죽음인가요.\n인생은 잠인가요.";
		KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
		KeyPair keyPair = generator.generateKeyPair();
		PublicKey publicKey = keyPair.getPublic();
		PrivateKey privateKey = keyPair.getPrivate();
		
		// 전자서명하기
		Signature signatureA = Signature.getInstance("SHA1withRSA");
		signatureA.initSign(privateKey);
		signatureA.update(msg.getBytes());
		byte[] sign = signatureA.sign();
		System.out.println("signature : " + ByteUtils.toHexString(sign));
		
		// 전사서명 검증하기
		String msgB = msg;
		Signature signatureB = Signature.getInstance("SHA1withRSA");
		signatureB.initVerify(publicKey);
		signatureB.update(msgB.getBytes());
		boolean verifty = signatureB.verify(sign);
		System.out.println("검증 결과 : " + verifty);
		
		// 전사서명 검증하기2		
		System.out.println(publicKey);
		RSAPublicKeyImpl rs = (RSAPublicKeyImpl)publicKey;
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PublicKey publicKeyC = keyFactory.generatePublic(new RSAPublicKeySpec(rs.getModulus(), rs.getPublicExponent()));
		Signature signatureC = Signature.getInstance("SHA1withRSA");
		signatureC.initVerify(publicKeyC);
		signatureC.update(msgB.getBytes());
		boolean veriftyC = signatureC.verify(sign);
		System.out.println("검증 결과 : " + veriftyC);
	}
}

* 실행결과
signature : 2a13fc892a7ae81d6def321955c772b76c0a69e4a85424627501f74e037b51e3601fc5e3943b1ce613ecba10186cffeb584857226627d745c86b34fe2a0dbdfd9f3872c1d5a08aafda851702d2652b2700ff705c1d90d218dcfaaed1899f56988bf8f3604c2c3c021abe6a7786b5212672fae6d0370a2619c40bd4b9ad45759c
검증 결과 : true
Sun RSA public key, 1024 bits
  modulus: 101452672405991007698085419191191735382952571083850266302971252953379246398252730591189132623596629498255271443121685046493750818971037666864872413890115776970919072293064144348538123580726746517732460757267148703775960571728334692408691211401575966591168055144314780327768496785758943824393831694299537281171
  public exponent: 65537
검증 결과 : true



-----------------------------------------------------------------------------------------------------------------
생뚱맞게 시나 한편 을퍼보자~
-----------------------------------------------------------------------------------------------------------------

고적한 밤

                  한용운

하늘에는 달이 없고 땅에는 바람이 없습니다
사람들은 소리가 없고 나는 마음이 없습니다

우주는 죽음인가요
인생은 잠인가요

한 가닥은 눈썹에 걸치고 한 가닥은 작은 별에 걸쳤던 님
생각의 금실은 살살살 걷힙니다
한 손에는 황금의 탈을 들고 한 손으로 천국의 꽃을 꺾던
환상의 여왕도 그림자를 감추었습니다
아아 님 생각의 금실과 환상의 여왕이 두 손을 마주잡고
눈물의 속에서 정사(情死)한 줄이야 누가 알아요

우주는 죽임인가요
인생은 눈물인가요
인생이 눈물이면
죽음은 사랑인가요