OpenSSL : Decryption

어제 올린 포스트에서 언급했듯이, 오늘은 Decryption 쪽을 포스팅해본다. 오늘 올릴 소스코드는 완전한 것이 아니라, 어떤 method의 한 부분을 보여주는데, 적어도 OpenSSL의 함수를 사용하는 부분에 대해서만은 완전한 소스의 형태를 갖추고 있다.

	const char *validationRawData = [validataionData bytes];
	if( validataionData )
	{
		int validationLength = [validataionData length];
		int totalLength = 0; // For decrypted length

		int result = 0;
		unsigned char inputBuffer[8], outputBuffer[8];
		int inputLength = 0, outputLength = 0;

		bzero( inputBuffer, sizeof( inputBuffer ) );
		bzero( outputBuffer, sizeof( outputBuffer ) );

		char finalBuffer[64];
		bzero( finalBuffer, sizeof( finalBuffer ) );

		// Initialize cipher context
		EVP_CIPHER_CTX ctx;
		EVP_CIPHER_CTX_init( &ctx );

		// Copy a key
		unsigned char keyForDES[8];
		memcpy( keyForDES, kKeyText, 8 ); // "LXFExpor"

		result = EVP_DecryptInit( &ctx, EVP_des_ecb(), keyForDES, NULL);
		if( result )
		{

			int byteLeft = validationLength;
			int bytesToCopy = 0;
			int inputLoc = 0, outputLoc = 0;

			while( byteLeft > 0 )
			{
				if( byteLeft < 8 )
				{
					bytesToCopy = byteLeft;
					byteLeft = 0;
				}
				else
				{
					bytesToCopy = 8;
					byteLeft -= 8;
				}

				bzero( inputBuffer, sizeof( inputBuffer ) );
				memcpy( inputBuffer, validationRawData + inputLoc, bytesToCopy );
				inputLoc += bytesToCopy;

				bzero( outputBuffer, sizeof( outputBuffer ) );
				inputLength = bytesToCopy;
				result = EVP_DecryptUpdate( &ctx, outputBuffer, &outputLength, inputBuffer, inputLength );
				if( result )
				{
					memcpy( finalBuffer + outputLoc, outputBuffer, outputLength );
					outputLoc += outputLength;

					isSuccessful = YES;
				}
				else
				{
					isSuccessful = NO;
					break;
				}
			}

			bzero( outputBuffer, sizeof( outputBuffer ) );
			result = EVP_DecryptFinal( &ctx, outputBuffer, &outputLength );
			if( result )
			{
				memcpy( finalBuffer + outputLoc, outputBuffer, outputLength );
				outputLoc += outputLength;

				totalLength = outputLoc;

				isSuccessful = YES;
			}
			else
				isSuccessful = NO;

		}
		else
			isSuccessful = NO;

역시 주의할 부분은 EVP_DecryptUpdate() 함수의 호출부분이다. 이 함수의 호출 결과가 바로 바로 생각하는 단계의 것을 반영하지 않고, 다음 단계에 가서야 반영될 수있다. 직접 디버깅해 보면 좋을 것이다.

덧대서 말하자면 Mac에서는 libcrypto.dylib과 libssl.dylib을 링크해야 한다.
Windows에서는 좀 다르다. 현재 비공식 배포판이 있는데, Unix나 Mac의 것과 조금 다른 이름의 라이브러리로 되어 있다.
쉽게 파악할 수있기에 여기서는 설명을 하지 않겠다.

여기서 잠깐 부언 설명을 하자면, output buffer와 input buffer의 데이터 타입이 unsigned char의 어레이로 되어 있다. 이 점은 참 시사하는 바가 있다. 물론 사용할 수있는 암호화 기법마다 키의 길이가 다르고 output으로 나오는 길이가 다르기 때문에 int나 long이나 혹은 long long과 같은 데이터 타입을 사용하기가 좀 그렇다. char의 어레이로 하는 편이 여러가지로 난데, 여기엔 아마 또 하나의 고려사항이 있는 듯하다. byte ordering이 그것이다. 다양한 플랫폼으로 포팅을 할 때, 유념해야 할 사항 중의 하나가 바로 byte ordering이다. 의외로 미국에는 특히 인도계나 중국계가 그런데, Unix를 모르는 전산과 출신들이 많다. 컴퓨터하면 Windows만 아는 것이다. 근데 생각해 보자, 전산을 한 사람이 Windows는 모를 수있어도, Unix를 모른다는게 말이 되는가? 내가 본 소스 중에 이 byte ordering을 생각하지 않고 막 짠 것들이 꽤 있다. 근데, 자기가 테스트 한 머신에서는 되니까 그냥 되는구나하고 submit를 해 버린거다. 경력 15년이란다.. 어이그.. 내가 그런 것들 밑에서 일한다는게.. 정말..
아무튼… 그 소스 코드는 Unix를 모르는, Windows만 아는 사람이 만든거다. Unix를 쓰면 바로 Byte Ordering에 노출될텐데 말이지. 하긴…Intel Processor가 골치 아픈 구조이긴 하다. 세상의 거의 모든 Processor들이 다 Big Endian인데, Intel Processor들은 혼자서 Little Endian이다. 이거 참 웃기는 구조다. 통신도 Big Endian이 기본이다. 거의 모든 표준 규약이 Big Endian을 기반으로 한다. 왜 인텔의 프로세서 디자이너들은 little endian으로 만들었을까? 하다 못해 ARM core도 인텔이 fab을 한건 little endian으로 돈다. 다른 업체들이 만든건 Big Endian으로 돌지..
뭐 투덜대는건 그만하고… OpenSSL의 이런 구조는 porting할때 상당히 편하게 만드는 구조다. 이런 면은 참 생각을 잘하고 만든거 같다.

근데.. 그래도 역시 처음 사용하는 사람을 어리둥정하게 만드는 것은, 어디서부터 시작해야할지 모르게 만드는 함수 이름들과 MAN 페이지의 설명.. 이 OpenSSL을 보면, C++의 namespace보다 Objective-C처럼 클래스나 메소드 이름을 잘 정하는 것이 실제로 더 생산성을 높이고 관리하게 편하게 만드는 것이라는 것을 알 수있다. 물론 기본을 잘하고 namespace가 있으면 더 좋겠지만, 실제론 그런가?

근데 Cocoa나 Foundation 클래스 중에 이 OpenSSL을 wrapping해서 만든게 분명 있을텐데… KeyChain에 관련된 것과 CFAuthorization인가 등이 관련이 있을거 같은데 (그리고 특히 Keychain에 관련된 것들은 확실히 사용하고 있다.), 아무리 봐도 직접적으로 DES나 RSA, MD5, blowfish등을 언급한 도큐먼트가 Cocoa엔 없다.. 이거 참……

참.. 그리고 Mac에는 이거 외에도 또 암호화 기술을 사용할 수있게 하는 것이 있다. CC_로 시작되는 건데, 이름하여 Common Crypto API다. 몇가지 함수 이름을 보자면 CC_MD5_Init, CC_SHA1_Update, CCCryptorCreate 등등이다.

지금보니 뭔가 구조가 OpenSSL의 것과 비슷하다.
CCCryptorCreate(), CCCryptorUpdate(), CCCryptorFinal()… 비슷하지 않은가?
함수 이름들이 훨씬 정리가 잘 되어 있다. 근데 Mac이외에는 이 Common Crypto API의 MAN페이지가 검색되지 않는 것으로 보아, Apple사가 만들고 Mac에서만 쓰이는 것 같다.
혹은 BSD? 음.. 제목쪽에 BSD Library Functions Manual 라고 써져있는 것으로 보아 BSD Unix에서 쓰이는 것인가보다.

ADDED : 보니까 이 Common Crypto library는 Apple의 Open Source인 것같다.
여기 링크가 있다. http://developer.apple.com/opensource/security/

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: