여러 용도가 있지만, PC에서는 주로, 파일의 에러를 체크하는데 CRC가 사용됩니다. 즉 파일이 깨졌는지 아닌지 알아보는 데 사용하는 것입니다.

예를 들어, 맹구가 어떤 홈페이지에서 100기가짜리 파일을 며칠 걸려서 다운로드 받았는데, 그 파일이 깨지지 않고 정확하게 전송되었는지 알려면 어떻게 해야 할까요. 그 파일을 다시 한 번 더 다운로드 받아서, 전에 받은 파일과 한 글자씩 비교해 보아야 할 것입니다. 그러나 그러면 같은 파일을 2번 다운받아야 하니 아주 비효율적입니다.

그런데 만약 그 홈페이지 주인장이 그 파일의 CRC값을 알려준다면 간단히 해결됩니다. 가령 홈페이지 주인장이, "그 파일의 CRC 값은, D01B0B02 다" 라고 알려 주었다고 가정합시다.

맹구가 다운 받은 그 파일의 CRC값을 계산해서, D01B0B02 라는 값이 나오면 파일이 100% 정확히 받아진 것이고, 틀리다면 파일이 깨진 것이라는 사실을 간단히 알 수 있습니다.

100기가짜리 파일을 다시 다운받지 않아도, 고작 8글자의 CRC 값만 알면, 그 파일의 훼손 여부를 정확히 알 수 있습니다. 즉 CRC는 파일의 지문에 해당되는 것입니다. 사람이 모두 고유한 지문을 가지고 있듯이 파일에도 고유한 지문이 있습니다.




CRC의 정확성



만약 그 D01B0B02 라는 CRC 값을 가진 파일에서 단 글자라도 깨진다면 또는 단 1비트라도 변한다면, 그 파일의 CRC 값은 엄청나게 달라집니다. D01B0B02 가 D01B0B03 정도의 값으로 변하는 것이 아니라, 79D52C9D 등으로 아주 확 달려져 버립니다. 그래서 파일의 일부가 변경 또는 훼손되었다는 사실을 한눈에 알 수 있습니다.

요즘에 쓰는 CRC는 CRC32 입니다.

CRC32 는 C9AEBFF7 이런 식으로, 십육진수를 사용해 8글자로 표기합니다.




그러나 CRC32가 완벽하게 에러를 검출하는 것은 아닙니다. 파일이 훼손되거나 변경되었지만 같은 CRC32 값을 가지고 있을 수도 있습니다.

2의 32 승 = 4294967296 (약 43억)

결국 CRC32는, 00000000 ~ FFFFFFFF 까지 약 43억개의 경우의 수가 있습니다.

그래서 만약 파일이 43억개가 있다면, 확률적으로, 그 중의 하나에서 CRC가 제 기능을 못할 수 있습니다. 따라서 CRC32 가 오류를 일으킬 확률은 43억분의 1이라고 생각됩니다. ※ 제 생각일 뿐이지, 학술적으로 정확한지는 모르겠습니다.


아무튼 일반 PC 에서 사용할 때는 CRC32로도 충분합니다. 더 엄밀한 에러 체커를 위해서, MD5 (Message-Digest algorithm 5) 라는 알고리즘이 사용됩니다. 32비트가 아닌 128비트입니다. (리눅스 CD를 다운받으러 가면 사이트에 MD5 값이 함께 적혀 있습니다.) 그러나 이것도 완벽한 것은 아닙니다. 해커가 속이려고 들면 속이는 건 시간 문제라고 하더군요.





ZIP 이나 RAR 같은 압축 프로그램이 파일을 압축할 때에는, 파일과 그 파일의 CRC32 값을 함께 저장합니다.

예제:
   Date     Time    CRC-32   Name
   ----     ----   --------  ----
2006-06-04  20:45  7E83AC61  simcity_2000_happylnd.png
2006-06-02  14:19  B4F36322  chess_kchess_elite.png
2006-06-04  14:57  D01B0B02  chessboard_std_medium.zip
2006-06-03  11:36  521E65D3  0.htm
2006-06-04  20:08  791AB223  simcity_2000_toolbar.png


그러면 압축파일 속에 들어 있는 파일들이 깨졌는지/변조되었는지를 알 수 있기 때문입니다. WinRAR 이나 WinZip에는 "Test" 라는 것이 있습니다. 이것이 바로 CRC를 검사하는 것입니다.

만약 파일이 깨졌다면 그 파일의 CRC32 값과 불일치하게 됩니다. 이것이 CRC 에러 입니다.

즉, CRC 에러가 났다는 것은, 그 파일이 깨졌다는 의미입니다. 파일이 깨지면 (이론적으로) 그 파일을 완벽히 복구하는 것은 불가능합니다.

단, RAR로 압축할 때에 Put recovery record 라는 옵션을 켜면, CRC 에러가 났을 때 100% 복구할 수도 있습니다. 그러나 이러면 압축파일의 용량이 약간 커지는 문제가 있습니다.




CRC32 값 구하기



파일의 CRC 값을 알기 위한 가장 간단한 방법은 그 파일을 WinRAR 이나 WinZip 등으로 압축해 보는 것입니다. (WinRAR 이나 WinZip에서는 기본적으로, CRC값을 보여주지 않는데, 보여주도록 화면을 설정하면 됩니다.)





옵션으로 지정해준 파일의 CRC32 값을 구하는 자바 소스입니다. 자바에 내장되어 있는 java.util.zip.CRC32 클래스로 값을 얻습니다. ZIP 이나 RAR에서 사용되는 CRC32 값과 동일한 값을 얻을 수 있습니다.

이 자바 프로그램으로, 675MB 크기 파일의 CRC32 를 구하는 데, 16초 걸렸습니다.

순수한 C로 작성된 CRC32 프로그램으로는 15초 걸렸습니다. 약간 차이는 있지만, 속도는 아주 빠릅니다.


JAVA: 파일의 CRC32 값 얻기 소스 코드


소스 파일명: GetCRC32.java
import java.io.*;
import java.util.zip.*;


public class GetCRC32 {
  public static void main(String args[]) {

    // 파일명을 옵션으로 주지 않으면 에러 내고 종료
    if (args.length != 1) {
      System.err.println("Usage: java GetCRC32 <input filename>");
      System.exit(1);
    }

    // CRC32 값과 파일명 화면에 출력
    System.out.format(
                               "%08X : %s%n",
                      getCRC32Value(args[0]),
                                     args[0]
                      );

  }




  public static long getCRC32Value(String filename) {
    Checksum crc = new CRC32();

    try {
      ////////////////////////////////////////////////////////////////////////////////
      BufferedInputStream in = new BufferedInputStream(new FileInputStream(filename));
      byte buffer[] = new byte[32768];
      int length = 0;

      while ((length = in.read(buffer)) >= 0)
        crc.update(buffer, 0, length);

      in.close();
      ////////////////////////////////////////////////////////////////////////////////
    } catch (IOException e) {
        System.err.println(e);
        System.exit(2);
    }
    return crc.getValue();
  }

}



컴파일 및 실행 결과:
D:\Z>javac GetCRC32.java

D:\Z>java GetCRC32 0.exe
FE4186B2 : 0.exe

D:\Z>

0.exe 라는 어떤 파일의 CRC32 값이 FE4186B2 라고 나오고 있습니다.


D:\Z>javac GetCRC32.java && java GetCRC32 "사본 - test.jpg"
6E17BBC0 : 사본 - test.jpg

D:\Z>

공백과 한글이 들어간 파일명도, 큰따옴표로 둘러싸 주면 잘 작동합니다.


출처 - http://mwultong.blogspot.com/2006/10/java-crc32-crc.html






'Development > Java' 카테고리의 다른 글

java - 파일 전송  (0) 2013.04.04
system.out 출력 포맷  (0) 2013.01.31
serialVersionUID  (0) 2013.01.01
RSA java 구현  (0) 2012.12.26
javax.crypto.BadPaddingException: Given final block not properly padded  (0) 2012.12.24
Posted by linuxism
,