DES

Programming/Security | 2011. 11. 29. 22:38
Posted by 신이내린프로그래머

1. DES(Data Encryption Standard)  

    DES는 평문을 64비트로 나눠 56비트의 키를 이용해 다시 64비트의 암호문을 만들어 내는 알고리즘이다.(대칭형 블럭 암호)

     DES 알고리즘의 모습은 대체로 다음과 같다.  64비트의 평문이 16라운드를 거쳐 
    64비트의
 암호문을 나오게 하는 것이다

   INPUT :  64비트의 평문과 키 스케줄을 거친 64비트의 키가  입력된다.  OUTPUT : 64비트의 암호문이 나온다. 

    ① 먼저 64비트의 평문이 첫 라운드를 거치기 전에 IP(initial permutation)를 거친다. 
    ② IP를 거친 뒤 평문은 첫 번째 라운드에 들어가게 되는데, 좌우 각각 
       32비트(Lo,Ro)로 나눠서
 들어간다. 
    ③ 이제 오른쪽 32비트는 키 스케줄에 의해 나온 첫 번째 48비트 키와 F함수에
       들어가고 F함수
는 32비트를 내뱉는다.
    ④ F함수에서 나온 32비트는 2번의 왼쪽 32비트와 XOR연산을 거치게 된다.
    ⑤ 첫 라운드의 오른쪽 32비트는 다음 라운드의 왼쪽 32비트로 들어가고, XOR
       연산을 거친 32
트는 다음 라운드의 오른쪽 32비트로 들어가게 된다. 
    ⑥ 두 번째 라운드부터 16번째 라운드까지 첫 번째 라운드와 같은 방식으로 
       이루어 진다. 
    ⑦ 마지막 라운드를 거친 뒤 IP-1에 들어가게 되는데 이 때는 좌우가 
       바뀌어서( R 16,L16)로 
들어간다. 
    ⑧ IP-1를 거친 것이 64비트의 암호문이다. 

   F함수에는 오른쪽의 32비트 텍스트와 키 스케줄을 거친 키가 들어간다. 

    ① 오른쪽 32비트는 E(expansion)를 거치게 되어 48비트가 된다.
    ② 이 48비트는 키(48비트)와 XOR연산을 하게 된다. 
    ③ XOR연산의 결과로 나온 48비트는 6비트씩 잘려서 8개의 S-box에 들어가게 된다. 
    ④ 각각의 6비트는 S-box를 거친 뒤 4비트가 되어서 나오게 된다. 
    ⑤ 4비트씩 8개가 모여 다시 32비트를 이루게 된다. 
    ⑥ 이 32비트는 P(permutation)를 거쳐서 F함수의 결과(32비트)를 내 놓는다. 

     <키 스케줄>
    사용자는 56비트의 키를 입력하는데 이것에 8비트의 parity bits가 포함되어 키 
   스케줄에는 
모두 64비트의 키가 들어간다.  
   parity bits는 키 사이즈를 64에서 56 비트로 줄여준다.

   키 스케줄을 거친 뒤 16개의 48비트 키가 생성되는데 그 과정은 다음과 같다. 

    ① 키 스케줄을 하기 전에 쉬프트 횟수를 정의하는데 1, 2, 9, 16번째는 1번, 
     나머지는 2번씩
이다.  이것으로 총 28번의 쉬프트가 이루어진다.

    ② 먼저 키는 PC1박스를 거치게 된다.  PC1박스를 거친 후엔 두 부분(각각 28비트)으로 나뉘게 된다.

    ③ 이제 각각의 두 부분은 위에서 정의한 데로 1번째에는 1번의 왼쪽 쉬프트를, 두 번째에는 1번의 왼쪽 쉬프트를, 세 번째에는 2번의 왼쪽 쉬프트를 .....16번째에는 1번의 왼쪽 쉬프트를 하게 된다.

    ④ 첫 번째 키는 1번째 쉬프트를 했을 때 두 부분을 합쳐서 PC2박스를 통과시켜 나오는 48비트 이다.

    ⑤ 두 번째 키는 2번째 쉬프트를 한 후 첫 번째와 같이 두 부분을 합쳐 PC2박스를 통과시켜 나오는 48비트이다.

    ⑥ 이런 식으로 16번째까지 모두 16개의 키가 생성되게 된다.

   2. 다중 DES

      - Double DES

    DES 알고리즘 자체는 변형시키지 않고 DES의 안전성을 증대시키기 위한 방법 중의 하나로

    2개의 다른키로 2번 암호화를 수행한다.

  2중 DES의 암호화

  2중 DES의 복호화

    2개의 서로 다른 키가 적용되어졌기 때문에 2중 DES의 유효한 키는 56 ×112비트이다.

    이 경우의 모든 가능한 키를 시도해보는 횟수는 2112 번 작업이 소요된다.
    관측된  한 쌍의 평문과 암호문(m,c)가 주어졌을 때

 

 관계가 성립하며 아래의 관계식을 구할 수가 있다.

    m에 2개의 모든 가능한 k1을 적용하여 암호화시킨 x값을 정렬하여 보관한다.다음에는 역시 256 개의 모든 가능한 k2를 c에 적용하여 복호화한다. 
    복호화되는 가각의 값을 저장된 테이블에 있는 값과 비교하여 일치하는 항목에 대한 k1과 k2를 선정하여 이것을 하나의 평문과 암호문의 쌍에 적용시켜 검증한다. 

    이 암호분석에 소용되는 작업량은 암호화와 복호화에 2·256 그리고 n개의 값을 정렬하는데


의 작업이 요구되어 전반적으로 263 로 정도의 작업이 소요되어 단일

         DES에 비해 크게 증대되지 못했다. 따라서 "중간충돌" 공격을 방지 할 수 있는 
         Triple 
DES가  제시 되어졌다.

    - Triple DES

             "중간충돌" 공격을 방지할 수 있다.

         

   3. DES 운영방식

       1) ECB(Electronic CodeBook)

         ECB 모드는 DES 암호 방식의 사용 방식 중 가장 간단한 방식으로 평문을 
        64비트씩 나누어 
암호화하는 방식이다. 평문을 64비트씩 나눌 때 마지막 블록이
        64비트가 되지 않을 때는 임
의의 약속된 비트 모양을 패딩(padding)하게 된다. 
       64비트 블록의 평문을 그림 4.6과 같이 
암호화한다.

    이 방식은 동일한 평문 블록 모양에 따라 항상 동일한 암호문이 출력되므로 암호 해독자들

    의 해독 가능성을 높게 만든다. 즉, 문서의 종류에 따라 동일한 문서 모양을 갖고 있으므로 암호문 단독 공격의 가능성을 높게 해준다. 따라서 64비트 길이의 평문 암호화에 유용하게 사용될 수 있으므로 DES 암호 방식의 키 암호화에 사용할 수 있다.

       2) CBC(Cipher Block Chaining)

    DES 암호 방식의 CBC 모드는 출력 암호문이 다음 평문 블록에 영향을 미치게 하여 각 암호문 블록이 전단의 암호문의 영향을 받도록 만든 방식으로 ECB에서 발생하는 동일한 평문에 의한 동일한 암호문이 발생하지 않도록 구성한 동작 모드이다. CBC 모드 동작은 아래 그림과 같이 처음 입력된 평문 블록은 초기 벡터 (initial vector)와EX-OR되어 DES 암호기에 입력된다. 암호기 출력 암호문 은 다음 단 평문 블록 와 EX-OR되어 DES 암호기에 입력된다.


    CBC 모드 동작 중 발생하는 비트 손실이나 오류에 대한 영향을 검토해보자. 전송 중에 암호문 블럭 c에서 발생하는 한 비트의 오류는 복호화된 해당 평문 블럭 m에서는 여러 비트의 영향을 주게되며 다음 단의 복호화된 평문 블럭 mi +1 에는 한 비트의 오류를 유발하게 된다.

    물론 그 다음 단의 복호화된 평문 블럭 mi+2 에는 영향을 주지 않는다. CBC 방식의 특징은 현 단계에서 생성되는 암호문이 그 다음으로 생성되는 암호문 블럭에 영향을 미치기 때문에 특정 암호문 블럭이 전달되는 과정에서 발생되는 채널상의 잡음에 의한 오류는 해당 암호문 뿐만아니라 그 다음 암호문에도 그 효과가 연장된다.

    한편 CBC 모드의 평문 블럭 m에서의 오류 발생시 암호문 분석에 미치는 영향을 살펴보자.

    평문 블럭 m에서의 한 비트 오류는 그 다음에 출력되는 모든 암호문 블럭 ci  ci+1 ci+2에 영향을 미치게 된다. 이러한 특징은 메시지 인증에 유용하게 사용될 수 있다. 구체적으로 말하면 이러한 특징은 문서 인증 부호 MAC(message authentication code)에 사용될  수 있다.


       3) CFB(Cipher FeedBack)

    CFB 모드는 블록 암호가 스트림 암호처럼 동작하도록 한다. CBC처럼, 이 모드도 초기벡터를 이용하지만, 내부 처리가 조금 더 필요하다. CFB 모드에서 블록 암호는 블록 크기보다 작은 데이터의 조각을 암호화할 수 있다. 실제로, CFB는 하나의 비트에서부터 블록까지 어떠한 크기의 데이터도 암호화할 수 있다. 일반적으로, CFB는 동시에 한 바이트(8비트)를 암호화하거나 복호화하는 데 사용하며 이것을 CFB8이라고 한다. 

    아래 그림은 CFB8을 이용한 한 바이트의 암호화를 보여준다.


    『 암호화 (p→c) 
        ① 블록 암호를 이용하여 기본적 암호의 블록 크기만큼 버퍼를 암호화.
             초기에 버퍼는 IV로 채워진다.

         ② 암호화된 버퍼의 최좌단 비트 수와 평문은 XOR로 연산됨. 그 결과 암호문이 출력됨.
             암호화된 버퍼의 나머지는 폐기됨.
             CFB8에서, 암호화된 버퍼의 최좌단 바이트는 평문과 XOR 

         ③ CFB8에서, 버퍼는 한 바이트 왼쪽으로 이동.
              암호문은 버퍼의 오른쪽편에 있는 빈 공간을 채우는 데 사용된다.
              이 버퍼는 다음 암호화에서 다시 사용될 것이다.
              이 과정이 계속되면, 버퍼는 전부 암호문으로 채우는 데 사용될 것이다.

    『 복호화 (c→p) 
       ① 버퍼는 블록 암호를 이용하여 암호화한다. 
            암호문 바이트를 복호화할 지라도, 여전히 버퍼를 암호화 하기 위해 블록 암호를 이용
            한다.

        ② 암호화된 버퍼의 최좌단 비트는 평문 출력을 처리하는 암호문과 XOR로 연산된다.
             다시, 암호화된 버퍼의 나머지는 폐기된다.

        ③ 원래 버퍼는 왼쪽으로 이동하고, 암호문으로 채워진다. 
            이 버퍼는 다음 복호화에서 다시 사용될 것이다.


       4) OFB(Output FeedBack)

    OFB 모드는 내부 버퍼가 갱신되는 것을 제외하고 CFB모드처럼 동작한다.

    내부 버퍼가 왼쪽으로 이동될 때, 오른쪽의 공간은 암호화된 버퍼의 가장 왼쪽 비트로 채워

    진다.
     이론적으로, OFB는 암호의 블록 크기보다 작거나 같은 어떠한 비트 크기로도 사용될 

    수 있다. 그러나 피드백 크기가 기본적 암호의 블록 크기보다 작을 때 OFB의 성능은 떨어진

    다. 단지 피드백 크기가 암호 블록 크기와 같을 때에만 사용하는 것이 좋다.



    <DES.h 파일>
    [CODE]
    /************************************************************************/
    /* DES Algorithm!
    /* Jinsik, Park
    /************************************************************************/
    #ifndef DECLARE_DES
    #define DECLARE_DES

    #include "stdafx.h"

    #include <string>
    using namespace std;

    #ifndef DLLEXPORT
    #define DLLEXPORT __declspec( dllexport )
    #endif

    #ifndef DLLIMPORT
    #define DLLIMPORT __declspec( dllimport )
    #endif

    #ifdef DESIMPORT
    class DLLIMPORT CDES
    #else
    class DLLEXPORT CDES
    #endif
    {
    public:
     CDES()
     {}
     //암호하고, 파일 이름을 넘겨 받는다.
     int DESEncrypt( char * pFileName, char * pDesFileName, char * pPassword,  int nLength );

     
     //암호하고, 저장할 파일 이름을 넘겨 받는다.
     int DESDecrypt( char * pFileName, char * pDesFileName, char * pPassword  , int nLength  );

    protected :
     void DESKeyGenerate( char * pKeySource );
     //8 byte가 넘는 key를 8 byte로 줄이기
     void DESKeyTruncate( char * pKeySource );
     //Char를 2진수 코드로 만들기 
     void DESChar2Binary( int * piTarget, char * pSource, int iSourceLen );
     //8개의 2진수를 하나의 Char로 만들기
     char DESBinary2Char( int * iSource );
     void DESSwap32Bit( int * piLeftBit, int * piRightBit, int * piBufferBit );
     void DESRound( int * piLeftData, int * piRightData );
     void DESStart( int iJobType, int iDataSize, char * pSrcData, char * ptgtData );
     int DESOperation(int iJogType, char * pInput, char * pOutput, char * pKey, int nLength);
    };

    #endif
     [/CODE]

    <DES.cpp파일>
    [CODE]
    #include "Stdafx.h"
    #include "Define.h"   //define 
    #include "DES.h"
    /************************************************************************/
    /* DESStart( int iJobType, int iDataSize, char * pSrcData, char * ptgtData )
    /************************************************************************/
    void CDES::DESStart( int iJobType, int iDataSize, char * pSrcData, char * ptgtData )
    {
     int srcBinary[64] = { 0, }, tgtBinary[64] = { 0, }, binaryBuff[64] = { 0, };
     int leftData[32] = { 0, }, rightData[32] = { 0, }, swapBuff[32] = { 0, };
     int tgtIndex=0;
     char textBuff[9] = { '\0', };
     int i, j, k;

     // Data의 끝까지 가면서 암호화, 복호화 한다 
     for( i = 0, tgtIndex = 0; i < iDataSize; i++ ) 
     { 
      memset( textBuff, 0, 9 );
      // srcData에서 8자씩 textBuff로복사 
      memcpy( textBuff, ( pSrcData + tgtIndex ), 8 ); 

      // textBuff를 binary로  
      DESChar2Binary( binaryBuff, textBuff, 8 ); 

      // Initial Permutation 
      for( j = 0; j < 64; j++ )  
       srcBinary[j] = binaryBuff[ MAT_IP[j]-1 ];

      //Encryption일 경우
      if( iJobType == ENCRYPT ) 
      {
       // 하나의 64bit를 둘의 left, right data 로 나눈다
       for(j=0; j<32; j++)
       { 
        leftData[j] = srcBinary[j];
        rightData[j] = srcBinary[j+32];
       }
      }
      // 복호화 할경우 left data와 right data의 위치를 바꾼다 
      else  
      {
       // 하나의 64bit를 둘의 left, right data 로 나눈다
       for( j = 0; j < 32; j++ )
       { 
        rightData[j] = srcBinary[j];
        leftData[j] = srcBinary[j+32];
       }
      }

      DESRound( leftData, rightData );

      //Encrypt일 경우
      if( iJobType == ENCRYPT ) 
       DESSwap32Bit( leftData, rightData, swapBuff );

      // 둘의 left, right data 를 하나의 64bit로 합한다 
      for( j = 0; j < 32; j++ )
      { 
       // 또한 32bit swap을 한다 
       binaryBuff[j] = rightData[j]; 
       binaryBuff[j+32] = leftData[j];
      }

      // Inverse Initial Permutation 
      for( j = 0; j < 64; j++ ) 
       tgtBinary[j] = binaryBuff[ MAT_IP_1[j]-1 ];

      memset( textBuff, 0, 9 );

      // tgtBinary를 ascii로 변형후 textBuff에 저장 
      for( j = 0, k = 0; j < 64; j += 8, k++ ) 
       textBuff[k] = DESBinary2Char( & tgtBinary[j] );


      // textBuff의 내용을 tgtData로 복사 
      memcpy( ( ptgtData + tgtIndex ), textBuff, 8 ); 
      tgtIndex += 8;
     }
    }

    /************************************************************************/
    /* DESSwap32Bit( int * piLeftBit, int * piRightBit, int * piBufferBit )
    /************************************************************************/
    void CDES::DESSwap32Bit( int * piLeftBit, int * piRightBit, int * piBufferBit )
    {
     int i;

     for( i = 0; i < 32; i++)
      piBufferBit[i] = piLeftBit[i];

     for( i = 0; i < 32; i++ )
      piLeftBit[i] = piRightBit[i];

     for( i = 0; i < 32; i++ )
      piRightBit[i] = piBufferBit[i];
    }

    /************************************************************************/
    /* DESRound( int * piLeftData, int * piRightData )
    /************************************************************************/
    void CDES::DESRound( int * piLeftData, int * piRightData )
    {
     int sboxOut[ 32 ] = { 0, }, leftFinal[ 32 ] = { 0, }, permuOut[ 32 ] = { 0, };
     int eBuff[ 48 ] = { 0, }, eBuffOut[ 48 ] = { 0, };
     int sboxRow, sboxCol, sboxValue;
     int i, j, k, keyIndex;

     //16번의 round를 거친다 
     for( keyIndex = 0; keyIndex < 16; keyIndex++ )
     { 
      for( i = 0; i < 32; i++ )
       leftFinal[ i ] = * ( piRightData + i );

      /* E table 적용 */
      for( i = 0; i < 48; i++ )
      {  
       eBuff[ i ] = * ( piRightData + ( MAT_EXP[ i ] -1 ) );
      }

      // eBuff xor key 
      for( i = 0; i < 48; i++ )
      {  
       eBuffOut[i] = eBuff[i] ^ KEY[keyIndex][i];
      }

      // sBox 적용 
      for( i = 0, j = 0, k = 0; i < 8; i++ )
      { 
       sboxRow = (eBuffOut[j+0] * 2) + eBuffOut[j+5];
       sboxCol = (eBuffOut[j+1] * 8) + (eBuffOut[j+2] * 4) + (eBuffOut[j+3] * 2) + eBuffOut[j+4];
       sboxValue = MAT_SBOX[i][sboxRow][sboxCol];
       sboxOut[k]   = ((sboxValue & 8)  ? 1:0 );
       sboxOut[k+1] = ((sboxValue & 4)  ? 1:0 );
       sboxOut[k+2] = ((sboxValue & 2)  ? 1:0 );
       sboxOut[k+3] = sboxValue & 1; 
       j += 6;
       k += 4;
      }

      //sboxOut 에 p table적용 
      for( i = 0; i < 32; i++ )  
       permuOut[ i ] = sboxOut[ MAT_PERMU[ i ] - 1 ];  

      // permuOut xor leftData 를 rightData에 저장
      for( i = 0; i < 32; i++ ) 
      {  
       * ( piRightData + i ) = * ( piLeftData + i ) ^ permuOut[ i ];
      }

      //첨에 복사한 leftFinal을 leftData에 복사 
      for( i = 0; i < 32; i++ )  
       * ( piLeftData + i ) = leftFinal[ i ];
     }
    }

    /************************************************************************/
    /* DESKeyGenerate( char * pKeySource )
    /************************************************************************/
    void CDES::DESKeyGenerate( char * pKeySource )
    {
     int keySchedule[ 16 ] = { 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1 };
     int binaryKey[ 64 ] = { 0, };
     int pc1[ 56 ] = { 0, };
     char tempKey[ 9];
     int i, j, k, tmp1, tmp2, srcLen;

     //입력된 암호의 길이가 8자 이상일 경우 Truncate해 줌
     if( ( strlen( pKeySource ) ) > 8 ) /* 입력된 암호의 길이가 8자 이상이면 */
      DESKeyTruncate( pKeySource );

     strncpy( tempKey, pKeySource, 8 );
     tempKey[8] = '\0';

     srcLen = strlen( tempKey );
     DESChar2Binary( binaryKey, tempKey, srcLen );
     memset( tempKey, 0, 8 );

     //64bit를 56bit로 줄이는거 
     for( i = 0; i < 56; i++ )  
      pc1[i] = binaryKey[ MAT_PC_1[i]-1 ];

     for( i = 0; i < 16; i++ )
     {
      for( j = 0; j < keySchedule[ i ]; j++ )
      {
       tmp1 = pc1[0];
       tmp2 = pc1[28];
       for(k=1; k<28; k++)
       {
        pc1[k-1] = pc1[k];
        pc1[k+27] = pc1[k+28];
       }
       pc1[27] = tmp1;
       pc1[55] = tmp2;
      }
      //56bit 를 48bit로 줄여서 저장 - 최종 key 
      for(j=0; j<48; j++)  
       KEY[i][j] = pc1[ MAT_PC_2[j]-1 ];
     }
    }

    /************************************************************************/
    /* DESKeyTruncate( char * pKeySource )
    /************************************************************************/
    void CDES::DESKeyTruncate( char * pKeySource )
    {
     char * temp;
     int srcLen = 0, dev4;
     int i, j;

     srcLen = strlen( pKeySource );
     temp = ( char * )malloc( srcLen + 1 );
     memset( temp, 0, srcLen +1 );
     strcpy( temp, pKeySource );
     memset( pKeySource, 0, srcLen );

     dev4 = srcLen / 4;

     srcLen-- ;

     for(i=0,j=0;i<4;i++,j+=dev4)
     {
      * ( pKeySource + i ) = * ( temp + srcLen - j );
      * ( pKeySource + i + 4 ) = * ( temp + j );
     }  
    }

    /************************************************************************/
    /* DESChar2Binary( int * piTarget, char * pSource, int iSourceLen )
    /* char 를 binary형태로 만들기 
    /************************************************************************/
    void CDES::DESChar2Binary( int * piTarget, char * pSource, int iSourceLen )
    {
     int targetIndex = 0, i, j;
     char oneChar, temp1, temp2;

     for( i = 0 ; i < iSourceLen; i++)
     {
      oneChar=*( pSource + i);
      for( j = 7; j >= 0; j-- )
      {
       temp1 = oneChar >> j;
       temp2 = temp1 & 0x0001;
       * ( piTarget + targetIndex ) = ( temp2 == 1 ? 1 : 0 );
       targetIndex++;
      }
     }
    }

    /************************************************************************/
    /* DESBinary2Char( int * iSource )
    /* 8개의 2진수를 하나의 Char로 만듬 
    /************************************************************************/
    char CDES::DESBinary2Char( int * iSource )
    {
     char temp;
     int i, j, inTemp=1, chTemp=0;

     for( i = 0; i < 8; i++ )
     {
      inTemp=1;
      if( * ( iSource + i) ) 
      {
       for(j=7; j>i; j--)
        inTemp *= 2;
       chTemp += inTemp;
      }
     }
     temp=chTemp;
     return temp;
    }

    /************************************************************************/
    /* DESEncrypt( char * pFileName, char * pDesFileName, char * pPassword  )
    /************************************************************************/
    int CDES::DESEncrypt( char * pFileName, char * pDesFileName, char * pPassword, int nLength  )
    {
     return DESOperation( ENCRYPT, pFileName, pDesFileName, pPassword, nLength);
    }

    /************************************************************************/
    /* DESDecrypt( char * pFileName, char * pDesFileName, char * pPassword  )
    /************************************************************************/
    int CDES::DESDecrypt( char * pFileName, char * pDesFileName, char * pPassword, int nLength  )
    {
     return DESOperation( DECRYPT, pFileName, pDesFileName, pPassword, nLength);
    }

    /************************************************************************/
    /* DESOperation(int iJogType, char * pFileName, char * pDesFileName, char * pPassword  )
    /************************************************************************/
    int CDES::DESOperation(int iJogType, char * pInput, char * pOutput, char * pKey, int nLength)
    {
     int tempKey[16][48];
     long int datasize = 0, readSize = 0, writesize = nLength;
     char * pInputBuff, * pOutputBuff;
     char nameTemp[100] = {0, };
     char qprkDes[100] = {0, };
     int i, j;

     DESKeyGenerate(pKey);

     
     if(iJogType == DECRYPT)
     {
      for(i=0; i<16; i++)
      {
       for(j=0; j<48; j++)
       {
        tempKey[15-i][j] = KEY[i][j];
       }
      }
      for(i=0; i<16; i++)
      {
       for(j=0; j<48; j++)
       {
        KEY[i][j] = tempKey[i][j];
       }
      }
     }
     
     pInputBuff = new char [BUFFSIZE];
     pOutputBuff = new char [BUFFSIZE];

     int iCount = 0;

     int iRength = ( ! iJogType ) ? (( nLength / RWSIZE ) + 1 ) :
             ( nLength / RWSIZE );
     for( i = 0; i < iRength ; i++ )
     { 
      ZeroMemory(pInputBuff, BUFFSIZE);
      ZeroMemory(pOutputBuff, BUFFSIZE);

      if(writesize > RWSIZE)
      {
       memcpy(pInputBuff, &pInput[readSize], RWSIZE);
      }
      else
      {
       memcpy(pInputBuff, &pInput[readSize], writesize);
      }
     
      //Encrypt 시작
      DESStart( iJogType, RWSIZE / 8, pInputBuff, pOutputBuff ); 
      //memcpy(&pOutput[readSize], pOutputBuff, RWSIZE);
     
      if(writesize > RWSIZE)
       memcpy(&pOutput[readSize], pOutputBuff, RWSIZE);
      
      readSize += RWSIZE;
      writesize -=  RWSIZE;
     }

     delete [] pInputBuff;
     pInputBuff = NULL;
     delete [] pOutputBuff;
     pOutputBuff = NULL;
     
     return readSize - writesize; 
    }
    [/CODE]

 

include <> 와 "" 의 차이

Programming/C++ | 2011. 11. 29. 03:32
Posted by 신이내린프로그래머
인터넷을 돌아다니가 볼랜드포럼의 wfc.h라는 것을 받았다. 
Windows Foundation Classes라고 한다.
이것을 C++빌더에서 사용해보자.

인클루드 패스에 대해서 살펴보자.

인클루드 파일을 지정하는 데는 두가지 방법이 있는데,
첫번째는 인클루드 
디렉토리로서 디폴트로 지정된 디렉토리에 있는 경우고,
두번째는 그외의, 그러니까 

소스가 있는 현재 디렉토리에 있든지 다른 디렉토리에 있을 경우이다. 

#include <stdio.h> 라고 하면, 이 인클루드 파일은 현재 컴파일하고 있는 
컴파일러에 디폴트로 세팅된 디렉토리에서 검색하게 된다. 빌더의 경우에는 
프로젝트 옵션에서 이 디폴트 인클루드 디렉토리를 설정하게 되어있는데, 
빌더 설치 직후에는 다음과 같이 설정되어 있다. 
$(BCB)\include;$(BCB)\include\vcl 
이 말은, 빌더의 루트 밑의 /include 디렉토리와 빌더 루트 밑의 /include/vcl 
디렉토리를 디폴트 인클루드 디렉토리로 설정했다는 뜻이 된다. 

한편, 디폴트 인클루드 디렉토리로 설정되지 않은 파일을 인클루드 할 때는, 
인클루드 프리프로세서에서 < 와 > 대신 "으로 앞뒤를 묶는다. 
#include "myheader.h" 
패스를 별도로 지정하지 않았으므로 현재 프로젝트 소스가 있는 디렉토리를 
대상으로 찾아보게 된다. 만약 다른 디렉토리라면, 
#include "..\myheader.h" 
라든지, 
#include "c:\MyHaeders\myheader.h" 
이런식으로 지정할 수 있다. 

소스 디렉토리에다 넣었다면 
디폴트 인클루드 디렉토리에 소스 디렉토리를 추가하든지, 혹은 인클루드 
프리프로세서 자체에서 소스 디렉토리의 패스를 지정해주면 된다. 
그러니까... 
#include "c:\Program Files\Borland\Cbuilder4\Source\wfc.h" 
라고 하면 됨. 
 

JPEG에 사용된 압축 알고리즘

Programming/Image Processing | 2011. 11. 27. 01:38
Posted by 신이내린프로그래머

JPEG 국제 표준으로 정식 명칭은 ‘Digital Compression and Coding of Continuous Tone Still Image’이다이는 ISO/IEC 10918-1(ITU권고 T.81) 표준화되어 있다.

JPEG에서는 DC성분과 AC성분을 따로 압축한다.  DC성분은 DCT 행한 첫째 값이고 AC성분은 나머지 값을 말한다.

JPEG 데이터를 8x8 블록 단위로 읽어서 처리한다

DC성분은 12가지의 값을 가질 있다그리고 화면에서 DC값들은 비슷한 경우가 많기 때문에 새로운 블록을 처리할 이전 블록의 DC값과 비교해서 차이를 이용해 압축을 수행한다.

AC성분은지그재그 스캔 데이터를 가지고 압축한다기본적인 JPEG에서는 AC값이 모두 10가지 값을 가질 있다.  AC값은 바이트를 4비트씩 나눠 앞쪽에는 연속된 데이터의 개수가 들어가고 뒤에는 코드값이 들어간다( Run Length Coding). 또한 0 16 이상 연속으로 나오면 이를 블록의 (EOB)이라고 인식한다.

이와 같은 식으로 우선 한번의 작업을 거친 후에 데이터를 가지고 엔트로피 코딩에 들어간다.

 

허프만 코딩(Huffman coding)

JPEG에서 사용하는 엔트로피 코딩은 Huffman coding Arithmetic coding 가지이다 가지를 모두 사용하는 것은 아니고 파일에 따라서 어떤 파일은 Huffman coding, 어떤 파일은 Arithmetic coding 사용하는 것이다.  Huffman coding 허프만이란 사람이 개발한 코드로 구현하기 쉽고 사용료가 없기 때문에 가장 많이 사용되는 코드이다. Arithmetic coding IBM에서 개발한 코드로, 압축률은 Huffman coding보다 약간 좋다고 알려져 있지만, 실수연산을 하기 때문에 코드가 복잡하고 IBM 사용료를 지불해야 하기 때문에 사용하지 않는다.

 

파라미터

크기(bits)

   

DHT

16

FFC4(h)

 허프만 테이블임을 나타내는 마커 코드

Lh

16

 

 허프만 테이블의 길이

Tc

4

0,1

 table class(0=DC, 1=AC)

Th

4

0,1

 Identifier

Li

8

0-255

 코드길이가 i 허프만 코드의 개수

Vi,j

8

0-255

 허프만 코드에 해당하는

1 허프만 테이블 구문









Discrete Cosine Transform(DCT)

1차원 DCT           : C(u) = alpha (u)  sum from {x=0} to {N-1} f(x) cos [ { (2x+1) u pi } over { 2 N } ]

1차원 IDCT          :f(x) = sum from {u=0} to {N-1} alpha (u) C(u) cos[ { (2x+1) u pi } over { 2 N } ]

u, x 0에서 N-1까지이고, alpha 다음과 같이 정의된다.

alpha (u) &= root { 1 over N } ~~~~~for~ u=0# &=root { 2 over N } ~~~~~for~u!=1

2차원 DCT              :C(u,v) = alpha (u) alpha (v) sum from { x=0 } to { n-1 } sum from {y=0} to {n-1} f(u,v) cos [ {2x+1) u pi } over { 2N } ] cos [ { (2y+1) u pi } over {2N} ]

2차원 IDCT          :f(u,v) = sum from { x=0 } to { n-1 } sum from {y=0} to {n-1} alpha (u) alpha(v) C(u, v) cos [ {2x+1) u pi } over { 2N } ] cos [ { (2y+1) u pi } over {2N} ]

 

JPEG Encoding, Decoding 방법

입력 영상을 8x8블럭으로 나눈다.

각각의 블록에 대해 DCT 행한다.

양자화를 행한다.

계수값을 코딩한다.

헤더를 붙이고 형식에 맞춰서 저장한다.

파일을 읽는다.

값을 디코딩한다.

역양자화를 행한다.

각각의 블록에 대하여 IDCT 행한다.

원영상을 재구성한다.





JPEG 파일에서 Huffman 코딩 : 
JPEG 파일에서는 DCT-양자화를 거친 데이터를 Huffman 코딩 방식으로 압축을 한다. Huffman 코드의 최대 길이는 16비트로 제한되어 있다. DCT계수 가운데 DC 계수와 AC 계수를 따로 분리하여 코딩하고 필요에 따라 YCbCr 성분 별로도 따로 코딩을 한다. Huffman 코딩은 서로 같은 데이터가 많을 수록 압축 효율이 좋기 때문에 이렇게 서로 비슷한 성분들끼리 분리하여 코딩을 하는 것이다.
보통 DC계수의 크기는 AC계수의 크기보다 크며 양자화된 AC계수는 대부분이 0이다. AC계수끼리 묶으면 대부분의 데이터가 0인데 보다 압축효율을 높이기 위해 0으로 된 데이터들은 PCX파일에서 사용한 Run-length encoding 방식으로 압축을 한다. 즉, 데이터 자체를 저장하는 것이 아니라 0의 개수를 저장하는 것이다. 0이 아닌 AC계수와 DC계수는 Huffman 인코딩을 하는데 값 자체를 인코딩하는 것이 아니고 인접한 값과의 차이를 인코딩한다. 예를 들어 DC 계수 배열이 122, 123, 124, 125, 126 이런 식이라면 실제 값이 아닌 인접한 값과의 차이인 122, 1, 1, 1, 1을 인코딩하는 것이다. 이렇게 하면 서로 똑같은 값들이 많아지기 때문에 값 자체를 인코딩할 때 보다 훨씬 더 압축 효율이 높아진다. 이런 이유 때문에 인접한 픽셀들끼리의 변화가 적은 사진 이미지가  도형 이미지보다 압축 효율이 좋다.

'Programming > Image Processing' 카테고리의 다른 글

영상처리  (0) 2011.11.30
레이저마우스  (0) 2011.11.26
 

MFC 헤더 및 라이브러리파일 설명

Programming/MFC | 2011. 11. 26. 16:09
Posted by 신이내린프로그래머

■ 런타임 라이브러리

 

- Advapi32.lib   : 레지스트리 사용과 보안 API들과 같이 대부분의 고급 API 서비스들을 위한 임포트 라이브러리.

                      임포트 라이브러리와 링크하면 여러분의 응용 프로그램이 윈도우즈 Advapi32.dll에 있는 함수를 엑세스할수 있다.

 

- Atl.lib            : ATL을 위한 지원 라이브러리

 

- Binmode.obj  : 이 모듈과 링크하면 C 런타임 라이브러리에 의해 열리는 파일들이 기본적으로 이진 모드에서 열린다.

 

- Cap.lib          : Call Attributed Profiler에 대한 인터페이스. 이 도구는 함수 호출 패턴을 분석함으로써 Win32 응용 프로그램을 세밀하게

                     조정할수 있게 해준다.

 

- Chkstk.obj     : 런타임 스팩 깊이 검사 프로브. 이 개체 모듈은 모든 함수 호출들이 이루어지기 전에 스택의 깊이를 검사함으로써

                     여러분의 응용 프로그램이 스택 오버플로우를 일으키지 않았다는 것을 검사하는것을 돕는다. 윈도우즈 NT는 여러분 응용

                     프로그램의 스택 세그먼트를 주의 깊게 측정하고 스택 오버플로우 조건에서 응용 프로그램을 잘 종료시켜주기 때문에

                     이 파일이 거의 필요없다.

 

- Comctl32.lib   : 윈도우즈 공통 컨트롤.

 

- Comdlg32.lib  : 윈도우즈 공통 대화상자. 이 라이브러리는 표준 파일열기. 파일 저장.글꼴 선택.출력.색상 선택 대화상자에 대한 인테페이스제공.

 

- D3drm.lib       : Direct3D랜더링 모델 API

 

- Ddraw.lib       : DirectDraw API

 

- Dflayout.lib     : 복합 문서 파일들에 저장 관리를 수행하는 OLE 함수들을 위한 임포트 라이브러리.

 

- Gdi32.lib        : 윈도우즈 GDI 임포트 라이브러리.

 

- Glu32.lib        : OpenGL 그래픽 핵심 함수들

 

- Libc.lib         : 표준 c 런타임 라이브러리.

 

- Kernel32.lib   : 윈도우즈 커널 임포트 라이브러리.

 

- Libcid.lib      : 표준 iostream 구현이 있는 표준 c 라이브러리의 디버그빌드.

 

- Libcp.lib       : 표준 c++ 런타임 라이브러리.

 

- Mapi32.lib     : MicroSoft Mail API 라이브러리

 

- Mfcuia32.lib   : OLE 공통 사용자 인터페이스의 MFC 구현을 제공하는 코드.

 

 

 

■ 헤더파일

 

- Afx.h             :  윈도우즈를 사용하지 않는 MFC 응용프로그램을 위한 메인 헤더파일.이 헤더는 콘솔기반 MFC 응용 프로그램에서 필요하다.

                         이것은  윈도우즈 바깥에서 동작하는 모든 클래스들을정의한다. 여기에는 콜렉션 클래스들과 모든 애플리케이션 프레임워크

                         클래스들이 포함된다. 여러분이 콘솔 애플리케이션을 작성하고 있다면 다른 MFC 파일들 전에 이 파일을 포함시켜야한다.

                          여러분이 윈도우즈 응용 프로그램을 작성하고 있다면 Afx.h 대신 Afxwin.h를 사용한다.

 

- Afxadv.h        :  이 헤더 파일에 일부 변화하는 MFC 클래스들의 정의가 들어 있다. 이 클래스들을 별도의 헤더로 분리하는 것은 MFC의 사용에

                        영향을 주지 않지만.MFC의 어떤 클래스들이 변경 상태에 있는지알려주는데 도움을 준다. 여기에 있는 클래스들은

                        온라인 도움말의 "Technical Notes" 섹션에 문서화 되어 있다. 이것은 차기 버전에서 바뀔수도 있고

                      , 더 안정적이고 문서화된 라이브러리로 될수도 있다.

                        CRecentFileList,CDockState,CSharedFile은 모두 이 헤더에 선언되어 있고, 이 헤더는 Afxpriv.h에 의해 참조된다.

 

- Afxcmn.h       : 이 파일은 윈도우즈 공통 컨트롤을 위한 정의들을 포함하고 있다.

                         여러분이 아직 Afxwin.h를 포함시키지 않았다면 이 파일을 사용할 수 없다.

 

 

 

- Afxcoll.h         : 이 파일은 MFC 컨테이너 클래스들을 위한 정의들을 포함하고 있고,Afx.h 의 내용을 의존한다. Afxcoll.h는

                          CObject 스타일 컬렉션과 타입안전 컬렉션들을 위한 정의들을 포함하고 있다. 템플릿 컬렉션 클래스들은 Afxtempl.h에 있다.

 

- Afxctl.h           : 이 파일은 ActiveX 컨트롤을 작성하는데 사용되는 정의들과 클래스들을 포함하고 있다. 여러분은 여러분의 컨트롤 프로젝트에서                           Afx.h 나 Afxwin.h대신 이 파일을 포함시켜야한다.  

 

- Afxcview.h      : 이 파일은 트리나 리스트 공통 컨트롤에 기반을 둔 CView 유도 클래스들을 위한 정의들을 포함하고 있다.

                        좀더 효과적인 링크와 구분을 위해 이 파일이 Afxwin.h 및 Afxcmn.h과 분리되어 있다.

                        이렇게 하면 실행 파일의 크기가 더 작아지고, 실행속도고 빨라진다.

                        여러분이 CTreeView 나 CListView클래스를 사용하면 이 헤더 파일이 Afxwin.h 다음에 오게 해야한다.

 

- Afxdb.h           : 이파일은 ODBC 기반 데이터베이스 응용 프로그램 개발을 지원하는 클래스들을 포함하고 있다.

                          이 파일은 CDatabase 와 CRecordset을 포함한다. 이 파일은 데이터베이스 응용 프로그램이 사용하는

                          글로벌 함수들(RFX_* 레코드 필드 교환 명령어등)을 정의한다. 여러분은 데이터베이스 클래스들을 사용할 때 여러분의

                          응용 프로그램에 이 헤더 파일에 대한 참조를 넣어야한다. 여러분은 Afx.h 나 Afxwin.h를 먼저 포함시킬 필요가 있을것이다. 

 

- Afxdisp.h        : 이 파일은 COM 디스패치 인터페이스를 위한 선언과 정의들을 포함하고 있다. 기본적으로 이것은 CCmdTarget 핸들 자동화를

                         만들기 위해 필요한 모든 확장들을 포함하고,MFC가 COM프로그래밍을 더 쉽게 만들기 위해 제공하는 모든 데이터타입과

                         래퍼클래스들을 포함한다. 여러분이 COM을 사용하고 있을때만 이 인클루드 파일을 여러분의 리스트에 포함시키길 바란다.

                         그렇지 않으면 여러분의 프로그램이 필요하지 않은 많은 런타임 dll들을 의존할 것이다. 이것은 여러분의 프로그램을 아주 느리게

                        할것이다. 여러분이 Afxcmn.h를 사용하고 있고 OLE클래스들을 필요로 하면 Afxdisp.h를 포함시켜야한다.

 

- Afxdlgs.h        : MFC 확장 대화샂아 클래스들은 여기서 선언된다.

                          이 클래스들은 윈도우즈 공통 대화 상자를 위한 mfc래퍼들뿐 아니라                    

                         CPropertySheet와CPropertyPage도 포함한다. 여러분이 Afxext.h를 포함시킬때 이 파일도 포함된다.

 

- Afxdllx.h         : 이 파일은 실제로 MFC확장 DLL을 작성할때 여러분의 소스 모듈들중의 하나에 포함시킬 필요가 있는 소스코드를 포함한다.

 

- Afxext.h          :  이 헤더파일은 '확장된' MFC 클래스들을 선언한다.

                           이것은 CStatusBar와 CToolBar와 같이 향상된 사용자 인터페이스클래스들을 포함하고 있다.

 

- Afxhtml.h        : define CHtmlView class.

 

- Afxinet.h         : 인터넷클라이언트 응용 프로그램을 작성할 수 있게 해주는 CHttpConnection과 같은 클래스들을 정의한다.

 

- Afxisapi.h       : ISAPI 인터페이스를 사용하는 인터넷 서버 응용 프로그램의 작성을 돕는 클래스를 정의한다.

 

- Afxmt.h           : 이 파일은 멀티스레드 응용 프로그램을 위한 동기화 객체들을 포함하고 있다.

                         여러분은 콘솔 응용 프로그램에서 이 클래스들을 사용할 수도 있지만 항상 Afx.h를 먼저 포함해야한다.

 

-Afxole.h           : 이 파일은 핵심 OLE 지원을 위해 필요한 클래스들을 선언한다. 이 클래스들은 ole를 지원하는 COleDocument 기반 클래스들과

                         모든 OLE 항목들과 이것들과 함께 오는 드레그 앤 드롭 지원을 포함하고 있다. 여러분의 응용프로그램에 OLE를

                         사용한다면 Afxwin.h 다음에 이 파일을 포함시킬 필요가 있다.

 

- Afxres.h         : 이 파일은 리소스 스크립트에 의해 사용된다.MFC응용 프로그램을 위한 .rc파일은 이것을 직접 포함 시킨다.

                         여러분은 이것을 직접 참조할 필요가 거의 없을것이다.  정의된 모든 MFC리소스들을 위한 전처리기 기호정의들을 포함한다.

 

- Afxsock.h       : 이 파일은 CSocket 과 CAsyncSocket 클래스들을 위한 정의들을 포함한다.

                          이 클래스들은 네트워크 기반 통신 API인 윈도우즈 소켓API를 래핑한다.

 

- Afxtempl.h      : 이 파일은 CSocket 과 CAsyncSocket 클래스들을 위한 정의들을 포함한다.

                         이 클래스들은 네트워크 기반 통신 API인 윈도우즈 소켓API를 래핑한다.

 

- Afxwin.h        : 이 파일은 윈도우즈에서 실행될 MFC 응용 프로그램의 중요 헤더이다.

                        여러분이 윈도우즈 프로그램을 작성하려고 할때 .Afx.h 다음에 이 파일을

                        사용해야한다.콘솔 애플리케이션을 만들고 싶으면 이 파일을 사용하지 않아야한다.

                        이 파일은 CWnd및 많은 유도 클래스들과 같은 기본적인 클래스들을 정의한다.

 

레이저마우스

Programming/Image Processing | 2011. 11. 26. 05:15
Posted by 신이내린프로그래머


속도를 위해 그레이모드로 하여 밝은값을 찾게 하였다. 밝은 값은 슬라이드바로 조절 가능. 클릭, 더블클릭, 오른쪽마우스 클릭 가능

'Programming > Image Processing' 카테고리의 다른 글

영상처리  (0) 2011.11.30
JPEG에 사용된 압축 알고리즘  (0) 2011.11.27
 

내가 만든 학교 어플

Programming/Android | 2011. 11. 26. 05:03
Posted by 신이내린프로그래머

 

 

 

 

 

 

윈도우에서 제공하는 간단한 방식의 암복호화 소스

Programming/Security | 2011. 11. 26. 03:40
Posted by 신이내린프로그래머

#include <WinCrypt.h>
int Encrypt(LPCTSTR lpszIn, LPTSTR lpszOut, int nBufLen)
{
 int result = 0;

 HCRYPTPROV hProv;
    HCRYPTHASH hHash;
    HCRYPTKEY hKey; 
    CString  csPass = "PASSWORD";
 DWORD  dwLen = strlen(lpszIn);

    if(!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0))
    {
        if(!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET))
        {
            return -1;
        }
    }
 strcpy(lpszOut, lpszIn);
 
    CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash);
    CryptHashData(hHash, (BYTE*)(LPCTSTR)csPass, csPass.GetLength(), 0);
    CryptDeriveKey(hProv, CALG_RC4, hHash, 0x0080*0x10000, &hKey);
    CryptEncrypt(hKey, 0, TRUE, 0, (BYTE*)lpszOut, &dwLen, nBufLen);
    //CryptDecrypt(hKey, 0, TRUE, 0, (BYTE*)lpszOut, &dwLen);
    CryptDestroyHash(hHash);
    CryptReleaseContext(hProv, 0);
 return result;
}

int Decrypt(LPCTSTR lpszIn, LPTSTR lpszOut)
{
 int result = 0;
 
 HCRYPTPROV hProv;
    HCRYPTHASH hHash;
    HCRYPTKEY hKey; 
    CString  csPass = "PASSWORD";
 DWORD  dwLen = strlen(lpszIn);
 
    if(!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0))
    {
        if(!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET))
        {
            return -1;
        }
    }
 strcpy(lpszOut, lpszIn);
 
    CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash);
    CryptHashData(hHash, (BYTE*)(LPCTSTR)csPass, csPass.GetLength(), 0);
    CryptDeriveKey(hProv, CALG_RC4, hHash, 0x0080*0x10000, &hKey);
    CryptDecrypt(hKey, 0, TRUE, 0, (BYTE*)lpszOut, &dwLen);
    CryptDestroyHash(hHash);
    CryptReleaseContext(hProv, 0);
 
 return result;
}

'Programming > Security' 카테고리의 다른 글

버퍼 오버플로우  (0) 2011.12.04
웹메소드 중 Get방식과 Post방식  (0) 2011.12.04
FTP의 Active Mode 와 Passive Mode  (0) 2011.12.04
DES  (0) 2011.11.29
오픈소스 API  (0) 2011.11.26
 

error C2731: 'WinMain' : 함수를 오버로드할 수 없습니다

Programming/MFC | 2011. 11. 26. 02:19
Posted by 신이내린프로그래머
프로젝트 속성의 유니코드와 멀티바이트 세팅에 따른 에러 메시지로
멀티바이트의 경우에는 LPTSTR로 설정하면 되고 유니코드의 경우에는
LPWSTR 설정하면 된다.

'Programming > MFC' 카테고리의 다른 글

MFC 헤더 및 라이브러리파일 설명  (0) 2011.11.26
 

오픈소스 API

Programming/Security | 2011. 11. 26. 01:48
Posted by 신이내린프로그래머
crypto++, OpenSSL, Crypto API
 

'Programming > Security' 카테고리의 다른 글

버퍼 오버플로우  (0) 2011.12.04
웹메소드 중 Get방식과 Post방식  (0) 2011.12.04
FTP의 Active Mode 와 Passive Mode  (0) 2011.12.04
DES  (0) 2011.11.29
윈도우에서 제공하는 간단한 방식의 암복호화 소스  (0) 2011.11.26
 

블로그 이미지

신이내린프로그래머

카테고리

Category (22)
Programming (19)
... (1)