딩굴 딩굴 딩구리~~

andy9273.egloos.com

포토로그 마이가든



다른 Window에 Message 보내기

Window가 두 개 있는데 한 Window에서 다른 Window로 Message를 보내고 싶다.
그리고, 이 두 개의 Window 모두 한 사람(회사)의 개발자가 개발
이럴 때 어쩔까나..

가장 쉬운 방법인SendMessage를 이용하기로 한다.
SendMessage를 사용하기 위해서 Target Window의 Handle(HWND)를 찾아야 한다.

이 때 가장 먼저 생각할 수 있는 것이 FindWindow이다.

즉,

CWnd* pWnd = FindWindow("", Target Window caption) ;
::SendMessage(pWnd->m_hWnd, WM_보낼메시지, wParam, lParam) ;

요렇게 하면 된다.

흠..
그런데 문제는 이제 시작이다.
망할 Target Window는 Caption이 없다..
즉, Title bar가 없다는 것이다.
그렇다고, Class Name을 알아내자니, 망할 VS는 알려주지 않고 꽁꽁 숨겨놓았다.

이럴 경우에 어쩔까나..

이 때는 Process ID로부터 HWND를 가져올 수 있다.

일단 해당 Target Window의 Process ID를 가져온다.
가져오는 방법은 저~~ 아래를 참고하여 약간 변형하면 된다.
이 때, 우리가 만드는 프로그램이니깐 실행파일 이름 정도는 알 수 있다.

DWORD get_processid(char* psz_exec_name)
{
    DWORD a_proc[1024], dw_needed, dw_proc ;
    unsigned int i ;
    CString proc_name ;
    TCHAR sz_exec_name[MAX_PATH] = {0, } ;


    if(!EnumProcesses(a_proc, sizeof(a_proc), &dw_needed))
        return ERROR_FIND ;


    dw_proc = dw_needed / sizeof(DWORD) ;


    for(i=0 ; i<dw_proc ; i++)
    {
        HANDLE h_proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, a_proc[i]) ;

        if(NULL != h_proc)
        {
            HMODULE h_module ;
            if(EnumProcessModules(h_proc, &h_module, sizeof(h_module), &dw_needed))
            {
                GetModuleBaseName(h_proc, h_module, sz_exec_name, sizeof(sz_exec_name)/sizeof(TCHAR)) ;

                if(psz_process_name == CString(sz_exec_name))
                    return a_proc[i] ;
            }
        }
    }

    return ERROR_FIND ;
}

자.. 이제 Process ID를 알았으니, HWND를 알아보자.
이 때 사용되는 API는 EnumWindows이다.

BOOL EnumWindows(      
    WNDENUMPROC lpEnumFunc,
    LPARAM lParam
);

typedef struct _PROC_HWND
{
    DWORD dw_pid ;
    HWND h_wnd ;
    CString str_class ;
    CString str_title ;
} PROC_HWND, *PPROC_HWND ;

BOOL CALLBACK EnumWindowsHWND(HWND hWnd, LPARAM lParam)
{
    char sz_class[_MAX_PATH] = {0, } ;
    char sz_title[_MAX_PATH] = {0, } ;
    DWORD dw_pid = 0 ;
    PPROC_HWND proc = (PROC_HWND*)lParam ;

    GetWindowThreadProcessId(hWnd, &dw_pid) ;
    if(proc->dw_pid == dw_pid)
    {
        GetClassName(hWnd, sz_class, _MAX_PATH) ;      //    테스트를 위해서 찍어보자.
        GetWindowText(hWnd, sz_title, _MAX_PATH) ;         //    테스트를 위해서 찍어보자.
        proc->str_class = sz_class ;
        proc->str_title = sz_title ;
        proc->h_wnd = hWnd ;

        return FALSE ;
    }

    return TRUE ;
}

HWND CFindNoTitleDlg::get_Window_handle(DWORD dw_pid)
{
    PROC_HWND ph ;
    ph.dw_pid = dw_pid ;
    ph.h_wnd = NULL ;
    ph.str_class.Empty() ;

    EnumWindows((WNDENUMPROC)EnumWindowsHWND, (LPARAM)&ph) ;

    return ph.h_wnd ;
}

이렇게 작성한 후, get_Window_handle을 호출하면 Target Window의 HWND를 구할 수 있다.
그리고, 구한 값들 중 Class name은 SPY++로 알아본 Target Window의 Class Name과 동일함을 알 수 있다.
물론 Target Window의 Title은 ""일 것이고..
내 경우엔 Class Name이 "#37728"로 나왔다.

이제 HWND를 알아왔으니, 가볍게 SendMessage를 호출하여 메시지를 날릴 수 있다.

이 때 생성할 수 있는 메시지의 범위는 아래와 같다.(MSDN)

RangeMeaning
0 through WM_USER–1Messages reserved for use by the system.
WM_USER through 0x7FFFInteger messages for use by private window classes.
WM_APPthrough 0xBFFFMessages available for use by applications.
0xC000 through 0xFFFFString messages for use by applications.
Greater than 0xFFFFReserved by the system.


그리고, 덧붙여 한 가지 더..

위 방법이 번거롭다면 두 프로그램이 같은 Window Message를 등록한 후, 한 쪽에서 보낼 Message를 Broadcast 해 버리는 방법이다.
정말 간단하다..  ㅡㅡ;;

UINT RegisterWindowMessage(      
    LPCTSTR lpString
);

RegisterWindowMessage 함수를 이용하면 OS가 System에서 고유한 Message를 생성해주며, 이 때 생성되는 메시지는 0xC000에서 0XFFFF 사이의 값이다.

즉, 양쪽 프로그램에서
UINT g_msg = RegisterWindowMessage(_T("TEST_PRG_MESSSAGE")) ;
처럼 메시지를 등록하고, 보내는 쪽에서
SendMessage(HWND_BROADCAST, g_msg, 0, 0) ;
한 후, Target Window에서 알맞은 Event Handler를 작성하면 되겠다.

위 메시지는 Top-level Window에 모두 날라가겠지만, 메시지를 등록한 프로그램만 받을테니깐..

explorer.exe 재실행 밥은 먹구 다니냐?

프로젝트 진행 중 explorer에 메시지를 등록한 후 이벤트를 받아야 할 일이 있었다.
등록 과정은 밑의 글을 참조하면 될 듯 하고, 문제는...
explorer.exe가 죽으면 등록한 메시지도 같이 날라가서 이벤트를 받을 수 없다는 것이다.
그래서 다시 등록을 해야 할 필요가 있었고, 찾아보니 explorer가 재실행되면 Taskbar를 그리기 위해서 각 Process에 TaskbarCreated란 메시지를 전송한단다.

사용법은
1. 우선 이벤트를 받기 위한 메시지를 등록한다.
static UINT g_uExplorerRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));

2. 메시지 맵
BEGIN_MESSAGE_MAP(CXDlg, CDialog)
//{{AFX_MSG_MAP(CXDlg)
ON_WM_SYSCOMMAND()
......
//}}AFX_MSG_MAP
......
ON_REGISTERED_MESSAGE(g_uExplorerRestart, OnExplorerRestart)
END_MESSAGE_MAP()

3. 함수 구현(수행할 작업)
LRESULT CXDlg::OnTaskbarRestart(WPARAM wParam, LPARAM lParam)
{
// 아이콘 표시
  ShellNotify(NIM_ADD) ;

// 메시지 재 등록
  HWND hWnd = GetSafeHwnd() ;
  LPITEMIDLIST ppidl ;
  if(NOERROR == SHGetSpecialFolderLocation(hWnd, CSIDL_DESKTOP, &ppidl))
  {
    SHChangeNotifyEntry shCNE ;
    shCNE.pidl = ppidl ;
    shCNE.fRecursive = TRUE ;
    m_ulSHChangeNotifyRegister = SHChangeNotifyRegister(
      hWnd,
      SHCNE_DISKEVENTS,
      SHCNE_DRIVEADD CNE_DRIVEREMOVED,
      WM_USER_MEDIACHANGED,
      1,
      &shCNE) ;
  }
  else
  {
  // 예외처리
  }
  return 0 ;
}

InstallShiedl를 이용한 Background 설치 밥은 먹구 다니냐?

InstallShield를 이용하여 사용자 모르게 설치하고자 할 경우 다음과 같이 한다.
이 때, 사용한 버전은 7.x 되겠다.

1. 정상적인 InstallShield Setup file을 생성한다.
2. Command-line에서 "setup /r"을 실행한 후 정상적으로 설치한다.
3. Windows 폴더에 setup.iss 파일이 생성된다.
4. InstallShied의 Media tab에서 Disk Images >> Disk1에 setup.iss 파일을 넣는다.
5. InstallShied의 Setup Files tab에서 Advanced Files >> Disk1에 setup.iss 파일을 넣는다.
6. InstallShied의 Media tab에서 New CD-ROM Media를 클릭하면 세팅된 상황이 나타나는데, 이 때 setup command line을 클릭한다.
나타난 대화상자의 setup command에 -s를 입력한다.
부가적으로 하나의 파일로 구성되는 설치파일을 생성하려면 Create a single file executable을 선택하고 파일이름을 입력한다.
7. Build 후 test!!!

이렇게 하면 끝.!!

다시 이글루로.. ㅜㅜ

예전에 이글루에 글을 올렸었는데, 일정 부분이 몽땅 날라가버려 열받아서 다른 곳으로 이사를 갔는데..

거긴 글쓰기가 너무 어려워서 걍 버려두었다가 다시 컴백.. ㅜㅜ

이젠 다시 잘 관리 함 해보까?

USB 포트로 장착된 장치 인식하기 밥은 먹구 다니냐?

요즘 진행하고 있는 프로젝트가 둘 있는데, 모두 하드웨어와 Interface하는 프로그램이다.
제작된 하드웨어가 컴퓨터에 연결되었을 때 이를 인식하여 Application level에서 일련의 동작을 수행하는 것으로, 하드웨어와 커널 중간에 Device Driver와 Filter Driver가 작동하고 있다.

이 때, 장치가 장착되었을 때와 탈착되었을 때를 알아야 이에 맞는 동작을 수행할 수 있어서 이런 Event를 잡아내는 것이 필요하며, Windows에서는 WM_DEVICECHANGE라는 메시지를 Broadcast하므로 이 메시지를 잡아 처리하면 알아낼 수 있다.

MSDN을 보면 함수 원형은
     afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD dwData) ;
이고,
nEventType은 발생한 이벤트의 종류로써,
     DBT_DEVICEARRIVAL
     DBT_DEVICEQUERYREMOVE
     DBT_DEVICEQUERYERMOVEFAILD
     DBT_DEVICEREMOVEPENDING
     DBT_DEVICEREMOVECOMPLETE
     DBT_DEVICETYPESPECIFIC
     DBT_CONFIGCHANGED
등이 있다.
DWORD dwData는 각 event에 대한 자료(구조체)의 주소다.

MSDN 맨 아래 부분에 Note를 보면
This member function is called by the framework to allow your application to handle a Windows message.
...
이런 말이 써 있는데, 나를 비롯한 많은 사람들이 이 문장을 놓쳐서 고생했을 것으로 생각된다.
즉, Dialog base에서는 그냥 event에 대한 message handler를 작성하면 끝이지만 Doc/View 구조에서는 그렇게 하면 작동하지 않는다.

Dialog base에서는

XXXDlg.h
     afx_msg BOOL OnDeviceChange(UINT, DWORD);

XXXDlg.Cpp

BEGIN_MESSAGE_MAP(CAgentNewDlg, CDialog)
     //{{AFX_MSG_MAP(CAgentNewDlg)

     ...
     //}}AFX_MSG_MAP
     ON_MESSAGE(WM_BNB_NOTIFYTRAY, OnNotifyTray)
     ON_WM_DEVICECHANGE()
     ON_MESSAGE(WM_HOTKEY, OnHotKey)
END_MESSAGE_MAP()


...

BOOL CAgentNewDlg::OnDeviceChange(UINT nEventType, DWORD dwData)
{
   PDEV_BROADCAST_HDR hdr ;
   hdr = (PDEV_BROADCAST_HDR)dwData ;

    switch (nEventType)
    {
        case DBT_DEVICEARRIVAL:
            if(hdr->dbch_devicetype == DBT_DEVTYP_VOLUME)

                AfxMessageBox("Inserted!!") ;
        break ;

       case DBT_DEVICEREMOVECOMPLETE:
            if(hdr->dbch_devicetype != DBT_DEVTYP_VOLUME)
                 AfxMessageBox("Removed!!") ;
           break ;

    }
    return TRUE;
}
와 같이 동작시키면 된다.

위의 예제는 Volume에 대해서 장치를 장/탈착 할 경우, 동작한다.
가장 간단한 예로 USB를 장/탈착해보면 알 수 있다.

Doc/View 구조에서는

MainFrm.h
// Overrides
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CMainFrame)
    public:
    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
    virtual void ActivateFrame(int nCmdShow = -1);
    protected:
    virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
 //}}AFX_VIRTUAL


MainFrm.cpp
LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    if(WM_DEVICECHANGE == message)
    {

        상동...(Dialog base에서 OnDeviceChange 함수내의 이탤릭으로 된 부분)
    }

    return CFrameWnd::WindowProc(message, wParam, lParam);
}
과 같이 동작시킨다.

WindowProc은 ClassWizard에서 생성하면 쉽게 만들 수 있다.

그런데, 문제는 DDK Sample 중 USBView를 통해서 보면 확인가능하겠지만, PnP Manager에서 위 Message를 한 번만 Broadcasting하는 것이 아니라는 사실이다.
이거때매 완전좌절모드로...ㅠㅠ
꽁수를 써서 한 번만 동작하도록도 해보고, 다른 짓거리도 해 보았지만, 워낙 상황이 다양해서 모두 대처할 수 없어 폐인같은 삶을 지속하다가 한 줄기 단비와도 같은 함수 이름 하나를 듣게 되었다...
그 날의 감동이란..
외주업체에 Windows는 마지막 Message를 잡아 처리하는데 왜 나는 안되느냐며 떼를 썻고, 그 업체 직원들이 지인을 통해 수소문한 결과, SHChangeNotifyRegister라는 API를 알아왔다..^^

이 함수는 이름 앞에 붙은 접두어에서도 알 수 있듯이, Shell 함수이다.
A, B라는 메시지가 발생했을 때, 나한테 C라는 메시지를 날려라 라고 등록하는 함수로써, 이 함수가 성공하면, C라는 메시지에 대한 이벤트 처리만 하면 된다는 것이다.
보통 이 함수는 탐색기 같은 것 만들때, 폴더의 변화를 알아오거나 하는 경우 많이 사용하고, 알고 있던 함수였으나, 이런 오묘한 기능마저 하는 줄은 상상도 못했다.
역시 MSDN을 외우라는 건가..ㅠㅠ
원형은 다음과 같이 생겼다.
ULONG SHChangeNotifyRegister( 
    HWND hwnd,
    int fSources,
    LONG fEvents,
    UINT wMsg,     int cEntries,
    SHChangeNotifyEntry *pfsne
);

여기서, fEvent에
SHCNE_DRIVEADD | SHCNE_DRIVEREMOVED 를 조합해서 넣으면, 장치의 장/탈착을 알 수 있다.
이 것이 WM_DEVICECHANGE와 다른 점은 장/탈착되는 시점이 아닌 mount되는 시점을 안 다는 것이다.
따라서, 그냥 장착되었다는 것만 알 필요가 있다면 요놈이 더 편리하다.
그르나 바뜨, 이 것도 커널버전에 따라 적용 안될 수 있고, Platform SDK가 있어야 하는 등의 제한 사항은 있다.
MSDN 참조..ㅡㅡ;;

헤더에
    afx_msg LRESULT OnMediaChanged(WPARAM wParam, LPARAM lParam) ;

CPP에

    ON_MESSAGE(WM_USER_MEDIACHANGED, OnMediaChanged)
...

BOOL CNtfyDlg::OnInitDialog()
{
    HWND hWnd = GetSafeHwnd() ;
    LPITEMIDLIST ppidl ;
    if(NOERROR == SHGetSpecialFolderLocation(hWnd, CSIDL_DESKTOP, &ppidl))
    {
        SHChangeNotifyEntry shCNE ;
        shCNE.pidl = ppidl ;
        shCNE.fRecursive = TRUE ;

        m_ulSHChangeNotifyRegister = SHChangeNotifyRegister(hWnd,
            SHCNE_DISKEVENTS,
            SHCNE_DRIVEADD  | SHCNE_DRIVEREMOVED,
            WM_USER_MEDIACHANGED,
            1,
            &shCNE) ;

     }
     else
         ASSERT(0) ;

     ...
}

LRESULT CNtfyDlg::OnMediaChanged(WPARAM wParam, LPARAM lParam)
{
    SHNOTIFYSTRUCT* pshns = (SHNOTIFYSTRUCT*)wParam ;
    CString strPath, strMsg ;
    switch(lParam)
    {
    case SHCNE_DRIVEADD  :
        strPath = GetPathFromPIDL(pshns->dwItem1) ;
        if(FALSE == strPath.IsEmpty())
        {
            strMsg.Format("Media inserted into %s", strPath) ;
            AfxMessageBox(strMsg) ;
        }
        break ;


    case SHCNE_DRIVEREMOVED :
        strPath = GetPathFromPIDL(pshns->dwItem1) ;
        if(FALSE == strPath.IsEmpty())
       {
            strMsg.Format("Media removed into %s", strPath) ;
            AfxMessageBox(strMsg) ;
       }
       break ;
     }

      return NULL ;
}

위 소스는 CodeProject에서 가져와 나에게 맞도록 메시지 정도만 수정한 것이며, 원문을 보고 싶다면 여기(Using the shell to receive notification of removable media being inserted or removed.)를 클릭!!

샘플은 냉중에...^^



 

CISSP!! 나란 인간



드디어
CISSP를 취득했다..ㅠㅠ
그 동안 고생하고 맘 졸인 거 생각하면 눈물이...
지대로 재수 없게도 진행하고 있는 프로젝트가 시험시기와 정확히 맞아 떨어지는 바람에 시험전 2주 가량 집에도 못가고 거의 매일 밤샘 작업 하느라 공부를 못해서 내심 고민 많이 했었는데, 합격 Mail을 받고나니 기분이 새롭다.
이노무 시험은 접수비가 50만원 가량($499)하는 바람에 떨어지면 집 나가라는 마님의 협박에 얼마나 떨었던가!
다행히도 담당업무의 많은 부분(암호, 통신, 개발)이 시험내용과 관련이 있어서 도움이 되었다.

매년 programming language 하나와 자격증 하나 따자는 연초 계획중 하나를 이뤄서 내 자신에게도 뿌듯하다.
당분간 좀 쉬고, 이젠 PMP닷!!!

AES(Advanced Encryption Standard) 밥은 먹구 다니냐?

AES(Advanced Encryption Standard)는 DES(특히 3DES)를 대체하기 위하여 NIST에서 공모한 암호프로젝트가 이후 표준으로 지정된 이름이다.
15개의 출품작 중 최종 선정된 5개(MARS, RC6, Rijndael, SERPENT, Twofish)의 알고리즘이 경합을 벌였고, 1위를 차지한 Rijndael 알고리즘이 통상 AES라 표현되고 사용된다.
선정 과정 및 기준 등 자세한 사항을 보려면
여기를 참조하면 된다.
또한 AES 표준에 관련된 내용은
FIPS-197에 자세히 설명되어 있다.

이상은 딱딱한 내용이었고, Santa Clara University의 Edward Schaefer라는 교수는 학생들에게 쉽게 가르치기 위해서(쉽게..ㅡㅡ;;) Simplified AES라는 것을 개발했다.
Block이나 Key size를 16bit로 만들어 크기를 작게하여 손으로 풀 수 있도록 만든 것이다.
이렇게 손으로 풀어보면 대개는 이해하게 되기 때문인데 아직 풀어보진 않았다.
이 외에도 Simplified DES도 있다.
아래의 샘플 소스는
Code project에서 받은 소스를 가지고 줄여서 만든 것으로 AES를 통해 파일을 암/복호화하는 소스이다.

"맘대로 써라. 단, 책임지지 않는다."
어차피 내가 프로젝트나 스터디에 필요해서 구현한 것이고, 전체가 순수한 내 창작물도 아니므로 안정성 등의 문제에 대해서 책임질 수 없다...
헤더에 원 저자의 주석이 고스란히 있으니 한 번 다운받아 검토해 보시길...

참고문헌 및 사이트
Cryptography and Network Security Principles and Practices 4/E- Simplifed AES를 첨 알게 되었다.(page 165)
Code project - FileCrypt, a Cryptographic Application By George Anescu.- Sample program의 암호 알고리즘. Thanks George!!
FIPS-197등등

Sample source
FileEncTest.zip - MD5는 이전 글의 것을 사용하였다.

책장 개봉^^ 책장

사실 난 취미가 책 모으기라고 해도 과언이 아닐 만큼 책이 많고, 또 많이 산다.
주로 컴퓨터 관련 서적이다 보니 강컴에서 많이 구입하는 편이다.
작년에 책 사는 데 쓴 돈만 해도 백만원은 넘을 듯 하다.
아쉽게도 산 책 모두를 정독하진 못하지만 자주 보려고 노력하고 그만큼 도움도 많이 받고 있다.

여기에 글 하나를 올리기 위해서 한 글자라도 더 읽을 테니 나에겐 열심히 공부하자는 스스로에 대한 약속과도 같은 것이다.
이제 보고 있는 책과 앞으로 볼 책들에 관해서 가끔씩 써 보려 한다.

그리고 여담이지만, 책 사기에 앞서 서평을 읽는 편인데 재밌는 얘기들이 많다.
"초보자용"이라는 얘기가 가장 그렇고, 난이도를 표시하는 항목은 거의 대부분 초급이다.!!!
우리나라 개발자들의 실력에 경악을 금할 수 없으나, 어찌하여 이름난 Guru는 하나도 없는지 궁금할 뿐이다.

자랑할 건 아니지만, 학부, 대학원과 직장까지 합치면 대략 12~13년 정도 개발일을 한 것 같다.
아직도 신입사원이 구매한 책을 보며 도움을 받을 때가 있고, 학교다닐 때 보던 책을 다시 들출 일도 많다.
고수라 불릴만한, 아니 어느 정도 개발이 손에 익은 사람이라면 대충 목차만 봐도 어떤 내용을 다루고 누구에게 필요한 책이라는 걸 정확히는 아니더라도 대략은 파악할 수 있다고 본다.
그렇다면 그런 서평을 쓰는 사람들 대부분은 자신의 실력을 과시하고 싶어한다고 밖에 볼 수 없다.

정작 필요한 책들에는 서평이 하나도 없는 것도 슬프다.
하는 일이 보안이나 암호와 관련된 일을 하다 보니 특정 분야의 책을 많이 찾는데, 서평이 있는 책이 드물다.
원서 아니면 별로 있지도 않지만...
낚시질 하지 말고, 정작 필요한, 피가 되고 살이 되는 서평을 써 주시길...
그러는 나도 정작 서평은 쓰지 않는 구차니즘이 부끄럽긴 하다.

여기까진 잡설이고 현재 보고 있는 책은
Security in Computing이라는 책이다.

아직 초반부라 뭐라 말하긴 그렇지만 그리 뛰어나지도, 지저분하지도 않은 보안 관련 개괄서다.
암호부터 네트워크, OS, 윤리적 문제까지 전반적인 내용을 다루고 있다.

많은 부분을 망라하려 해서인지 깊이 파고들진 못하지만 어차피 개괄이므로 좋다.
다 보고 나면 다시 한 마디 적을 수 있겠지...

Secure Hash Algorithm(SHA) 밥은 먹구 다니냐?

SHA도 MD-series와 마찬가지로 Hash algorithm이다.
NSA(미국 국가안전 보장국)이 MD4를 기반으로 작성한 이 알고리즘은 NIST(미국 표준기술 연구소)에 의해 현재 미국 표준으로 적용되어 있다.
구질구질한 설명들은 여기를 참조하면 될 듯 하고, 알고리즘 관련해서는 RFC 3174FIPS 180-2를 보면 될 듯 하다.
친철한 설명과 Code, Test suite가 제공되므로 구현 후, 테스트해 볼 수 있다.
구현이 귀찮으면 아래 자료를 다운받아 사용해도 무방하다.
대신, 늘 그렇듯 오류나 기타 문제들에 대해서는 책임지지 않는다.(역시 배째라..ㅡㅡ)
VC++6.0, Windows XP SP2에서 테스트되었다.
여기에 나와 있는 테스트 문자열로 시험해 보니 맞는 것 같긴 하지만.

Practical Cryptography라는 책에 보면 MD-series는 안전성에 문제가 있을 수 있고, SHA384/512는 비용 대비 효과가 떨어지므로 SHA256의 사용을 강.추. 하고 있다.
그러나 역시 선택은 개발자의 몫인것 같다.
내 자료가 그다지 중요하지도 않은데 SHA512를 구태여 사용할 필요는 없으니까..

SHA384의 경우는 Hash 크기는 384인 주제에 계산량은 512와 동일하다.
따라서, 사용하지 않는 편이 나을 듯 하다.
왜 만들어졌는지, 존재 자체가 궁금한 녀석이다.

여담이지만, 내가 맡은 프로젝트에서도 Hash를 여러 군데 사용하고 있다.
키 생성 관련해서도 사용하고, 무결성 검증을 위해서도 사용한다.
MD5와 SHA1을 적절히 섞어서 남들이 눈치 못채게...
아마도 다른 프로젝트를 진행하더라도 군데군데 사용하게 될 것이다.


SHATest.zip

The MD5 Message-Digest Algorithm 밥은 먹구 다니냐?

통신하는 데이터가 변조, 혹은 유실되었는가를 판단하는 기준으로 해쉬(Hash) 또는 메시지 다이제스트(Message digest)라는 기법을 사용한다. 이는 임의의 문자열을 고정길이의 결과물로 나타내주는 것을 말하며 일방향 함수(One-way function) 사용하여 원문으로 되돌릴 없다.
어떤 데이터를 암호화 및 전송하기 앞서, Hash를 만들어 함께 전송하면, 수신측에서는 복호화하여 Hash를 만들어 전송되어 온 Hash와 비교하여 데이터가 원본 데이터인지 확인하게 된다.

또한, Password의 경우 DB에는 Password가 아닌 Password의 Hash가 저장되며, Password를 입력하면 Hash를 만들어 비교하게 된다.
이렇게 함으로써, Password가 노출되는 것을 방지한다.

Hash에는 MD-series(MD2, MD4, MD5), SHA-series(SHA0, SHA1, SHA256, SHA3846, SHA512) 등이 있다.
MD-series는 작고 가볍지만 2, 4는 이미 쉽게 공격당한다고 알려져 있다.

현재 NIST에서 표준으로 사용되고 있는 Hash algorithm은 SHA이다.
하지만 SHA는 MD5에 비하여 2배 이상의 시간이 소요된다고 한다.(테스트해보진 않았음.ㅡㅡ;;해봐야 겠군..)

MD5는 MIT의 Ronald L. Rivest가 제안한 알고리즘으로 RFC-1321에 기술되어 있다.
RFC-1321는 어찌나 친절하신지, 상세한 설명은 물론이고 C로 작성된 코드 및 테스트 용 문자열과 정답까지 나와있다.
따라서, 위 문서를 보고 코드를 작성했다면 테스트 용 문자열로 제대로 작성되었는지 테스트해 볼 수 있다.

개인적인 생각으론 국방이나, 금융 등 민감한 데이터가 아니라면 MD5만으로도 충분히 강력하다고 생각되며, 굳이 미국 표준이라는 이유로 무거운 SHA를 쓸 필요는 없다고 생각된다.

Computing power 가 좋아져서 MD5가 우습게 깨진다면 잽싸게 다른 알고리즘을 채택해야 겠지만, 그렇게 되면 아마도 암/복호 알고리즘도 바꿔야 할 것이므로 별 상관 없다고 본다.

또한 비록 Work factor(Cryptoanalysis(암호를 깨는 기술/학문)에 들어가는 시간, 노력, 컴퓨팅 자원 등의resource)가 클 지라도 이미 깨진 DES가 아직 사용되는 걸 보면 그리 틀린 말 같지도 않다.

늘 하는 얘기지만 더욱 상세한 설명은 RFC-1321을 참조하시고, 아래의 예제는 VC++ 6.0, Windows XP SP2에서 작성된 것이다.

가져다 쓰셔도 무방하나, 성능 및 무결성을 보장할 순 없다.(배 째라..ㅡㅡ)

MD5Test.zip






 

1 2