۱۳۸۹/۰۶/۰۸

نحوه‌ي استفاده از كتابخانه‌ي OpenSSL در ويندوز


سؤالي شده به اين مضمون : "یه الگوریتم دارم که بر طبق اون باید اعداد تصادفی خیلی بزرگ تولید کنم، اونها رو جمع و ضرب کنم. اینکه چطوری باید از dll یا lib استفاده کنم رو بلد نیستم. از VS2008 استفاده میکنم..."

سؤال در مورد زبان CPP است. كتابخانه‌ي استاندارد انجام اينگونه عمليات براي زبان‌هاي C و CPP ، كتابخانه‌ي OpenSSL است. البته شايد الان 100 كتابخانه ديگر را هم ليست كنيد، اما كساني كه با مباحث رمزنگاري اطلاعات مدتي كار كرده باشند، بعيد است سر و كارشان به اين كتابخانه نيفتاده باشد و يك استاندارد در اين زمينه به شمار مي‌رود؛ همچنين به دليل سورس باز بودن در اكثر سكوهاي كاري موجود نيز قابل استفاده است. بنابراين فراگيري نحوه‌ي كار كردن با آن يك مزيت به شمار مي‌رود. قسمتي از اين كتابخانه‌ي معظم مرتبط است به كار با اعداد بزرگ. اين مورد را هم جهت استفاده در الگوريتم RSA نياز دارد.
براي استفاده از آن در ويندوز ابتدا بايد OpenSSL را كامپايل كنيد. كار پر دردسري است. به همين جهت يك سايت فقط به اين موضوع اختصاص يافته و هربار آخرين نسخه‌ي OpenSSL را براي ويندوز كامپايل مي‌كند و در اختيار علاقمندان قرار مي‌دهد : +
در حال حاضر يا بايد Win32 OpenSSL v1.0.0a و يا Win64 OpenSSL v1.0.0a را دريافت كنيد (برنامه‌ي شما اگر 64 بيتي كامپايل شود، dll هاي 32 بيتي را نمي‌تواند بارگذاري كند و برعكس).

روش استفاده از كتابخانه‌ي OpenSSL در ويژوال CPP :

الف) ابتدا فايل‌هاي كامپايل شده‌ي فوق را دريافت و نصب كنيد. اكنون براي مثال يك پوشه‌ي OpenSSL-Win32 در كامپيوتر شما با محتويات اين كتابخانه بايد ايجاد شده باشد(اگر نسخه‌ي 32 بيتي را دريافت كرده‌ايد).
سپس به پوشه‌ي OpenSSL-Win32\lib\VC آن مراجعه كنيد. در اينجا فايل‌هاي كتابخانه‌اي جهت استفاده در ويژوال CPP قرار گرفته‌اند. اگر از محتويات پوشه OpenSSL-Win32\lib\VC\static استفاده كنيد، نيازي به توزيع فايل‌هاي DLL اين كتابخانه نخواهيد داشت و اگر از كتابخانه‌هاي OpenSSL-Win32\lib\VC استفاده كنيد، فايل‌هاي dll را نيز حتما بايد به همراه برنامه‌ي خود توزيع نمائيد.
سه نوع فايل در آن وجود دارند. ختم شده به MD ، MT و MDd كه معاني آن‌ها در مورد چند ريسماني بودن يا خير است (برگرفته شده از فايل faq.txt دريافتي):

Single Threaded /ML - MS VC++ often defaults to this for the release version of a new project.
Debug Single Threaded /MLd - MS VC++ often defaults to this for the debug version of a new project.
Multithreaded /MT
Debug Multithreaded /MTd
Multithreaded DLL /MD - OpenSSL defaults to this.
Debug Multithreaded DLL /MDd

ب) جهت سهولت كار، پوشه‌ي OpenSSL قرار گرفته در مسير OpenSSL-Win32\include را در آدرس زير كپي نمائيد:
C:\Program Files\Microsoft Visual Studio 10.0\VC\include
به اين صورت حين استفاده از اين كتابخانه نيازي به مشخص سازي محل قرارگيري فايل‌هاي include نخواهد بود.

ج) اكنون يك پروژه‌ي جديد Visual C++\Win32\Win32 console application را در VS.NET آغاز كنيد؛ براي مثال به نام OpenSSLTest .

د) سپس به منوي پروژه، گزينه‌ي خواص پروژه مراجعه كرده و مطابق تصاوير زير، اين فايل‌هاي كتابخانه‌اي را معرفي كنيد (انتخاب MD يا MT يا MDd بر اساس runtime library انتخاب شده است كه در تصاوير مشخص گرديده):









ه) اكنون يك مثال ساده در مورد ضرب دو عدد بزرگ به صورت زير مي‌تواند باشد:

#include "stdafx.h"
#include <openssl/bn.h>
#include <string.h>


void RotateBytes(unsigned char *in, int n)
{
unsigned char *e=in+n-1;
do {
unsigned char temp=*in;
*in++=*e;
*e-- =temp;
} while(in<e);
}

int _tmain(int argc, _TCHAR* argv[])
{
//دو عدد بزرگ جهت آزمايش
unsigned char testP[] = {0xD1,0x31,0x85,0x4D,0x00,0xD6,0x31,0x97,0x3A,0xFC,0xD2,0x27,0x02,0xEF,0xC2,0xA7};
unsigned char testA[] = {0xC7,0x1B,0x25,0x72,0x03,0xCB,0x72,0x03,0xCF,0x23,0x27,0x2D,0x00,0xD6,0x31,0x98};

//تبديل آرايه‌هاي فوق به فرمت اعداد بزرگ
BIGNUM *a = BN_new();
//it should be in "big-endian" form
RotateBytes(testA, 16);
BN_bin2bn(testA, 16, a);

BIGNUM *p = BN_new();
//it should be in "big-endian" form
RotateBytes(testP, 16);
BN_bin2bn(testP, 16, p);


//ضرب اين دو عدد در هم
BIGNUM *result = BN_new();
BN_CTX *ctx = BN_CTX_new();

BN_mul(result, a, p, ctx);

//نمايش نتيجه
//حاصل از چند بايت تشكيل شده؟
int num = BN_num_bytes(result);
if(num>0)
{
unsigned char *tmpdata;
if((tmpdata=(unsigned char *)malloc(num)))
memset(tmpdata, 0, num);

//تبديل عدد با فرمت اعداد بزرگ به آرايه‌اي از بايت‌ها
BN_bn2bin(result, tmpdata);
RotateBytes(tmpdata, num);

for(int i=0; i<num; i++)
{
if(i%16==0) printf("\n");
printf("%02X ",tmpdata[i]);
}

if(tmpdata) free(tmpdata);
}


//آزاد سازي منابع
BN_free(a);
BN_free(p);
BN_CTX_free(ctx);

return 0;
}


در مورد شرح توابع كتابخانه OpenSSL به اينجا مراجع كنيد : +
علت استفاده از تابع RotateBytes ، تغيير endian ورودي است.