C/C++opensslを用いて要約と暗号解読(md 5,sha 256,des,rsa)

13481 ワード

Opensslには要約ハッシュ、暗号解読のためのアルゴリズムが多く、エンジニアリングプロジェクトに統合しやすく、ネットワークメッセージにおける安全な伝送と認証に広く応用されている.以下、md 5、sha 256、des、rsaのいくつかの典型的なapiを例として簡単に使用する.
 
アルゴリズムの紹介
md5:https://en.wikipedia.org/wiki/MD5
sha256:https://en.wikipedia.org/wiki/SHA-2
des: https://en.wikipedia.org/wiki/Data_Encryption_Standard
rsa: https://en.wikipedia.org/wiki/RSA_(cryptosystem)
 
エンジニアリング構成
windows
 
  • opensslライブラリをコンパイルし、ヘッダファイルincludeとリンクライブラリlibとdll
  • を得る.
  • 構成はヘッダファイルディレクトリとライブラリディレクトリ
  • を含む.
  • プロジェクトでリンク指定lib:fenbieshlibsslを設定する.lib,libcrypto.lib
  • 対応するdllをexe実行ディレクトリにコピーする:libcrypto-1_1.dll, libssl-1_1.dll

  • linux
  • opensslライブラリをコンパイルし、ヘッダファイルincludeとリンクライブラリaとso
  • を得る.
  • 構成はヘッダファイルディレクトリとライブラリディレクトリ
  • を含む.
  • プロジェクトでリンク指定lib:libcryptoを設定.a後者libcrypto.so

  •  
    コード#コード#
     
    #include   
    #include 
    #include   
    #include   
    #include "openssl/md5.h"  
    #include "openssl/sha.h"  
    #include "openssl/des.h"  
    #include "openssl/rsa.h"  
    #include "openssl/pem.h"  
    
    // ---- md5     ---- //  
    void md5(const std::string &srcStr, std::string &encodedStr, std::string &encodedHexStr)
    {
    	//   md5    
    	unsigned char mdStr[33] = {0};
    	MD5((const unsigned char *)srcStr.c_str(), srcStr.length(), mdStr);
    
    	//          
    	encodedStr = std::string((const char *)mdStr);
    	//           32    
    	char buf[65] = {0};
    	char tmp[3] = {0};
    	for (int i = 0; i < 32; i++)
    	{
    		sprintf(tmp, "%02x", mdStr[i]);
    		strcat(buf, tmp);
    	}
    	buf[32] = '\0'; //     0, 32      
    	encodedHexStr = std::string(buf);
    }
    
    // ---- sha256     ---- //  
    void sha256(const std::string &srcStr, std::string &encodedStr, std::string &encodedHexStr)
    {
    	//   sha256    
    	unsigned char mdStr[33] = {0};
    	SHA256((const unsigned char *)srcStr.c_str(), srcStr.length(), mdStr);
    
    	//          
    	encodedStr = std::string((const char *)mdStr);
    	//           32    
    	char buf[65] = {0};
    	char tmp[3] = {0};
    	for (int i = 0; i < 32; i++)
    	{
    		sprintf(tmp, "%02x", mdStr[i]);
    		strcat(buf, tmp);
    	}
    	buf[32] = '\0'; //     0, 32      
    	encodedHexStr = std::string(buf);
    }
    
    // ---- des      ---- //  
    //    ecb    
    std::string des_encrypt(const std::string &clearText, const std::string &key)
    {
    	std::string cipherText; //     
    
    	DES_cblock keyEncrypt;
    	memset(keyEncrypt, 0, 8);
    
    	//           
    	if (key.length() <= 8)
    		memcpy(keyEncrypt, key.c_str(), key.length());
    	else
    		memcpy(keyEncrypt, key.c_str(), 8);
    
    	//       
    	DES_key_schedule keySchedule;
    	DES_set_key_unchecked(&keyEncrypt, &keySchedule);
    
    	//     , 8      
    	const_DES_cblock inputText;
    	DES_cblock outputText;
    	std::vector vecCiphertext;
    	unsigned char tmp[8];
    
    	for (int i = 0; i < clearText.length() / 8; i++)
    	{
    		memcpy(inputText, clearText.c_str() + i * 8, 8);
    		DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_ENCRYPT);
    		memcpy(tmp, outputText, 8);
    
    		for (int j = 0; j < 8; j++)
    			vecCiphertext.push_back(tmp[j]);
    	}
    
    	if (clearText.length() % 8 != 0)
    	{
    		int tmp1 = clearText.length() / 8 * 8;
    		int tmp2 = clearText.length() - tmp1;
    		memset(inputText, 0, 8);
    		memcpy(inputText, clearText.c_str() + tmp1, tmp2);
    		//       
    		DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_ENCRYPT);
    		memcpy(tmp, outputText, 8);
    
    		for (int j = 0; j < 8; j++)
    			vecCiphertext.push_back(tmp[j]);
    	}
    
    	cipherText.clear();
    	cipherText.assign(vecCiphertext.begin(), vecCiphertext.end());
    
    	return cipherText;
    }
    
    //    ecb    
    std::string des_decrypt(const std::string &cipherText, const std::string &key)
    {
    	std::string clearText; //     
    
    	DES_cblock keyEncrypt;
    	memset(keyEncrypt, 0, 8);
    
    	if (key.length() <= 8)
    		memcpy(keyEncrypt, key.c_str(), key.length());
    	else
    		memcpy(keyEncrypt, key.c_str(), 8);
    
    	DES_key_schedule keySchedule;
    	DES_set_key_unchecked(&keyEncrypt, &keySchedule);
    
    	const_DES_cblock inputText;
    	DES_cblock outputText;
    	std::vector vecCleartext;
    	unsigned char tmp[8];
    
    	for (int i = 0; i < cipherText.length() / 8; i++)
    	{
    		memcpy(inputText, cipherText.c_str() + i * 8, 8);
    		DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_DECRYPT);
    		memcpy(tmp, outputText, 8);
    
    		for (int j = 0; j < 8; j++)
    			vecCleartext.push_back(tmp[j]);
    	}
    
    	if (cipherText.length() % 8 != 0)
    	{
    		int tmp1 = cipherText.length() / 8 * 8;
    		int tmp2 = cipherText.length() - tmp1;
    		memset(inputText, 0, 8);
    		memcpy(inputText, cipherText.c_str() + tmp1, tmp2);
    		//       
    		DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_DECRYPT);
    		memcpy(tmp, outputText, 8);
    
    		for (int j = 0; j < 8; j++)
    			vecCleartext.push_back(tmp[j]);
    	}
    
    	clearText.clear();
    	clearText.assign(vecCleartext.begin(), vecCleartext.end());
    
    	return clearText;
    }
    
    
    // ---- rsa       ---- //  
    #define KEY_LENGTH  2048               //     
    #define PUB_KEY_FILE "pubkey.pem"    //     
    #define PRI_KEY_FILE "prikey.pem"    //     
    
    //           
    void generateRSAKey(std::string strKey[2])
    {
    	//        
    	size_t pri_len;
    	size_t pub_len;
    	char *pri_key = NULL;
    	char *pub_key = NULL;
    
    	//        
    	RSA *keypair = RSA_generate_key(KEY_LENGTH, RSA_3, NULL, NULL);
    
    	BIO *pri = BIO_new(BIO_s_mem());
    	BIO *pub = BIO_new(BIO_s_mem());
    
    	PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
    	PEM_write_bio_RSAPublicKey(pub, keypair);
    
    	//       
    	pri_len = BIO_pending(pri);
    	pub_len = BIO_pending(pub);
    
    	//            
    	pri_key = (char *)malloc(pri_len + 1);
    	pub_key = (char *)malloc(pub_len + 1);
    
    	BIO_read(pri, pri_key, pri_len);
    	BIO_read(pub, pub_key, pub_len);
    
    	pri_key[pri_len] = '\0';
    	pub_key[pub_len] = '\0';
    
    	//        
    	strKey[0] = pub_key;
    	strKey[1] = pri_key;
    
    	//      (        begin rsa public key/ begin rsa private key   )
    	FILE *pubFile = fopen(PUB_KEY_FILE, "w");
    	if (pubFile == NULL)
    	{
    		assert(false);
    		return;
    	}
    	fputs(pub_key, pubFile);
    	fclose(pubFile);
    
    	FILE *priFile = fopen(PRI_KEY_FILE, "w");
    	if (priFile == NULL)
    	{
    		assert(false);
    		return;
    	}
    	fputs(pri_key, priFile);
    	fclose(priFile);
    
    	//     
    	RSA_free(keypair);
    	BIO_free_all(pub);
    	BIO_free_all(pri);
    
    	free(pri_key);
    	free(pub_key);
    }
    
    //            (begin public key/ begin private key)
    //   openssl     ,    
    // openssl genrsa -out prikey.pem 1024 
    // openssl rsa - in privkey.pem - pubout - out pubkey.pem
    
    //       
    std::string rsa_pub_encrypt(const std::string &clearText, const std::string &pubKey)
    {
    	std::string strRet;
    	RSA *rsa = NULL;
    	BIO *keybio = BIO_new_mem_buf((unsigned char *)pubKey.c_str(), -1);
    	//        
    	// 1,            ,      rsa
    	// 2,                ,      rsa
    	// 3,           rsa
    	RSA* pRSAPublicKey = RSA_new();
    	rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);
    
    	int len = RSA_size(rsa);
    	char *encryptedText = (char *)malloc(len + 1);
    	memset(encryptedText, 0, len + 1);
    
    	//     
    	int ret = RSA_public_encrypt(clearText.length(), (const unsigned char*)clearText.c_str(), (unsigned char*)encryptedText, rsa, RSA_PKCS1_PADDING);
    	if (ret >= 0)
    		strRet = std::string(encryptedText, ret);
    
    	//     
    	free(encryptedText);
    	BIO_free_all(keybio);
    	RSA_free(rsa);
    
    	return strRet;
    }
    
    //       
    std::string rsa_pri_decrypt(const std::string &cipherText, const std::string &priKey)
    {
    	std::string strRet;
    	RSA *rsa = RSA_new();
    	BIO *keybio;
    	keybio = BIO_new_mem_buf((unsigned char *)priKey.c_str(), -1);
    
    	//        
    	// 1,            ,      rsa
    	// 2,                ,      rsa
    	// 3,           rsa
    	rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
    
    	int len = RSA_size(rsa);
    	char *decryptedText = (char *)malloc(len + 1);
    	memset(decryptedText, 0, len + 1);
    
    	//     
    	int ret = RSA_private_decrypt(cipherText.length(), (const unsigned char*)cipherText.c_str(), (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING);
    	if (ret >= 0)
    		strRet = std::string(decryptedText, ret);
    
    	//     
    	free(decryptedText);
    	BIO_free_all(keybio);
    	RSA_free(rsa);
    
    	return strRet;
    }
    
    int main(int argc, char **argv)
    {
    	//       
    	std::string srcText = "this is an example";
    
    	std::string encryptText;
    	std::string encryptHexText;
    	std::string decryptText;
    
    	std::cout << "===      ===" << std::endl;
    	std::cout << srcText << std::endl;
    
    	// md5  
    	std::cout << "=== md5   ===" << std::endl;
    	md5(srcText, encryptText, encryptHexText);
    	std::cout << "    : " << encryptText << std::endl;
    	std::cout << "   : " << encryptHexText << std::endl;
    
    	// sha256  
    	std::cout << "=== sha256   ===" << std::endl;
    	sha256(srcText, encryptText, encryptHexText);
    	std::cout << "    : " << encryptText << std::endl;
    	std::cout << "   : " << encryptHexText << std::endl;
    
    	// des  
    	std::cout << "=== des    ===" << std::endl;
    	std::string desKey = "12345";
    	encryptText = des_encrypt(srcText, desKey);
    	std::cout << "    : " << std::endl;
    	std::cout << encryptText << std::endl;
    	decryptText = des_decrypt(encryptText, desKey);
    	std::cout << "    : " << std::endl;
    	std::cout << decryptText << std::endl;
    
    	// rsa  
    	std::cout << "=== rsa    ===" << std::endl;
    	std::string key[2];
    	generateRSAKey(key);
    	std::cout << "  : " << std::endl;
    	std::cout << key[0] << std::endl;
    	std::cout << "  : " << std::endl;
    	std::cout << key[1] << std::endl;
    	encryptText = rsa_pub_encrypt(srcText, key[0]);
    	std::cout << "    : " << std::endl;
    	std::cout << encryptText << std::endl;
    	decryptText = rsa_pri_decrypt(encryptText, key[1]);
    	std::cout << "    : " << std::endl;
    	std::cout << decryptText << std::endl;
    
    	system("pause");
    	return 0;
    }

    実行結果
     
     
    ===      ===
    this is an example
    
    === md5   ===
        :   ! 
       : 9202816dabaaf34bb106a10421b9a0d0
    === sha256   ===
        :  X5   j/ ?17?P?4 zD
       : d44c035835f1c5e0668b7d186a2ff5b0
    === des    ===
        :
    ?/   t8: U ? 
        :
    this is an example
    
    === rsa    ===
      :
    -----BEGIN RSA PUBLIC KEY-----
    MIIBCAKCAQEA59WESdYbPsD6cYATooC4ebClTpvbTsu3X29Ha0g31kW3AmLR2zLj
    hMvdWjUhhVuM7xBoh3Ufoyj4jTGHVhunFfbzxNrt1Nb64N95bZH8e9u6LjJYqh4e
    sNoFknG+McjoSLNqGW9Yd8ejKH1Ju6C9SBUcC43XbB3XdC2matgV1zTsKhqjuywm
    gVN9DZdo2TlZkqsvOHC23rbQ+lP09rpQJ/RI4NQSnCUBqQxErCN85trcWRj1zyJA
    WaBZSvKh7J5RJcrC2ByMDmL7jrDDZl7YEolyW93SSc4xTE9Dr20OXznXNDsfQc9r
    RQHBri8Aqsu4WW3tHSBRmjW5kxFMxS4qxwIBAw==
    -----END RSA PUBLIC KEY-----
    
      :
    -----BEGIN RSA PRIVATE KEY-----
    MIIEowIBAAKCAQEA59WESdYbPsD6cYATooC4ebClTpvbTsu3X29Ha0g31kW3AmLR
    2zLjhMvdWjUhhVuM7xBoh3Ufoyj4jTGHVhunFfbzxNrt1Nb64N95bZH8e9u6LjJY
    qh4esNoFknG+McjoSLNqGW9Yd8ejKH1Ju6C9SBUcC43XbB3XdC2matgV1zTsKhqj
    uywmgVN9DZdo2TlZkqsvOHC23rbQ+lP09rpQJ/RI4NQSnCUBqQxErCN85trcWRj1
    zyJAWaBZSvKh7J5RJcrC2ByMDmL7jrDDZl7YEolyW93SSc4xTE9Dr20OXznXNDsf
    Qc9rRQHBri8Aqsu4WW3tHSBRmjW5kxFMxS4qxwIBAwKCAQEAmo5YMTlnfytRoQAN
    FwB6+8sY3xKSNIfPlPTaR4V6jtkkrEHhPMyXrd0+PCNrrj0In2BFr6NqbMX7CMuv
    jr0aDqSigzyejeSnQJT7nmFS/T0myXblxr6/IJFZDEvUITCa2yJGu5+QT9psxajb
    0mso2ri9XQk6SBPk+B5u8eVj5Myt4tqpWL0DEEDzwfhihs+uEGM7g6bPvQBI4JXu
    8uxfSRUkpyZ5s1koEhqj+RCguksPzSWO/Ut2Sd60iOUMRhya2aEbAyRTtfhsXja3
    4NMWjXorJ0SRkryM1iLJvVWkhkcr2vShH9rm9qz16BkrkI9/9Yx++GNNr6VU/p/+
    Waa8CwKBgQD4m0ryXi6rCqazdCICGoZJGzaljApOZ1rWOiotM9TekaYE7tZ2NDAT
    eytiCzxvs4/+1Jt5XzdGJ035VJKSai/n2ZzAq1YYtVHy5CG2olmeFtwaIWU18m2s
    RjHQf/FiscVB4XdKrHjh3gLgSB8MWMDg/krisxT86HNyp1UE2jZv+QKBgQDuuoez
    V+H23ktb9oDS9HuLXt+wZuww29uNb0jhVoLiqK6M90Pl2u8yErjsq04cG9pF0MUl
    8/nIw4RRKQh9GUOBBbxZqA/1yBxmHTz48siYJ3YXf5HB+0WxxOlEk3s05AnTilTi
    5Y4u9Ptwieoy+TOXatBL9XZgKkpHbcxKZH2gvwKBgQClvNyhlB8cscR3osFWvFmG
    EiRuXVw0ROc5fBweIo3ptm6t9I75eCAM/MeWsihKd7VUjbz7lM+EGjP7jbcMRsqa
    kRMrHOQQeOFMmBZ5wZEUDz1mwO4j9vPILsvgVUuXIS4r66TccvtBPqyVhWoIOytA
    qYdBzLiomvehxONYkXmf+wKBgQCfJwUiOpaklDI9TwCMov0HlJUgRJ115+ezn4Xr
    jwHscHRd+i1D50ohYdCdx4loEpGD4INuoqaF162LcLBTZi0Arn2RGrVOhWhEE337
    TIW6xPlk/7aBUi52g0Ytt6d4mAaNBuNB7l7J+KegW/F3UM0PnIrdTk7qxtwvnogx
    mFPAfwKBgAEuRGqF2Q9bNu/r0OufeFxsYm0zFvWBIxbq3DxPYRtzfhiQMeTOzl1g
    5rowAtb/w1SusGAZ4/lEUZoBgzV+8fr+rpx3eavVCmcXBVjDi9B5nNLIXWkcoEQG
    G/4ZwXUr5kyTBktL6mIBVNJ8dJUQo8xyxK0GjfWhlsk5t/Zu8tmK
    -----END RSA PRIVATE KEY-----
    
        :
      ?z_&   K ;J╄[i9?S ?て p?[hD∞51 ,k|1          ? w2?`vlu
    L

     
     
     
    注意:
    (1)公開鍵ファイルの読み出し時にPEM_read_RSA_PUBKEY()関数とPEM_read_RSAPublicKEY()の疑惑.秘密鍵ファイルを読み込むためのPEM_read_RSAPrivateKey()は、上記opensslコマンドで生成された公開鍵ファイルに対して、その内容を読み取る際に対称的なPEM_read_RSAPublicKEY()インタフェースは間違っています.PEM_を使わなければなりません.read_RSA_PUBKEY()のみ可能です.
    RSA PUBLIC KEYとPUBLIC KEYの2種類の公開鍵ファイルは格納方式が異なり、PEM_read_RSAPublicKEY()は、RSA PUBLIC KEYの先頭形式の公開鍵ファイル(関数で生成されたもの)のみを読み取ることができ、PEM_read_RSA_PUBKEY()は、PUBLIC KEYの先頭形式の公開鍵ファイル(コマンドラインで生成されたもの)のみを読み取ることができるので、公開鍵秘密鍵読み出し関数は、生成された鍵ペアのフォーマットに対応しなければならない.
    (2)公開鍵の暗号化と秘密鍵の復号化,秘密鍵の暗号化の両方を用いることができる.
    (3)一般的に暗号化された文字列は符号化が中国語に対応していないため文字化けであり,16進数列で出力する場合が多い
     
    (4)実際のエンジニアリングアプリケーションにおける鍵の読み取りペアのセキュリティ検証が必要
    (5)純粋なコードでopensslライブラリに依存しなくても,これらの復号アルゴリズムを自分で実現できるので,原理を明らかにすればよい.