반응형

 

출처 : http://blog.kangwoo.kr/49

인터넷 뱅킹을 하시는 분이라면 대부분 공인인증서를 가지고 있다. 이 공인인증서를 가지고 전자서명을 해보도록하자(전혀 쓸데없는 일이긴 하다 ^^;)
필자의 경우 yessign에서 발급한 은행용 공인인증서를 가지고 있는데 그 경로는 C:\NPKI\yessign\USER\아래폴더... 에 위치해 있다.
그 디렉토리에 보면 CaPubs, signCert.der, signPri.key 세 파일이 존재한다.
CaPubs은 무슨 파일인지 잘 모르겠다. signCert.der는 공인 인증서 파일이고, signPri.key는 개인키 파일이다.
(der은 인증서 저장시 바이너르 형태로 저장하기 위한 포맷이고, pem은 문자열로 표현가능한 데이터로 인코딩(BASE64같은..)한 포맷이다.)
한국정보보호진흥원(http://www.rootca.or.kr/kcac.html)의 기술규격을 참조해보면, 현재 사용하는 공인인증서는 RFC3280을 준수하여, 전자서명인증체계에서 사용하는 정수2를 갖는 X.509 v3을 사용하고 있다고 한다.

1. 공개키 가져오기.
- 자바에서 X.590를 지원해주니 간단히 사용해보자.

01 package test.security;
02
03 import java.io.File;
04 import java.io.FileInputStream;
05 import java.io.IOException;
06 import java.security.cert.CertificateFactory;
07 import java.security.cert.X509Certificate;
08
09 public class CertificateTest1 {
10
11 public static void main(String[] args) throws Exception {
12 X509Certificate cert = null;
13 FileInputStream fis = null;
14 try {
15 fis = new FileInputStream(new File("C:/signCert.der"));
16 CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
17 cert = (X509Certificate) certificateFactory.generateCertificate(fis);
18 } finally {
19 if (fis != null) try {fis.close();} catch(IOException ie) {}
20 }
21 System.out.println(cert);
22 System.out.println("-----------------");
23 System.out.println(cert.getPublicKey());
24 }
25 }

실행해보면 아래처럼 인증서에 대한 정보를 볼 수 있을것이다.(보안 관계상 많은 부분을 생략하겠다.)

[
[
Version: V3
Subject: CN=누굴까(RangWoo)0000000000000000, OU=XXX, OU=personalXXX, O=yessign, C=kr
Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5

Key: Sun RSA public key, 1024 bits
... 생략 ...
[7]: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
[accessMethod: 1.3.6.1.5.5.7.48.1
accessLocation: URIName: http://ocsp.yessign.org:4612]
]
... 생략 ...
Sun RSA public key, 1024 bits
modulus: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
public exponent: 00000

당연히, V3 버젼을 사용하고 서명 알고리즘은 SHA1withRSA을 사용한다. SHA1withRSA 옆에 보면 OID란 놈이 있다.
OID란 Object IDentifier의 약어로서 객체식별체계정도로 이해하면 되겠다. 즉, OID의 값이 1.2.840.113549.1.1.5이면 SHA1withRSA란 의미이다.
http://www.oid-info.com/ 사이트에 가서 1.2.840.113549.1.1.5 값을 입력하면 아래와 같은 값을 얻을 수 있다.

그리고 중간쯤에 ocsp(Online Certificate Status Protocol)라고 실시간으로 인증서 유효성 검증을 할수 있는 정보도 나온다.
좀더 내려가보면 공개키부분이 나오는데, 이놈이 우리가 사용할 부분이다. cert.getPublicKey() 메소드를 이용하면 직접 공개키를 가져올 수 있다.

2. 개인키 가져오기
- 공개키는 거의 날로 먹었는데, 개인키란 놈은 만만하지가 않다.
- 기본적으로(?)는 PKCS#8를 이용해서 개인키를 저장하는데, 국내 공인인증서에 사용하는 개인키 파일는 암호화(?)해서 저장한다.
PKCS#5(Password-Based Cryptography Standard)의 PBKDF1(Password-Based Key Derivation Function), PBES1(Password-Based Encryption Scheme)를 이용한다는 것이다.
여기까지는 별 문제가 없는데, 데이터 암호화를 할때 국내에서만 사용하는 SEED란 블럭암호화 알고리즘를 사용한다는것이다.
즉, 기본적으로 제공이 안되므로 직접 구현을 해야한다.
뭔소리인지 이해가 안가면 한국정보보호진흥원(http://www.rootca.or.kr/)의 암호 알고리즘 규격(KCAC.TS.ENC)를 한번 읽어보자. (사실 읽어봐도 이해가 안가지만... ^^;)
간단히 설명을 하자면, PBES(Password-Based Encryption Scheme) 즉 패스워드 기반의 키 암호화 기법을 사용하겠다는 것이다. 암호화 할때 필요한게 비밀키이다. 이 키는 해당 알고리즘에 맞는 바이트 배열로 보통 사용을 하는데, 이것을 사람이 쉽게 인식할 수 있는 패스워드로 사용하겠다는것이다.
뭐 필자처럼 무식하게 "hello123".getBytes(); 를 사용해서 키로 사용할 수 있지만, 모양새가 안좋아보인다는것이다. 그래서 "hello123" 문자열을 가공해서 멋진(?) 키로 만들어 사용한다는 것이다.
이 가공하는 함수가 PBKDF(Password-Based Key Derivation Function)이다. 그리고 이 함수를 이용해서 비밀키를 생성해서 암호화/복화하는 하는 구조를 PBES라고 한다.
자바에서 기본적으로 "PBEWithMD5AndDES", "PBEWithSHA1AndDESede" 등의 알고리즘을 제공해준다.
Security.getProviders(); 메소드를 이용해서, Provider 정보를 출력해보면 지원하는 알고리즘을 알 수 있다.
01 package test.security;
02
03 import java.security.Provider;
04 import java.security.Security;
05
06 public class ProviderInfo {
07
08 public static void main(String[] args) {
09 Provider[] providers = Security.getProviders();
10 for (int i = 0; i < providers.length; i++) {
11 String name = providers[i].getName();
12 String info = providers[i].getInfo();
13 double version = providers[i].getVersion();
14 System.out.println("--------------------------------------------------");
15 System.out.println("name: " + name);
16 System.out.println("info: " + info);
17 System.out.println("version: " + version);
18
19 for (Object key : providers[i].keySet()) {
20 System.out.println(key + "\t"+ providers[i].getProperty((String)key));
21 }
22 }
23 }
24 }

그런데 불행히도 "PBEWithSHA1AndSeed"같은 알고리즘은 없는거 같다. 어떻게 해야할까? 당연히 삽~을 들어야한다.(아~~ 또 무덤을 파는구나 ㅠㅠ)
일단 파일의 구조를 파악해서 필요한 정보를 읽어와야한다.(ASN. 1으로 인코딩되어있다.)
다행히도 PKCS#8로 정의하고 있는 구조를 읽을 수 있는 EncryptedPrivateKeyInfo 클래스가 존재해서 한결 쉽게 작업을 할 수 있다
EncryptedPrivateKeyInfo 클래스를 사용해서 정보를 읽어오자. 사용하는 알고리즘을 출력해 보자.
01 // 1. 개인키 파일 읽어오기
02 byte[] encodedKey = null;
03 FileInputStream fis = null;
04 ByteArrayOutputStream bos = null;
05 try {
06 fis = new FileInputStream(new File("C:/signPri.key"));
07 bos = new ByteArrayOutputStream();
08 byte[] buffer = new byte[1024];
09 int read = -1;
10 while ((read = fis.read(buffer)) != -1) {
11 bos.write(buffer, 0, read);
12 }
13 encodedKey = bos.toByteArray();
14 } finally {
15 if (bos != null) try {bos.close();} catch(IOException ie) {}
16 if (fis != null) try {fis.close();} catch(IOException ie) {}
17 }
18
19 System.out.println("EncodedKey : " + ByteUtils.toHexString(encodedKey));
20
21 // 2. 개인카 파일 분석하기
22 EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = new EncryptedPrivateKeyInfo(encodedKey);
23 System.out.println(encryptedPrivateKeyInfo);
24 System.out.println(encryptedPrivateKeyInfo.getAlgName());

필자의 경우 "1.2.410.200004.1.15"란 값을 얻을 수 있었다. 나머지 파라메터 정보는 불행히도 제공을 안해줘서 직접 처리해야한다.
"1.2.410.200004.1.15" 어디서 많이 본 형식이다. 그렇다. OID이다. 사이트(http://www.oid-info.com/)가서 조회를 해보자.
"Key Generation with SHA1 and Encryption with SEED CBC mode" 란다.

한국정보보호진흥원(http://www.rootca.or.kr/)의 암호 알고리즘 규격(KCAC.TS.ENC)에서도 해당 OID에 대한 정보를 알 수 있다.

즉, 두 번째 방법이라는 것인데, DK의 값을 이용해서 해쉬값을 만든다음 그 값을 IV(초기화 벡터)로 사용하라는 것이다.
여기서 DK란 PBKDF를 사용해서 만든 추출키를 의미한다. 그렇다면 먼저 추출키를 만들어보자.

위의 설명대로 해당 함수를 구현해보자.
salt와 iteration count가 필요하다.
salt는 공인인증서를 발급할때마다 랜덤하게 생성되는것으로, 블특정다수의 사전(Dictionary) 공격을 방지하는 역할을 한다.(21-28바이트 사이의 8바이트를 사용함)
iteration count는 비밀키 생성을 위해 해쉬함수를 몇번 반복할 것인가를 나타낸다. (31-32바이트 사이의 2바이트를 사용함)
1 byte[] salt = new byte[8];
2 System.arraycopy(encodedKey, 20, salt, 0, 8);
3 System.out.println("salt : " + ByteUtils.toHexString(salt));
4 byte[] cBytes = new byte[4];
5 System.arraycopy(encodedKey, 30, cBytes, 2, 2);
6 int iterationCount = ByteUtils.toInt(cBytes);
7 System.out.println("iterationCount : " + ByteUtils.toHexString(cBytes));
8 System.out.println("iterationCount : " + iterationCount);

그럼 PBKDF1을 구현해보자. RFC2898(http://www.ietf.org/rfc/rfc2898.txt)을 보면 아래처럼 설명이 나와있다.
5.1 PBKDF1

   PBKDF1 applies a hash function, which shall be MD2 [6], MD5 [19] or
   SHA-1 [18], to derive keys. The length of the derived key is bounded
   by the length of the hash function output, which is 16 octets for MD2
   and MD5 and 20 octets for SHA-1. PBKDF1 is compatible with the key
   derivation process in PKCS #5 v1.5.

   PBKDF1 is recommended only for compatibility with existing
   applications since the keys it produces may not be large enough for
   some applications.

   PBKDF1 (P, S, c, dkLen)

   Options:        Hash       underlying hash function

   Input:          P          password, an octet string
                   S          salt, an eight-octet string
                   c          iteration count, a positive integer
                   dkLen      intended length in octets of derived key,
                              a positive integer, at most 16 for MD2 or
                              MD5 and 20 for SHA-1

   Output:         DK         derived key, a dkLen-octet string

   Steps:

      1. If dkLen > 16 for MD2 and MD5, or dkLen > 20 for SHA-1, output
         "derived key too long" and stop.

      2. Apply the underlying hash function Hash for c iterations to the
         concatenation of the password P and the salt S, then extract
         the first dkLen octets to produce a derived key DK:

                   T_1 = Hash (P || S) ,
                   T_2 = Hash (T_1) ,
                   ...
                   T_c = Hash (T_{c-1}) ,
                   DK = Tc<0..dkLen-1>

      3. Output the derived key DK.
설명대로 구현해주자. 피곤한 관계상 SHA1을 사용해서 20바이트의 추출키만을 반환하도록 만들었다.
01 public static byte[] pbkdf1(String password, byte[] salt, int iterationCount) throws NoSuchAlgorithmException {
02 byte[] dk = new byte[20];
03 MessageDigest md = MessageDigest.getInstance("SHA1");
04 md.update(password.getBytes());
05 md.update(salt);
06 dk = md.digest();
07 for (int i = 1; i < iterationCount; i++) {
08 dk = md.digest(dk);
09 }
10 return dk;
11 }
12 }

해당 함수를 사용해서 추출키(DK) 초기화 벡터(IV)를 만들어 보자.
01 String password = "password";
02
03 // 추출키(DK) 생성
04 byte[] dk = pbkdf1(password, salt, iterationCount);
05 System.out.println("dk : " + ByteUtils.toHexString(dk));
06
07 // 생성된 추출키(DK)에서 처음 16바이트를 암호화 키(K)로 정의한다.
08 byte[] keyData = new byte[16];
09 System.arraycopy(dk, 0, keyData, 0, 16);
10
11 // 추출키(DK)에서 암호화 키(K)를 제외한 나머지 4바이트를 SHA-1
12 // 으로 해쉬하여 20바이트의 값(DIV)을 생성하고, 그 중 처음 16바이트를 초기
13 // 벡터(IV)로 정의한다.
14 byte[] div = new byte[20];
15 byte[] tmp4Bytes = new byte[4];
16 System.arraycopy(dk, 16, tmp4Bytes, 0, 4);
17 div = SHA1Utils.getHash(tmp4Bytes);
18 System.out.println("div : " + ByteUtils.toHexString(div));
19 byte[] iv = new byte[16];
20 System.arraycopy(div, 0, iv, 0, 16);
21 System.out.println("iv : " + ByteUtils.toHexString(iv));

당연히 password 변수에는 공인인증서 암호를 입력해야한다. 안그러면 에러가 난다.
이제 고지가 눈앞에 보인다. 남은것은 SEED를 이용해서 복화만 하면 되는것이다. SEED 구현 + CBC 운용모드 구현을 직접하려면 정신적인 데미지가 커질 수 있으므로, 만들어놓은것을 가져다 쓰겠다.
Bouncy Castle Crypto APIs(http://www.bouncycastle.org/)를 감사하는 마음으로 가져다 쓰자.
%JAVA_HOME%/jre/lib/ext에 해당 jar파일을 복사한 다음, %JAVA_HOME%/jre/lib/security/java.security 파일에
security.provider.7=org.bouncycastle.jce.provider.BouncyCastleProvider
을 추가해서 사용할 수 있지만, 귀찮은 관계로 그냥(?) 사용하겠다.
1 // 3. SEED로 복호화하기
2 BouncyCastleProvider provider = new BouncyCastleProvider();
3 Cipher cipher = Cipher.getInstance("SEED/CBC/PKCS5Padding", provider);
4 Key key = new SecretKeySpec(keyData, "SEED");
5 cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
6 byte[] output = cipher.doFinal(encryptedPrivateKeyInfo.getEncryptedData());

이젠 해당 데이터로 개인키를 생성만 해주면 된다.
1 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(output);
2 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
3 RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey)keyFactory.generatePrivate(keySpec);
4 System.out.println(privateKey);
패스워드를 일치여부는 PBES에서 정의한 패딩이 존재하는지 여부로 판단한다. 만약 잘못된 패스워드라면
Exception in thread "main" javax.crypto.BadPaddingException: pad block corrupted
같은 에러가 발생할것이다.


그럼 마지막으로 공인인증서의 공개키와 개인키를 가지고 어제 해본 전자서명을 한번 해보자.
001 package test.security;
002
003 import java.io.ByteArrayOutputStream;
004 import java.io.File;
005 import java.io.FileInputStream;
006 import java.io.IOException;
007 import java.security.Key;
008 import java.security.KeyFactory;
009 import java.security.MessageDigest;
010 import java.security.NoSuchAlgorithmException;
011 import java.security.PrivateKey;
012 import java.security.PublicKey;
013 import java.security.Signature;
014 import java.security.cert.CertificateFactory;
015 import java.security.cert.X509Certificate;
016 import java.security.interfaces.RSAPrivateCrtKey;
017 import java.security.spec.PKCS8EncodedKeySpec;
018
019 import javax.crypto.Cipher;
020 import javax.crypto.EncryptedPrivateKeyInfo;
021 import javax.crypto.spec.IvParameterSpec;
022 import javax.crypto.spec.SecretKeySpec;
023
024 import kr.kangwoo.util.ByteUtils;
025
026 import org.bouncycastle.jce.provider.BouncyCastleProvider;
027
028 import com.jarusoft.util.security.SHA1Utils;
029
030 public class CertificateTest {
031
032 public static void main(String[] args) throws Exception {
033 String msg = "하늘에는 달이 없고, 땅에는 바람이 없습니다.\n사람들은 소리가 없고, 나는 마음이 없습니다.\n\n우주는 죽음인가요.\n인생은 잠인가요.";
034 PublicKey publicKey = getPublicKey("C:/signCert.der");
035 PrivateKey privateKey = getPrivateKey("C:/signPri.key");
036
037 // 전자서명하기
038 Signature signatureA = Signature.getInstance("SHA1withRSA");
039 signatureA.initSign(privateKey);
040 signatureA.update(msg.getBytes());
041 byte[] sign = signatureA.sign();
042 System.out.println("signature : " + ByteUtils.toHexString(sign));
043
044 // 전사서명 검증하기
045 String msgB = msg;
046 Signature signatureB = Signature.getInstance("SHA1withRSA");
047 signatureB.initVerify(publicKey);
048 signatureB.update(msgB.getBytes());
049 boolean verifty = signatureB.verify(sign);
050 System.out.println("검증 결과 : " + verifty);
051 }
052
053 public static PublicKey getPublicKey(String file) throws Exception {
054 X509Certificate cert = null;
055 FileInputStream fis = null;
056 try {
057 fis = new FileInputStream(new File(file));
058 CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
059 cert = (X509Certificate) certificateFactory.generateCertificate(fis);
060 } finally {
061 if (fis != null) try {fis.close();} catch(IOException ie) {}
062 }
063 System.out.println(cert.getPublicKey());
064 return cert.getPublicKey();
065 }
066
067 public static PrivateKey getPrivateKey(String file) throws Exception {
068 // 1. 개인키 파일 읽어오기
069 byte[] encodedKey = null;
070 FileInputStream fis = null;
071 ByteArrayOutputStream bos = null;
072 try {
073 fis = new FileInputStream(new File(file));
074 bos = new ByteArrayOutputStream();
075 byte[] buffer = new byte[1024];
076 int read = -1;
077 while ((read = fis.read(buffer)) != -1) {
078 bos.write(buffer, 0, read);
079 }
080 encodedKey = bos.toByteArray();
081 } finally {
082 if (bos != null) try {bos.close();} catch(IOException ie) {}
083 if (fis != null) try {fis.close();} catch(IOException ie) {}
084 }
085
086 System.out.println("EncodedKey : " + ByteUtils.toHexString(encodedKey));
087
088 // 2. 개인카 파일 분석하기
089 EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = new EncryptedPrivateKeyInfo(encodedKey);
090 System.out.println(encryptedPrivateKeyInfo);
091 System.out.println(encryptedPrivateKeyInfo.getAlgName());
092
093 byte[] salt = new byte[8];
094 System.arraycopy(encodedKey, 20, salt, 0, 8);
095 System.out.println("salt : " + ByteUtils.toHexString(salt));
096 byte[] cBytes = new byte[4];
097 System.arraycopy(encodedKey, 30, cBytes, 2, 2);
098 int iterationCount = ByteUtils.toInt(cBytes);
099 System.out.println("iterationCount : " + ByteUtils.toHexString(cBytes));
100 System.out.println("iterationCount : " + iterationCount);
101
102
103 String password = "password";
104
105 // 추출키(DK) 생성
106 byte[] dk = pbkdf1(password, salt, iterationCount);
107 System.out.println("dk : " + ByteUtils.toHexString(dk));
108
109 // 생성된 추출키(DK)에서 처음 16바이트를 암호화 키(K)로 정의한다.
110 byte[] keyData = new byte[16];
111 System.arraycopy(dk, 0, keyData, 0, 16);
112
113 // 추출키(DK)에서 암호화 키(K)를 제외한 나머지 4바이트를 SHA-1
114 // 으로 해쉬하여 20바이트의 값(DIV)을 생성하고, 그 중 처음 16바이트를 초기
115 // 벡터(IV)로 정의한다.
116 byte[] div = new byte[20];
117 byte[] tmp4Bytes = new byte[4];
118 System.arraycopy(dk, 16, tmp4Bytes, 0, 4);
119 div = SHA1Utils.getHash(tmp4Bytes);
120 System.out.println("div : " + ByteUtils.toHexString(div));
121 byte[] iv = new byte[16];
122 System.arraycopy(div, 0, iv, 0, 16);
123 System.out.println("iv : " + ByteUtils.toHexString(iv));
124
125 // 3. SEED로 복호화하기
126 BouncyCastleProvider provider = new BouncyCastleProvider();
127 Cipher cipher = Cipher.getInstance("SEED/CBC/PKCS5Padding", provider);
128 Key key = new SecretKeySpec(keyData, "SEED");
129 cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
130 byte[] output = cipher.doFinal(encryptedPrivateKeyInfo.getEncryptedData());
131
132 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(output);
133 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
134 RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey)keyFactory.generatePrivate(keySpec);
135 System.out.println(privateKey);
136 return privateKey;
137
138 }
139
140 public static byte[] pbkdf1(String password, byte[] salt, int iterationCount) throws NoSuchAlgorithmException {
141 byte[] dk = new byte[20]; // 생성이 의미가 없지만 한눈에 알아보라고 20바이트로 초기화
142 MessageDigest md = MessageDigest.getInstance("SHA1");
143 md.update(password.getBytes());
144 md.update(salt);
145 dk = md.digest();
146 for (int i = 1; i < iterationCount; i++) {
147 dk = md.digest(dk);
148 }
149 return dk;
150 }
151 }



반응형
반응형

사업을 정확하게 하기 위해서는 배달된 소포에 사인을 한다든지 손목과 서류 가방에 수갑을 채우든지 해야 할 것 같다. 어떤 식으로든 정보 교환에 안전이 보장되어야 한다. PDF 문서도 다를 바가 없다.

이 책에서는 많은 장에 걸쳐서, 프로젝트의 일부분으로 참가자가 검토 회람 및 옵션에 참가하는 방법을 설명했다. 그러나 이번 장에서는 전체를 할애해서 정보를 수집하고 분류하며 교환할 때마다 디지털 서명을 사용하는 방법에 대해서 알아볼 것이다. 또한 애크로뱃으로 표준적인 검토를 수행할 수도 있지만, PDF 패키지와 사용자가 만든 표지를 이용해서 사인 및 배포 과정을 관리하는 방법도 알아볼 것이다.




서명 요망

레인 크로리는 금융회사인 바버블랙 사의 문서 관리자다. 에린은 지점과 본점에서 주고받는 문서의 수발 업무를 맡고 있다. 법률과 사규에 따라, 수기로 서명한 지점의 영업 보고서는 매 주마다 인편으로 본점에 도착되어야 한다.

송달비는 사업 비용으로 처리되기는 하지만, 전달된 서명 문서는 방정식처럼 일치해야 한다. 보고서가 에린에게 전달되면, 줄줄이 원본 파일과 비교해야 한다. 여러 장 복사한 문서들은 서명을 위해서 배포하고 다시 이를 수집한 후에 보관해야 한다.
에린은 이런 일들이 복잡할 뿐만 아니라 인력 및 비용이 너무 많이 들기 때문에 애크로뱃 8프로페셔널을 이용하면 상당 부분을 효율적으로 처리할 수 있다고 생각한다.

지점과 본점의 주요 직원들은 최근 애크로뱃 8 프로페셔널로 업그레이드 되었다. 이 프로그 램을 이용하면 어도비 리더에서도 검토 문서를 사용하고 회람할 수 있다.



프로젝트의 진행 과정

에린은 지점 대표들이 디지털 서명을 이용해서 자료를 확인한 다음 전자 메일로 전달할 수 있는 시스템을 만들 계획이다. 판매 보고서는 PDF 패지로 묶고, 서명 필드가 포함된 표지를 추가한 다음 확인을 거쳐서 배포하고 서명을 받을 것이다. <그림 12-1>
에린의 팀이 이러한 프로젝트를 완수하기 위해 수행해야 할 일은 다음과 같다.
  • 원본 파일이 포함된 영업 보고서를 PDF 문서로 만드는 방법을 지점 직원들에게 교육한다.
  • 문서에 서명하고 전자 메일을 발송한다.
  • PDF 패키지에 승인 절차를 밟기 위한 표지를 만든다.
  • 문서에 서명 필드 및 지시사항, 전자 메일 링크를 추가한다.
  • 원본 파일의 서명을 침해하지 않는 범위 내에서 제출 문서로부터 PDF 패키지를 만든다.
  • 패키지 문서의 정확성을 검사한다.
  • 승인 과정을 거친다.


<그림 12-1 > 애크로뱃 기능을 이용하면 서명과 같은 문서 콘텐트를 관리할 수 있다.



PDF 보고서 준비하기


바버 블랙의 모든 지점은 엑셀 스프레드시트로 영업 정보 등의 데이터를 관리한다. 에린은 사내 교육을 통해서 지점 직원들이 애크로뱃 8 프로페셔널에 대해서 학습하고 있으므로 지 점 관리자들이 판매 수치를 PDF 버전으로 만들 수 있다는 사실을 알고 있다.

DOWNLOAD : http://www.donnabaker.ca/downloads.html
원본 엑셀 스프레드시트로 시작하려면 베이커 웹사이트에서 tsharp0906.xls, redwards0906.xls를 다운로드 한다 . 변환된 스프레드시 트 인 tsharp0906.pdf, redwards0906.pdf도 다운로드 할 수 있다.



변환 설정 선택하기


에린에게는 프로젝트를 도와줄 지역 담당자들이 두 명 더 있다. 솔트 레이크 시티의 타니스 샤프, 신시네티의 론 에드워드가 그들이다. 스프레드시트에서 PDF로 변환하는 방법은 다음 과 같다.

1. 엑셀에서 해당 스프레트시트를 연다.

2. ‘Adobe PDF > 변환 설정 변경'을 선택하면 대화상자가 열린다.<그림 12-2>


<그림 12-2> 대화상자에서 애크로뱃의 파일 변환 설정을 지정한다.

3. 변환 설정 메뉴에서 “표준”을 선택한다. 이전에 엑셀에서 PDFMaker를 사용한 적이 없다면, 표준이 기본 설정으로 선택되어 있다.

4. PDF는 스프레드시트의 파일명을 이용하기 때문에“Adobe PDF 파일 이름”의 선택을 해제한다.

5. 응용 프로그램 설정의 기본 옵션들의 선택을 해제한다.
  
6.응용 프로그램 설정에서 다음 옵션들을 선택한다.
  • Adobe PDF에 원본 파일 첨부
  • 태그가 있는 Adobe PDF를 만들어 액세서빌러티 및 리플로우 활성화
7. [확인]을 클릭해서 대화상자를 닫는다.

8. PDFMaker 도구모음에서‘Adobe PDF로 변환( )'을 선택한다.
인쇄 영역이 설정되어 있을 때 태그가 있는 문서는 변환되지 않는다는 메시지가 나타나면, [아니오]를 클릭하고 ‘파일 > 인쇄 영역 > 인쇄 영역 해제'를 선택하고, 파일을 저장한 다음 다시 시도한다.

9. 파일이 PDF로 변환되고 애크로뱃 8 프로페셔널이 파일이 열린다.



파일 점검하기

파일이 변환된 다음, 타니스와 론은 애크로뱃에서 그 결과를 점검해야 한다. 변환 설정에서 애크로뱃이 자동으로 PDF 파일을 연다는 옵션이 포함되어 있으므로 파일은 바로 열린다.
애크로뱃에서, 탐색 패널에서‘첨부( )'아이콘을 클릭하면 프로그램 창 하단에 첨부 패널 이 생긴다.
<그림 12-3>. 첨부 패널에는 첨부 파일 및 설명, 수정 날짜, 크기 등이 나온다. 다음은 내용을 검증했다는 서명을 추가할 것이다.


<그림 12-3> 원본 파일을 보기 위해서 첨부 패널을 클릭한다.



PDF 보고서에 서명하기


디지털 서명, 디지털 ID, 디지털 프로파일 등은 서로 교환되는 디지털 인증으로 문서를 보증하거나 문서에 서명하는 것을 의미하는 용어들이다. 디지털 ID는 편의상 이 책에 사용하는 용어이다.

사용하는 용어와 상관없이, 디지털 ID에 대한 정보는 다른 종류의 파일과 마찬가지로 공유하거나 교환할 수 있는 인증서에 포함된다.
론과 타니스는 각각의 영업 보고서를 변환하고 파일에 포함된 첨부 파일을 확인하고, 문서의 정확성을 점검한 다음 이 PDF 파일에 서명해야 한다. 그림 2.8 새로운 PDF 파일은 여러 가지 방법으로 만들 수 있다.

DOWNLOAD : http://www.donnabaker.ca/downloads.html
사인한 문서는 베이커 웹사이트에서 다운로드할 수 있다. 파일 이름은 redwards0906.pdf와 tsharp0906.pdf이다.
  출처 : http://www.acrobatpdf.com/tip/detail.asp?id=83&gotopage=10&code=
반응형
반응형

 
 ADOBE ACROBAT 8 Professional 에서
 
주석 기능을 활용한 업무 협업

Adobe Acrobat의 주석 기능을 활용하여 하나의 업무를 어떤 식으로 협업하여 활용할 수 있는지를 중심으로 설명하고자 한다.

네트워크가 발달된 오늘날, 필자를 포함한 많은 사람이 업무를 같은 장소에서 하지 않고 각자의 사무실 혹은 재택근무 등 다양한 곳에서 한 업무를 협업하여 진행한다. 이에 Adobe Acrobat으로 문서 검토를 관리해 지연, 분실되거나 업무에 차질이 생기지 않도록 하기 위한 방안으로 주석 기능을 활용하는 방안에 대해 설명하고자 한다.

문서 협업 작업을 위한 순서는 다음과 같다.
  1. 작업문서 메일전송

  2. 작업문서 검토 (주석 도구를 활용한 주석추가)

  3. 작업문서 재 전송

  4. 작업문서 결합

  5. 작업문서 검토 관리
위 5단계 작업 과정을 통해 Adobe Acrobat을 활용한 문서 공동 작업 과정을 설명하겠다.



1. 작업문서 메일전송

공동 작업할 pdf 문서를 대상자들에게 전송한다.
<그림 1>과 같이 Adobe Acrobat 메뉴 중 주석에 ‘전자메일 검토용으로 첨부'를 클릭한 후
<그림 2>, <그림 3>과 같이 작업한다.

 
<그림 1> 검토파일 메일 보내기 화면 <그림 2> 검토대상 이메일 추가 화면


<그림 3> 초대장 미리 보기 화면



2. 작업문서 검토


이제 공동 작업할 문서 전송이 끝났으니 문서를 검토해보자. 이메일로 전송된 pdf 문서가 열리면 주석 도구 모음에 두 가지 도구가 나타나고 문서에 권한이 부여되어 있으므로 프로그램 창의 상단 도구 모음에 ‘사용자 정의도구 모음 옵션'이 보이고, 여기에 있는 메뉴를 클릭해 도구 모음을 추가할 수 있다. 다른 도구 모음을 추가하는 방법은 Adobe Acrobat의 도구 모음에서 ‘사용자 정의 도구 모음' 단추를 클릭하고 필요한 도구를 추가, 확인한다. <그림 4>


<그림 4> 다른 도구 추가 팝업 창

일단 주석 작업에 많이 쓰이는 기능들을 <그림 5>에 나오는 메뉴 순서에 따라 간략하게 설명하겠다.


<그림 5> 주석 및 마크업 메뉴 화면

스티커 노트: 보통 다른 주석 도구들보다 많이 사용하는 도구로 문서를 클릭하면 팝업 창이 뜨고 입력을 시작하면 텍스트가 삽입된다. 페이지를 클릭해서 저장하는데 이때 페이지에 작은 노트 아이콘이 생기고 다시 이를 클릭하면 노트 팝업 창이 뜬다.


텍스트 편집:
  • 텍스트 삽입: 문서의 텍스트 사이를 클릭 후 입력한다. 내용이 팝업 주석 상자에 삽입된다.

  • 텍스트 삭제: ‘텍스트 편집' 도구를 이용하여 삭제할 텍스트를 선택하고 delete를 누른다. 이때 텍스트의 한가운데 빨간줄이 생긴다.

  • 텍스트 교체: ‘텍스트 편집' 도구를 이용하여 텍스트 선택 후 새 텍스트를 입력한다. 교체할 텍스트는 ‘교체텍스트' 창에 입력되고, 선택한 텍스트에는 줄이 그어지고 삽입 아이콘이 나타난다. 이때 팝업 창이 보이지 않을 경우 마우스를 해당 위에 움직이면 대체 텍스트가 보인다.
<그림 6>은 주석 및 마크업 도구를 활용하여 주석을 테스트한 화면이다.


<그림 6> 주석 및 마크업 테스트



3. 작업문서 재전송

편집과 주석 추가 작업이 끝나면 결과를 이메일로 전송을 해야 된다. <그림 5> 주석 및 마크업 메뉴에서 마지막 메뉴 ‘주석 보내기' 버튼을 클릭해 처음 작업 요청 메일을 보냈던 사람에게 되돌려 보낼 수 있다. 이때 주석이 첨부되면서 전송된다.


<그림 7> 주석 보내기



4. 작업문서 결합

공동 작업을 요청한 사람들이 이메일을 보내오면 그 문서를 Adobe Acrobat을 이용하여 주석과 마크업을 병합하는 작업을 한다. 공동 작업자가 보내온 첨부 문서 pdf 파일을 클릭하면 <그림 8> 과 같은 팝업 창이 뜨고 ‘예'를 눌러 병합을 한다.


<그림 8> 주석 병합 확인



5. 작업문서 검토 관리

주석 병합작업이 마무리되면 처음 이메일을 보낸 사람은 초기 작업을 했던 파일을 Adobe Acrobat의 ‘검토 추적기'를 통해 누가 어떤 작업을 했는지 확인하고 관리할 수 있다. Adobe Acrobat 메뉴의 ‘검토 및 주석' 메뉴를 클릭하고 ‘검토 추적기' 메뉴를 선택하면 <그림 9>와 같은 별도의 팝업 창이 뜬다.


<그림 9 > 검토 추적기 화면

검토 작업이 마무리되면 새로운 PDF를 만든 후, 모든 검토자에게 재전송 후 승인을 받으면 모든 작업이 끝난다.




전자 서명을 이용한 문서 보안을 적용한 문서 배포

완성된 문서를 본사에 보고하면 되는데, 이때 내가 보고하는 문서가 유출되거나 변경된 문서가 보고되면 안 된다. 이럴 경우 Adobe Acrobat의 ‘디지털 ID'라는 것을 활용하여 전달할 수 있다.

Adobe Acrobat은 공개키 기반구조(PKI)라는 방식을 채택하고 있다. Adobe Acrobat을 이용하여 ‘디지털 ID'를 하게 되면 이때 공개키와 개인키 두 개가 만들어진다. 개인 키는 서명을 발행한 본인이 갖고 있고 공개키는 다른 사람들과 공유한다. 즉 다른 사람이 문서에 포함된 공개키를 갖고 있으면 그 사람과 정보를 공유할 수 있다.




Adobe Acrobat 을 이용해서 서명을 추가 해보자

1. Adobe Acrobat의 ‘서명 작업도구'를 선택하고 ‘서명 삽입'을 선택한다. 그러면 서명 방법을 알려주는 팝업 창이 뜰 것이다. <그림 10>


<그림 10> 서명 삽입

확인을 선택하고 페이지 위로 마우스를 서명할 곳으로 움직인 후 서명을 추가할 만큼 드래그한 후 마우스를 놓는다. 그러면 ‘디지털 ID' 추가 대화 상자가 <그림 11>처럼 뜬다.


<그림 11> 디지털 ID 추가 상자 1


<그림 12> 디지털 ID 추가 2

2. ‘디지털 ID' 추가 대화상자 그림에서 디지털 ID를 처음 작성하는 사람은 세 번째 옵션을 사용하고, 서명 파일이 이미 있는 사람은 ‘기존 파일 찾기'를 선택하고 다름을 클릭한다.

3. [그림 12]에 보이는 찾아보기 버튼 클릭 후 서명 파일을 선택한다. 그리고 암호 필드에 암호 입력 후 패스워드를 입력하고 다름 버튼을 누른다.

 
<그림 13> 문서 서명  <그림 14> 서명 확인 화면

4. [그림 13]의 문서 서명 창이 뜨면 암호를 입력하고 서명 버튼을 누르면 처음 마우스로 위치를 정한 곳에 서명이 생긴다. <그림 14> 참조

이렇게 해서 주석을 활용한 문서 협업 과정을 알아봤고, 그리고 완성된 문서를 Adobe Acrobat의 디지털 서명을 통해 전달하는 방법까지 확인했다. 아직 국내에서는 디지털 서명을 통한 문서확인을 많이 사용하고 있지 않지만 추후 중요한 문서를 주고 받는 경우가 생긴다면 한번쯤은 사용해 볼만한 가치가 있다고 생각한다.

 

출처 : http://www.acrobatpdf.com/tip/detail_02.asp?id=17&gotopage=7&code=
반응형

+ Recent posts