• 로그인 함 해보끄나?

  • Sarangnamu.net June 17, 2003
    Home Login Profile Study Open Project Q&A Google Code
    blowfish
    Last Modify : 13 December, 2010(11:55)
    /**
     * @file CBlowfish.h
     * @author cheol-dong, Choi <aucd29@gmail.com>
     * @version 0.1
     *
     * @section LICENSE
     *
     * Copyright (c) 2003-2010, cheol-dong choi, (http://www.sarangnamu.net)
     *
     * Permission is hereby granted, free of charge, to any person
     * obtaining a copy of this software and associated documentation
     * files (the "Software"), to deal in the Software without
     * restriction, including without limitation the rights to use,
     * copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the
     * Software is furnished to do so, subject to the following
     * conditions:
     *
     * The above copyright notice and this permission notice shall be
     * included in all copies or substantial portions of the Software.
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
     * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
     * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING("")
     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     * OTHER DEALINGS IN THE SOFTWARE.
     * 
     *
     * @section DESCRIPTION
     * <b>sample code</b>
     * @code
     *		CBlowfish bf;
     *		std::string blowfish;
     *		bf.setHexKey("0123456789ABCDEFF0E1D2C3B4A59687");	// setKey 로 사용가능 (문자열의 경우)
     *		bf.setHexInitialVector("FEDCBA9876543210");			// setInitialVector 로 사용가능 
     *		
     *		blowfish = bf.encrypt("helloworld");
     *		bf.decrypt(blowfish.c_str());
     *		blowfish = bf.encrypt("helloworldhelloworldhelloworldhelloworld");
     *		bf.decrypt(blowfish.c_str());
     *		blowfish = bf.encrypt("7654321 Now is the time for ");
     *		bf.decrypt(blowfish.c_str());
     *		LOGALWAYS("\n\n");
     * @endcode
     * @n
     * <b>mode change</b>
     * @code
     *		bf.setMode(CBlowfish::eCBC);
     * @endcode
     * @n
     * <b>padding change</b>
     * @code
     *		bf.setPadding(CBlowfish::ePKCSPadding);
     * @endcode
     * @warning
     * - cfb/ofb 의 경우 string length 만큼 데이터를 처리 하기 때문에
     *   pkcs padding 을 적용 되지 않는다.
     *
     * @section UPDATE_LOG
     * - setHexKey 추가 2010-08-16 (16:44:20)
     * - 내부 구조 모두 변경 2010-08-17 (18:06:50)
     */
    
    #ifndef __CD_CBLOWFISH_H__
    #define __CD_CBLOWFISH_H__
    
    #include <stdio.h>
    #include <string>
    
    
    /**
     * @class CBlowfish
     * @brief blowfish 구현 클래스
     */
    class CBlowfish
    {
    public:
    
    	/*
    	 * Construction
    	 */
    	CBlowfish();
    
    	/*
    	 * Destructor
    	 */
    	virtual ~CBlowfish();
    
    public:
    
    	
    	/**
    	 * @enum eBlowfishMode
    	 * @brief blowfish mode 종류
    	 */
    	enum eBlowfishMode
    	{
    		eECB = 0,
    		eCBC,
    		eCFB64,
    		eOFB64
    	};
    
    	/**
    	 * @enum eBlowfishPadding
    	 * @brief blowfish padding 종류
    	 */
    	enum eBlowfishPadding
    	{
    		eZeroPadding = 0,
    		ePKCSPadding
    	};
    
    	/*
    	 * Getter methods
    	 */
    
    	void setKey(const char* key);
    
    	void setHexKey(const char* hexTypeKey);
    
    	void setInitialVector(const char* initialVector);
    
    	void setHexInitialVector(const char* initialVector);
    
    	void setMode(int mode);
    
    	void setPadding(int padding);
    
    
    	std::string encrypt(const char* data);
    
    	std::string decrypt(const char* data);
    
    	std::string encrypt_evptest(const char* data);
    
    
    protected:
    
     	/*
    	 * Internal methods
    	 */
    	void init();
    
    	inline void toHex(std::string& dest, const unsigned char* bin, bool uppperCase=false);
    
    	inline void toBin(std::string& dest, const char* hex);
    
    private:
    	int _mode;						///< mode 옵션
    
    	int _padding;					///< padding 옵션
    
    	void* _blowfishKey;				///< blowfish key ptr
    
    	unsigned char _keyValue[16];	///< secret key value
    
    	unsigned char _iv[8];			///< initial vector value
    };
    
    #endif
    
    /**
     * @file CBlowfish.cpp
     * @author cheol-dong, Choi <aucd29@gmail.com>
     * @version 0.1
     *
     * @section LICENSE
     *
     * Copyright (c) 2003-2010, cheol-dong choi, (http://www.sarangnamu.net)
     *
     * Permission is hereby granted, free of charge, to any person
     * obtaining a copy of this software and associated documentation
     * files (the "Software"), to deal in the Software without
     * restriction, including without limitation the rights to use,
     * copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the
     * Software is furnished to do so, subject to the following
     * conditions:
     *
     * The above copyright notice and this permission notice shall be
     * included in all copies or substantial portions of the Software.
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
     * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
     * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING("")
     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     * OTHER DEALINGS IN THE SOFTWARE.
     * 
     * @see http://en.wikipedia.org/wiki/Blowfish_(cipher)
     * @see http://www.joinc.co.kr/modules/moniwiki/wiki.php/Code/C/blowcrypt
     * @see http://bit.ly/9tSGa9
     * @see http://www.sarangnamu.net/basic/basic_view.php?no=4321
     * @see http://www.sarangnamu.net/basic/basic_view.php?no=4316
     *
     * @section DESCRIPTION
     *
     * - openssl 을 이용한 blow fish 구현.
     *
     * - Blowfish has a 64-bit block size and a variable key length
     * from 32 up to 448 bits.[2] It is a 16-round Feistel cipher and uses 
     * large key-dependent S-boxes. It is similar in structure to CAST-128, 
     * which uses fixed S-boxes.
     *
     * - 56byte ==> 448bits
     * 
     * - BF_BLOCK 값은 8이고 openssl/blowfish.h 에 정의 되어 있다.
     * 
     */
    
    #include "CBlowfish.h"
    #include "RSLOGGER.H"
    
    #include <memory.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    #include <openssl/evp.h>
    #include <openssl/blowfish.h>
    #include "Utility.h"
    
    /**
     * CBlowfish
     */
    CBlowfish::CBlowfish()
    	: _blowfishKey(NULL)
    	, _mode(0)
    	, _padding(1)
    {
    	memset(_keyValue, 0, sizeof(_keyValue));
    	memset(_iv, 0, sizeof(_iv));
    }
    
    
    /**
     * ~CBlowfish
     */
    CBlowfish::~CBlowfish()
    {
    	if (_blowfishKey)
    	{
    		delete _blowfishKey;
    	}
    }
    
    
    /**
     * string 형태의 secret key를 설정한다.
     *
     * @param key secret key 값
     */
    void CBlowfish::setKey(const char* key)
    {
    	LOG1("CBlowfish::setKey\n");
    
    	if (key == NULL || strlen(key) < 1)
    	{
    		LOGALWAYS("ERROR::CBlowfish::setKey <key == null>\n");
    		ASSERT(0);
    		return ;
    	}
    
    	memcpy((char*)_keyValue, key, strlen(key));
    	init();
    }
    
    
    /**
     * hex 형태의 serect key 를 설정한다.
     * 
     * @param  hexKey 
     */
    void CBlowfish::setHexKey(const char* hexTypeKey)
    {
    	if (hexTypeKey == NULL)
    	{
    		LOGALWAYS("ERROR::CBlowfish::setHexKey <hexTypeKey == null>\n");
    		ASSERT(0);
    		return ;
    	}
    
    	std::string key;
    	toBin(key, hexTypeKey);
    
    	LOG1("key : %s\n", key.c_str());
    	setKey(key.c_str());
    }
    
    
    /**
     * string 형태의 initial vector 를 설정한다.
     * 
     * @param  initialVector initial vector 값
     */
    void CBlowfish::setInitialVector(const char* initialVector)
    {
    	LOG1("CBlowfish::setInitialVector\n");
    
    	if (initialVector == NULL || strlen(initialVector) < 1)
    	{
    		LOGALWAYS("ERROR::CBlowfish::setKey <key == null>\n");
    		ASSERT(0);
    		return ;
    	}
    
    	memcpy((char*)_iv, initialVector, strlen(initialVector));
    }
    
    
    /**
     * hex 형태의 initial vector 를 설정한다.
     * 
     * @param  initialVector hex 형태의 initial vector 값
     */
    void CBlowfish::setHexInitialVector(const char* initialVector)
    {
    	LOG1("CBlowfish::setHexInitialVector\n");
    
    	if (initialVector == NULL || strlen(initialVector) < 1)
    	{
    		LOGALWAYS("ERROR::CBlowfish::setKey <key == null>\n");
    		ASSERT(0);
    		return ;
    	}
    
    	std::string iv;
    	toBin(iv, initialVector);
    	setInitialVector(iv.c_str());
    }
    
    
    /**
     * mode를 변경한다.
     * 
     * @param  mode mode 값
     */
    void CBlowfish::setMode(int mode)
    {
    	LOG1("CBlowfish::setMode\n");
    
    	_mode = mode;
    }
    
    
    /**
     * padding 을 변경한다.
     * 
     * @param  padding padding 값
     */
    void CBlowfish::setPadding(int padding)
    {
    	LOG1("CBlowfish::setPadding\n");
    
    	_padding = padding;
    }
    
    
    /**
     * 입력 받은 key를 설정한다.
     *
     */
    void CBlowfish::init()
    {
    	_blowfishKey = new BF_KEY;
    
    	BF_set_key((BF_KEY*)_blowfishKey, strlen((const char*)_keyValue), _keyValue);
    }
    
    
    /**
     * 입력한 문자열을 암호화 한다.
     *
     * @param  data 암호화할 문자열 (plain text)
     * @return 암호화된 문자열 (cipher text)
     */
    std::string CBlowfish::encrypt(const char* data)
    {
    	LOG1("CBlowfish::encrypt\n");
    
    	unsigned char result[BF_BLOCK] = {0};
    	size_t len = strlen(data);
    
    	if (len == 0)
    	{
    		LOGALWAYS("ERROR::CBlowfish::encrypt <data == null>\n");
    		return "";
    	}
    
    	double divValue = (double)len / (double)BF_BLOCK;
    	size_t loop = (size_t)ceil(divValue);
    	size_t pkcsValue = (loop * BF_BLOCK) - len;
    	unsigned char* p = (unsigned char*)data;
    	std::string returnValue;
    	unsigned char iv[8];
    	int n = 0;
    	memcpy(iv, _iv, 8);		// iv 를 그대로 사용하면 decrypt 할 때 안되므로..
    
    	LOG1("len : %d\n", len);
    	LOG1("divValue : %lf\n", divValue);
    	LOG1("loop : %d\n", loop);
    	LOG1("pkcsValue : %d\n", pkcsValue);
    
    	if (pkcsValue > 0)
    	{
    		--loop;
    	}
    
    	if (_mode == eECB)		// ecb
    	{
    		for (size_t i=0; i<loop; ++i)
    		{
    			BF_ecb_encrypt(p, result, (BF_KEY*)_blowfishKey, BF_ENCRYPT);
    			toHex(returnValue, result);
    			p += BF_BLOCK;
    		}
    	}
    	else if (_mode == eCBC) // cbc
    	{
    		for (size_t i=0; i<loop; ++i)
    		{
    			BF_cbc_encrypt(p, result, BF_BLOCK, (BF_KEY*)_blowfishKey, iv, BF_ENCRYPT);
    			toHex(returnValue, result);
    			p += BF_BLOCK;
    		}
    	}
    	else if (_mode == eCFB64) // cfb64
    	{
    		for (size_t i=0; i<loop; ++i)
    		{
    			BF_cfb64_encrypt(p, result, BF_BLOCK, (BF_KEY*)_blowfishKey, iv, &n, BF_ENCRYPT);
    			toHex(returnValue, result);
    			p += BF_BLOCK;
    			len -= BF_BLOCK;
    		}
    	}
    	else if (_mode == eOFB64)
    	{
    		for (size_t i=0; i<loop; ++i)
    		{
    			BF_ofb64_encrypt(p, result, BF_BLOCK, (BF_KEY*)_blowfishKey, iv, &n);
    			toHex(returnValue, result);
    			p += BF_BLOCK;
    			len -= BF_BLOCK;
    		}
    	}
    	else
    	{
    		ASSERT(0);
    	}
    
    	unsigned char pkcsBuffer[BF_BLOCK];
    
    	if (_mode == eECB || _mode == eCBC)
    	{
    		if (pkcsValue > 0)
    		{
    			strcpy((char*)pkcsBuffer, (char*)p);
    			memset(pkcsBuffer + (BF_BLOCK - pkcsValue), _padding ? pkcsValue : 0, pkcsValue);
    		}
    		else
    		{
    			pkcsValue = _padding ? 8 : 0;
    			memset(pkcsBuffer, pkcsValue, pkcsValue);
    		}
    	}
    	else
    	{
    		if (pkcsValue > 0)
    		{
    			strcpy((char*)pkcsBuffer, (char*)p);
    		}
    		else
    		{
    			memset(pkcsBuffer, 1, BF_BLOCK);
    		}
    	}
    	
    
    	if (pkcsValue)
    	{
    		memset(result, 0, sizeof(result));
    
    		if (_mode == eECB)			// ecb
    		{
    			BF_ecb_encrypt(pkcsBuffer, result, (BF_KEY*)_blowfishKey, BF_ENCRYPT);
    		}
    		else if (_mode == eCBC)		// cbc
    		{
    			BF_cbc_encrypt(pkcsBuffer, result, BF_BLOCK, (BF_KEY*)_blowfishKey, iv, BF_ENCRYPT);
    		}
    		else if (_mode == eCFB64)	// cfb
    		{
    			BF_cfb64_encrypt(pkcsBuffer, result, len + 1, (BF_KEY*)_blowfishKey, iv, &n, BF_ENCRYPT);
    		}
    		else if (_mode == eOFB64)
    		{
    			BF_ofb64_encrypt(pkcsBuffer, result, len + 1, (BF_KEY*)_blowfishKey, iv, &n);
    		}
    
    		if (_mode == eECB || _mode == eCBC)
    		{
    			toHex(returnValue, result);
    		}
    		else
    		{
    			/*
    			 * cfb, ofb 의 경우 가변형이므로 bin 마지막에 0x00 이 올 수 있다.
    			 * toHex 의 경우 00 처리를 별도로 하지 않으므로 클래스를 이용한다.
    			 */
    			CUtility util;
    			util.Bin2Hex(result, returnValue);
    		}
    	}
    
    	LOG2("encrypted : %s\n", returnValue.c_str());
    
    	return returnValue;
    }
    
    
    /**
     * 문자열을 복호화 한다.
     *
     * @param  data 복호화할 데이터 (cipher text)
     * @return 복호화된 데이터 (plain text)
     */
    std::string CBlowfish::decrypt(const char* data)
    {
    	LOG1("CBlowfish::decrypt\n");
    
    	size_t len = strlen(data);
    
    	if (len == 0)
    	{
    		LOGALWAYS("ERROR::CBlowfish::encrypt <data == null>\n");
    		return "";
    	}
    
    	size_t hexBlock = BF_BLOCK * 2;
    	double divValue = (double)len / (double)hexBlock;
    	size_t loop = (size_t)ceil(divValue);
    
    	const char* p = data;
    	char hexData[20] = {0};
    	unsigned char binaryData[8];
    	unsigned char out[12] = {0};
    	std::string returnValue;
    	CUtility util;
    	unsigned char iv[8];	// for cbc/cfb
    	int n = 0;				// for cfb
    	memcpy(iv, _iv, 8);
    
    	--loop; // 마지막의 경우는 data pkcs 때문에 별도로 처리해야 한다.
    
    	if (_mode == eECB)
    	{
    		for (size_t i=0; i<loop; ++i)
    		{
    			strncpy(hexData, p, hexBlock);
    			util.Hex2Bin(hexData, binaryData, hexBlock);
    			BF_ecb_encrypt(binaryData, out, (BF_KEY*)_blowfishKey, BF_DECRYPT);
    
    			p += hexBlock;
    			returnValue += (const char*)out;
    		}
    	}
    	else if (_mode == eCBC)
    	{
    		for (size_t i=0; i<loop; ++i)
    		{
    			strncpy(hexData, p, hexBlock);
    			util.Hex2Bin(hexData, binaryData, hexBlock);
    			BF_cbc_encrypt(binaryData, out, BF_BLOCK, (BF_KEY*)_blowfishKey, iv, BF_DECRYPT);
    
    			p += hexBlock;
    			returnValue += (const char*)out;
    		}
    	}
    	else if (_mode == eCFB64)
    	{
    		for (size_t i=0; i<loop; ++i)
    		{
    			strncpy(hexData, p, hexBlock);
    			util.Hex2Bin(hexData, binaryData, hexBlock);
    			BF_cfb64_encrypt(binaryData, out, BF_BLOCK, (BF_KEY*)_blowfishKey, iv, &n, BF_DECRYPT);
    
    			p += hexBlock;
    			returnValue += (const char*)out;
    			len -= hexBlock;
    		}
    	}
    	else if (_mode == eOFB64)
    	{
    		for (size_t i=0; i<loop; ++i)
    		{
    			strncpy(hexData, p, hexBlock);
    			util.Hex2Bin(hexData, binaryData, hexBlock);
    			BF_ofb64_encrypt(binaryData, out, BF_BLOCK, (BF_KEY*)_blowfishKey, iv, &n);
    
    			p += hexBlock;
    			returnValue += (const char*)out;
    			len -= hexBlock;
    		}
    	}
    	else
    	{
    		ASSERT(0);
    	}
    
    	if (_mode == eECB || _mode == eCBC)
    	{
    		strncpy(hexData, p, hexBlock);
    		util.Hex2Bin(hexData, binaryData, hexBlock);
    	}
    	else
    	{
    		memset(hexData, 0, hexBlock);
    		memset(out, 0, 12);
    		memset(binaryData, 0, 8);
    		strncpy(hexData, p, len);
    		util.Hex2Bin(hexData, binaryData, len);
    	}
    
    	if (_mode == eECB)
    	{
    		BF_ecb_encrypt(binaryData, out, (BF_KEY*)_blowfishKey, BF_DECRYPT);
    	}
    	else if (_mode == eCBC)
    	{
    		BF_cbc_encrypt(binaryData, out, BF_BLOCK, (BF_KEY*)_blowfishKey, iv, BF_DECRYPT);
    	}
    	else if (_mode == eCFB64)
    	{
    		BF_cfb64_encrypt(binaryData, out, BF_BLOCK, (BF_KEY*)_blowfishKey, iv, &n, BF_DECRYPT);
    	}
    	else if (_mode == eOFB64)
    	{
    		BF_ofb64_encrypt(binaryData, out, BF_BLOCK, (BF_KEY*)_blowfishKey, iv, &n);
    	}
    	else
    	{
    		ASSERT(0);
    	}
    
    	if (_mode == eECB || _mode == eCBC)
    	{
    		if (out[7] < 9 && out[7] > 0)
    		{
    			memset(out + (BF_BLOCK - out[7]), 0, out[7]);
    		}
    	}
    
    	returnValue += (const char*)out;
    
    	LOG2("decrypted : '%s'\n", returnValue.c_str());
    
    	return returnValue;
    }
    
    
    std::string CBlowfish::encrypt_evptest(const char* data)
    {
    	LOG1("CBlowfish::encrypt_test\n");
    
    	EVP_CIPHER_CTX ctx; 
    	EVP_CIPHER_CTX_init(&ctx); 
    
    	int olen = 0, tlen;
    	unsigned char buf[32] = {0};
    	size_t n = strlen(data);
    
    	// set padding
    	//EVP_CIPHER_CTX_set_padding(&ctx, 0);
    
    	EVP_EncryptInit(&ctx, EVP_bf_ecb(), _keyValue, _iv); 
    	if (EVP_EncryptUpdate(&ctx, buf, &olen, (unsigned char*)data, n) != 1) 
    	{ 
    		printf("Error in encrypt update\n"); 
    		return ""; 
    	}
    
    	if (EVP_EncryptFinal(&ctx, buf+olen, &tlen) != 1) 
    	{ 
    		printf("Error in encrypt final\n"); 
    		return ""; 
    	}
    
    	EVP_CIPHER_CTX_cleanup(&ctx);
    
    	CUtility util;
    	std::string returnValue;
    	util.Bin2Hex((unsigned char*)buf, returnValue);
    
    	LOG2("encrypted : %s\n", returnValue.c_str());
    
    	return returnValue;
    }
    
    
    /**
     * binary 를 hex 로 변경한다.
     * 
     * @param dest hex 로 변경된 데이터를 담는 버퍼
     * @param bin hex 로 변경할 데이터 원본
     * @param uppperCase true : 대문자 hex 형태로, false : 소문자 hex 형태로
     * @warning blowfish 구조상 8 byte 씩 데이터를 나눠서 처리해야 하므로
     *          binary 중간에 0x00 이 존재하면 CUtility 에서는 제대로 처리를
     *			하지 못하므로 toHex 를 사용한다.
     */
    void CBlowfish::toHex(std::string& dest, const unsigned char* bin, bool uppperCase)
    {
    	LOG1("CBlowfish::toHex\n");
    	
    	char toHex[4];
    	char caseType[8];
    
    	strcpy(caseType, uppperCase ? "%02X" : "%02x");
    	for (size_t i=0; i<BF_BLOCK; ++i)
    	{
    		sprintf(toHex, caseType, bin[i]);
    		dest += toHex;
    	}
    }
    
    
    /**
     * hex 를 bin 으로 변경한다.
     * 
     * @param  dest binary 형태로 변경한 데이터를 담을 버퍼
     * @param  hex hex 형태의 원본 소스
     */
    void CBlowfish::toBin(std::string& dest, const char* hex)
    {
    	LOG1("CBlowfish::toBin\n");
    
    	size_t len = strlen(hex);
    
    	if (len < 1)
    	{
    		LOGALWAYS("ERROR::CBlowfish::toBin <data == null>\n");
    		ASSERT(0);
    		return ;
    	}
    	
    	CUtility util;
    	util.Hex2Bin(hex, dest);
    }
    

    Comment


    입력하3 1508772117



    Locations of visitors to this page