강좌 전 Taeyo의 잡담>
꾸주니(azraid) 님은 현재 NCSOFT 에서 재직중인 이명용 님이십니다.
최근 웹 인증서와 암호화에 대한 업무를 진행하시다가, 정보 공유 차원에서 제 동생 사이트인 Dukyoung.net에 강좌를 올리셨고, 그것을 우연히 읽어보게된 저는 내용이 넘 재미있어서리..
꼬드김을 날렸었던 것이지요...
약간의 망설임 후에, 제 사이트에도 강좌를 올리기로 전격 결정하셨습니다.
약간은 생소하게 느껴지는 인증서와 암호화.. 한 번 기대해 볼까요? ^^
(읽다보면, 어투가 다소 지나치게 캐쥬얼하지 않은가 싶기도 할텐데요..
그래서, 오히려 약간은 더 잼나지 않나 합니다. 오해는 말아 주세요^^)
강좌 전 꾸주니 님의 잡담>
드디어 마지막 강좌를 쓰려고 한다. 하지만 이 강좌를 마치기도 전에 보안업계에 파장을 일으킬만한 사건이 발생했다. 미국에서 그렇게 자신만만하게 소리치던 보안 알고리즘들이 중국의 한 유명하지도 않은 대학의 교수에 의해서 깨져버린 것이고, 미국은 이 사실을 숨겨오다가 급기야 인정을 하게 이르렀다. 불과 한달전 일이다.
참고기사 http://www.jabo.co.kr/sub_read.html?uid=10076§ion=section4&wdate=1112251408
이제 세계의 보안연구원들은 또다시 쉽게 뚫리지 않는 새로운 암호 알고리즘을 개발하기 위해 똥꼬에 잔뜩 힘줘야 할 때이다.
자~ 오늘은 Microsoft CAPICOM을 이용하여, 문자열을 암호화/복호화시키는 코드를 만들어보고, 더 나아가서 문자열에 서명을 하는 코드를 만들어 보겠다.
Microsoft CAPICOM이 무엇인가? 라고 묻는 님이 있을 텐데, 'Microsoft CAPI를 이용하여 만든 Com Object 입니다.' 라고 말하면 분명 님들은 짜증낼 것이다.
간혹 프로그래밍 싸이트에서 질문을 올려 놓으면,
"아 그거 msdn에 있습니다. 관련 자료 참고하면 다 나옵니다"
라고 질알같은 답변을 올리는 사람들이 있다. 이러면 짜증 열라 받는다. 그게 답변이라고 하는 것인가? 차라리 쓰지나 말 것이지, 괜히 답변같지도 않은 답변 올려놔서, 다른 사람도 답변하지 않게 만드는 몰쌍식한 인간들은 정말 싫다.
CAPICOM은 Micorsoft에서 제공하는 암호화 API를 VB/Script 언어에서 사용할 수 있도록 Component로 제공하는 것인데, 기본적으로 VS 툴을 깔아도 설치되지 않는다. 그래서...
download.microsoft.com/download/7/7/0/7708ec16-a770-4777-8b85-0fcd05f5ba60/cc21inst.exe
이곳에서 따로 다운받아 설치 해야 한다. 설치하는 것이라면 괜히 두려워하는 님도 있을텐데, 위 프로그램을 설치하면 capicom.dll파일이 생긴다. 사실 이것만 있어도 된다. regsvr32 capicom.dll로 등록하거나 구성요소로 등록해서 여러분의 VB코드에서 사용하면 되는 것이다.
이것이 없을때는 이런 저런 개발자들이 만들어 놓은 Component를 다운받거나 수정해서 사용하곤 했는데 썩 맘에 드는게 없었다. 이것은 Microsoft에서 제공하는 것이니 만큼 신용이 간다.
그러면, CAPICOM을 이용해서 Encrypt/Decrypt 함수를 만들어 보자.
Const gcKEY = "OuSexy~!"
Public Function Encrypt(Message)
Dim ed, key
key = gcKEY
Set ed = CreateObject("CAPICOM.EncryptedData")
ed.Content = Message
ed.SetSecret key
Encrypt = ed.Encrypt
Set ed = Nothing
End Function
Public Function Decrypt(EncMessage)
Dim ed, key
key = gcKEY
Set ed = CreateObject("CAPICOM.EncryptedData")
ed.SetSecret key
ed.Decrypt EncMessage
Decrypt = ed.Content
Set ed = Nothing
End Function |
으앗... 코드다! 그렇다고 도망가지 마라. 딱 봐도 매우 간단하지 않은가? 정말 간단하다. 코드 설명은 안하겠다. 이해가 안되더라도 Copy해서 그냥 써라. 별 문제 없을 것이다. 단 gcKEY에 여러분이 원하는 키값을 맘대로 바꿔서 사용하면 된다. 이로써 암호화/복호화 코드 구현은 끝났다. 아싸~~
다음은 문자열에 사인과 확인하는 것에 대해서 설명을 해보겠다. 사실 내가 IIS나 IE개발자도 아닌데 이런게 왜 필요하겠냐? 묻겠지만 ....
사실 별로 필요없다.
-.-!
혹시나 타회사 Server와 우리 회사 Server 간 통신을 HTTP로 할 경우 사용할 수도 있다. 설령 사용하겠다 하더라도 말리는 사람이 많을 것이다. 그냥 HTTPS 통신을 하면 IIS에서 다 알아서 해줄텐데 왜 그러냐고... 그래서 아래 글은 안 읽어도 된다.
하지만 굳이 계속해서 쓰는 것은 이 강좌의 주제가 IIS의 행동을 이해하는 것이고 특정 상황에서는 사용할 필요가 있다. 가령 사용자가 타 회사(A) 웹서버에서 결제를 하고 우리 회사 웹서버로 Redirect시키는 구조라면, 우리가 손수 A회사에서 결제가 된 것을 확인해 줘야한다. 즉 A회사에서 결제가 완료 되었다면
Redirect "http://a.com/pay.asp?paycode=232&account=꾸주니&sign=sxdfla0skxlqalxkd+slxe3"
처럼 될 것이고, 우리는 이것이 사용자가 고의로 입력한 값이 아닌 것을 확인하기 위해서 sign=sxdfla0skxlqalxkd+slxe3 이값을 가지고 확인 할수 있는 것이다. 보통 이럴 경우에는 [paycode=232&account=꾸주니]자체를 sign한 값을 sign= 으로 넘긴다.
머리가 아픈가? 그럼 그냥 코드나 살펴보기로 하자.
Const CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT = 0
Const CAPICOM_ENCODE_BASE64 = 0
Public Function SignDatainPFX(Message, PFXFileName, PFXPassword)
Dim Signer, SignedData
Set Signer = CreateObject("CAPICOM.Signer")
Signer.Load PFXFileName, PFXPassword
Signer.Options = CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT
Set SignedData = CreateObject("CAPICOM.SignedData")
SignedData.Content = Message
SignDatainPFX = SignedData.Sign(Signer, False, CAPICOM_ENCODE_BASE64)
Set SignedData = Nothing
Set Signer = Nothing
Exit Function
End Function |
자.. 맨위에 두개의 상수는 CAPI API에서 사용하는 상수를 정의한 것이다.
이 강좌 맨뒤에 사용되는 상수들을 정리한 것이 있다. 참고하기 바란다.
함수 이름이 SignDatainPFX이다. 내가 왜 inPFX라고 붙였을까?
음... 왜냐면 아직도 함수 이름 짓는데 서투르기 때문이다.
나의 의도는 PFX파일을 사용해서 Data를 Sign하겠다는 의미이다.
PFX파일이란 IIS에 인증서를 설치해보고, 인증서를 백업한뒤에 다른 서버에 같은 인증서를 설치해 본사람은 안다. 즉 인증서를 가져오기 할때 사용하는 '개인정보교환' 파일 형식이다. 인증서관리자에서 인증서를 PFX파일로 저장할 수 있다. PFX파일로 저장할때 암호를 설정하게 되는데, PFXPassword가 그것이다.
또 나에게 위 코드를 테스트하려고 하는데, PFX파일을 얻기 위해서 인증서는 어디서 구하냐고 묻는 몰지각한 사람이 있을 지도 모르겠다. 도대체 뭘 읽은 것인가?
인증서는 도장집(Verisign회사)에서 구하는 것이다. 그러니 도장집에서 사기 바란다. 좀 비싸다..ㅎㅎ
(물론 가짜 인증서를 만드는 tool도 인터넷에서 돌아다니고 있으니, 돈이 없으면 각자 알아서 구해보기 바란다.)
다음에
Signer.Options = CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT
이런 구문이 있다.
인증서는 이 강좌 2번째에 설명한대로, 전세계가 공인하는 Verisign회사에서 Sign하고 그것을 그다음 회사에서 또 sign하고 .. 또 그다음 회사에서 Sign한다고 했다. 이렇게 인증서는 Chain형식으로 되어 있는데, Except_Root가 붙은 것을 보니, 최상위는 뺀다는 의미다.
그다음은 SignedData.Content의 내용을 Sign한다.
SignDatainPFX = SignedData.Sign(Signer, False, CAPICOM_ENCODE_BASE64)
CAPICOM_ENCODE_BASE64는 이렇게 Sign한 데이터는 문자열로 표현하기 어려운, Binary값이 되는데 이를 문자열로 표현하는 Encoding 방식이다. (혹시나 Encode과 Encrypt를 헤깔려 하는 사람이 있는데, Encode는 표현이 안되는 것을 표현할 수 있도록, Data를 변경시키는 것이고 (ex) URLEncode는 url string에 표현할 수 없는 '<space>'값을 '%20'이라는 문자열로 Encode하는 것) Encrypt는 우리가 얘기하고 있는 값을 알 수 없도록 하는 암호화이다. )
그럼 이제 저렇게 Sign한 데이타를 확인하는 코드를 만들어 보겠다.
Public Function VerifyData(SignedMessage)
Dim SignedData, Signer
Dim cSigner: cSigner = SignedData.Signers.Count
Dim sIndex: sIndex = 0
Set SignedData = CreateObject("CAPICOM.SignedData")
SignedData.Verify SignedMessage, False, CAPICOM_VERIFY_SIGNATURE_AND_CERTIFICATE
VerifyData = SignedData.Content
Set SignedData = Nothing
VerifyData = True
End Function |
자~ 이것이 Signed 데이타를 확인하는 코드 이다. 이것은 굳이 설명을 하지 않겠다. 이렇게 이 강좌에서 올라온 코드는 사실 MSDN에서 찾은 것으로 기억하는데, 지금 코드가 맞는지 확인하려고 찾다보니까, 못 찾겠다. 이런 제길.
그렇다 하더라도 대강의 Signing에 대한 소개는 여기서 잽싸게 끝낸다.
그동안 읽어주신 님들께 감사드린다. 그리고 이 자리를 빌어서 오늘 주인장네 집에서 밥을 얻어 먹고 왔다. 그러지 않았으면 아직 이강좌를 끝내지 못했을 것이다. 솔직히 나뿐만 아니라, 세상의 수많은 프로그래머들이 밥한끼에 목숨걸고 쉽게 넘어간다.
싸게 살지 말자.
부록
'**************************************************************************
'
' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
' WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
'
' Copyright (C) 1999- 2002. Microsoft Corporation. All rights reserved.
'
'******************************************************************************
'
' CSignData.vbs
'
' This is a sample script to illustrate how to use the CAPICOM's SignedData
' to sign/verify text file.
'
' Note: For simplicity, this script does not handle exception.
'
'**************************************************************************
Option Explicit
' CAPICOM's constants.
Const CAPICOM_LOCAL_MACHINE_STORE = 1
Const CAPICOM_CURRENT_USER_STORE = 2
Const CAPICOM_ACTIVE_DIRECTORY_USER_STORE = 3
Const CAPICOM_SMART_CARD_USER_STORE = 4
Const CAPICOM_CERTIFICATE_FIND_SHA1_HASH = 0
Const CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME = 1
Const CAPICOM_CERTIFICATE_FIND_ISSUER_NAME = 2
Const CAPICOM_CERTIFICATE_FIND_ROOT_NAME = 3
Const CAPICOM_CERTIFICATE_FIND_TEMPLATE_NAME = 4
Const CAPICOM_CERTIFICATE_FIND_EXTENSION = 5
Const CAPICOM_CERTIFICATE_FIND_EXTENDED_PROPERTY = 6
Const CAPICOM_CERTIFICATE_FIND_APPLICATION_POLICY = 7
Const CAPICOM_CERTIFICATE_FIND_CERTIFICATE_POLICY = 8
Const CAPICOM_CERTIFICATE_FIND_TIME_VALID = 9
Const CAPICOM_CERTIFICATE_FIND_TIME_NOT_YET_VALID = 10
Const CAPICOM_CERTIFICATE_FIND_TIME_EXPIRED = 11
Const CAPICOM_VERIFY_SIGNATURE_ONLY = 0
Const CAPICOM_VERIFY_SIGNATURE_AND_CERTIFICATE = 1
Const CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME = 0
Const CAPICOM_AUTHENTICATED_ATTRIBUTE_DOCUMENT_NAME = 1
Const CAPICOM_AUTHENTICATED_ATTRIBUTE_DOCUMENT_DESCRIPTION = 2
Const CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT = 0
Const CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN = 1
Const CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY = 2
Const CAPICOM_PROPID_KEY_PROV_INFO = 2
Const CAPICOM_HASH_ALGORITHM_SHA1 = 0
Const CAPICOM_HASH_ALGORITHM_MD2 = 1
Const CAPICOM_HASH_ALGORITHM_MD4 = 2
Const CAPICOM_HASH_ALGORITHM_MD5 = 3
Const CAPICOM_HASH_ALGORITHM_SHA256 = 4
Const CAPICOM_HASH_ALGORITHM_SHA384 = 5
Const CAPICOM_HASH_ALGORITHM_SHA512 = 6
Const CAPICOM_ENCODE_BASE64 = 0
Const CAPICOM_ENCODE_BINARY = 1
|
|