2010-06-29 11 views
17

पर ऑपरेशन का एन्क्रिप्शन मोड ओपनएसएसएल में नया, क्या कोई मुझे सी फाइल से एईएस सीटीआर मोड को प्रारंभ करने के तरीके में संकेत दे सकता है। मुझे पता है कि यह विधि हस्ताक्षर है लेकिन मुझे पैरामीटर के साथ समस्याएं आ रही हैं, कई दस्तावेज नहीं हैं और न ही एक सरल उदाहरण है कि एक सरल एन्क्रिप्शन कैसे बनाया जाए। अगर कोई इस विधि को कॉल का उदाहरण दे सकता है तो मैं सराहना करता हूं। अग्रिम में धन्यवाद!ओईएस सीटीआर 256 ओपनएसएसएल

void AES_ctr128_encrypt(const unsigned char *in, unsigned char *out, 
    const unsigned long length, const AES_KEY *key, 
    unsigned char ivec[AES_BLOCK_SIZE], 
    unsigned char ecount_buf[AES_BLOCK_SIZE], 
    unsigned int *num); 

हाय कैफ़े मैं वास्तव में यह वास्तव में उपयोगी साबित हुआ है अपने त्वरित जवाब की सराहना करते हैं, और defenetly सबसे अच्छा उदाहरण मैं वेब पर मिल गया है। मैं अनिश्चित लंबाई के साथ एक फ़ाइल खोलने की कोशिश कर रहा हूं, इसे एन्क्रिप्ट करें और सिफरटेक्स्ट जेनरेट के साथ एक और फाइल लिखें, फिर सिफर्ड फ़ाइल खोलें और सादे टेक्स्ट को पुनर्प्राप्त करें। मुझे काफी मात्रा में एमबी कारण की एक फ़ाइल का उपयोग करने की आवश्यकता है, मैं सीपीयू के प्रदर्शन को बेंचमार्क करना चाहता हूं। हालांकि मुझे अभी भी डिक्रिप्ट करते समय एक समस्या है। किसी भी तरह जब एक काफी txt फ़ाइलों (1504 केबी) को डिक्रिप्ट करते समय यह पूर्ण हो जाता है, और मुझे सादा पाठ में इसका आधा हिस्सा मिलता है और दूसरा आधा अभी भी सिफर किया जाता है। मुझे लगता है कि यह iv के आकार से संबंधित हो सकता है या जिस तरह से मैं काउंटर को बुला रहा हूं।

#include <openssl/aes.h> 
#include <stdio.h> 
#include <string.h> 

struct ctr_state { 
    unsigned char ivec[16]; 
    unsigned int num; 
    unsigned char ecount[16]; 
}; 

FILE *fp; 
FILE *rp; 
FILE *op; 
size_t count; 
char * buffer; 
AES_KEY key; 

int bytes_read, bytes_written; 
unsigned char indata[AES_BLOCK_SIZE]; 
unsigned char outdata[AES_BLOCK_SIZE]; 
unsigned char ckey[] = "thiskeyisverybad"; // It is 128bits though.. 
unsigned char iv[8] = {0};//This should be generated by RAND_Bytes I will take into consideration your previous post 
struct ctr_state state; 

int init_ctr(struct ctr_state *state, const unsigned char iv[8]){  
    state->num = 0; 
    memset(state->ecount, 0, 16);  
    memset(state->ivec + 8, 0, 8); 
    memcpy(state->ivec, iv, 8); 
} 

void encrypt(){ 
    //Opening files where text plain text is read and ciphertext stored  
    fp=fopen("input.txt","a+b"); 
    op=fopen("output.txt","w"); 
    if (fp==NULL) {fputs ("File error",stderr); exit (1);} 
    if (op==NULL) {fputs ("File error",stderr); exit (1);}  

    //Initializing the encryption KEY 
    AES_set_encrypt_key(ckey, 128, &key); 

    //Encrypting Blocks of 16 bytes and writing the output.txt with ciphertext 
while (1) {  
    init_ctr(&state, iv); //Counter call 
    bytes_read = fread(indata, 1, AES_BLOCK_SIZE, fp); 
    AES_ctr128_encrypt(indata, outdata, bytes_read, &key, state.ivec, state.ecount, &state.num);  
    bytes_written = fwrite(outdata, 1, bytes_read, op); 
    if (bytes_read < AES_BLOCK_SIZE) 
    break; 
    } 

    fclose (fp); 
    fclose (op); 
    free (buffer); 
} 

void decrypt(){ 
    //Opening files where text cipher text is read and the plaintext recovered   
    rp=fopen("recovered.txt","w"); 
    op=fopen("output.txt","a+b"); 
    if (rp==NULL) {fputs ("File error",stderr); exit (1);} 
    if (op==NULL) {fputs ("File error",stderr); exit (1);} 

    //Initializing the encryption KEY 
    AES_set_encrypt_key(ckey, 128, &key); 

    //Encrypting Blocks of 16 bytes and writing the output.txt with ciphertext 
    while (1) {  
    init_ctr(&state, iv);//Counter call 
    bytes_read = fread(indata, 1, AES_BLOCK_SIZE, op); 
    AES_ctr128_encrypt(indata, outdata, bytes_read, &key, state.ivec, state.ecount, &state.num); 
    bytes_written = fwrite(outdata, 1, bytes_read, rp); 
    if (bytes_read < AES_BLOCK_SIZE) 
    break; 
    } 
    fclose (rp); 
    fclose (op); 
    free (buffer); 
} 

int main(int argc, char *argv[]){ 
    encrypt(); 
    //decrypt(); 
    system("PAUSE"); 
    return 0; 
} 

प्रत्येक एन्क्रिप्ट और डिक्रिप्ट समारोह विभिन्न रन में कहा जाता है तो सब कुछ एक ही मूल्यों के साथ हमेशा आरंभ नहीं हो जाता: यहाँ क्या मैं अब तक है। संकेतों के लिए फिर से धन्यवाद, आप मुझे अग्रिम में & प्रदान कर सकते हैं !!!

+2

आपकी समस्या यह है कि आप प्रत्येक ब्लॉक के बाद काउंटर को फिर से शुरू कर रहे हैं। यह गलत है - 'एन्क्रिप्शन और डिक्रिप्शन दोनों में' जबकि() 'loops के बाहर' init_ctr() 'कॉल को ले जाएं। 'indata' और 'outdata' को' AES_BLOCK_SIZE' लंबाई की भी आवश्यकता नहीं है - वे काफी बड़े हो सकते हैं। – caf

+1

आपको * AES_encrypt' और दोस्तों का उपयोग नहीं करना चाहिए। यह एक सॉफ्टवेयर-केवल कार्यान्वयन है, इसलिए आप एईएस-एनआई जैसे हार्डवेयर समर्थन का आनंद नहीं लेंगे। आपको 'EVP_ *' फ़ंक्शंस का उपयोग करना चाहिए। ओपनएसएसएल विकी पर [ईवीपी सममित एन्क्रिप्शन और डिक्रिप्शन] देखें (http://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption)। वास्तव में, आपको शायद प्रमाणित एन्क्रिप्शन का उपयोग करना चाहिए क्योंकि यह * दोनों * गोपनीयता और प्रामाणिकता प्रदान करता है। ओपनएसएसएल विकी पर [ईवीपी प्रमाणीकृत एन्क्रिप्शन और डिक्रिप्शन] देखें (http://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption)। – jww

+0

यदि आप 'EVP_ *' फ़ंक्शंस का उपयोग करते हैं, तो ब्याज के सिफर 'EVP_aes_128_ctr',' EVP_aes_192_ctr' और 'EVP_aes_256_ctr' हैं। – jww

उत्तर

26

आमतौर पर, आप एक ही कुंजी और चतुर्थ, और एक वृद्धिशील काउंटर के साथ कई संदेश भेजने के लिए बार-बार AES_ctr128_encrypt() पर कॉल करना चाहते हैं। यह आपको 'ivec', 'संख्या' और कॉल के बीच 'ecount' मूल्यों का ट्रैक रखने की जरूरत का मतलब है - तो एक struct इन धारण करने के लिए बनाते हैं, और एक initialisation समारोह:

struct ctr_state { 
    unsigned char ivec[16]; /* ivec[0..7] is the IV, ivec[8..15] is the big-endian counter */ 
    unsigned int num; 
    unsigned char ecount[16]; 
}; 

int init_ctr(struct ctr_state *state, const unsigned char iv[8]) 
{ 
    /* aes_ctr128_encrypt requires 'num' and 'ecount' set to zero on the 
    * first call. */ 
    state->num = 0; 
    memset(state->ecount, 0, 16); 

    /* Initialise counter in 'ivec' to 0 */ 
    memset(state->ivec + 8, 0, 8); 

    /* Copy IV into 'ivec' */ 
    memcpy(state->ivec, iv, 8); 
} 

अब, जब आप संचार शुरू

unsigned char iv[8]; 
struct ctr_state state; 

if (!RAND_bytes(iv, 8)) 
    /* Handle the error */; 

init_ctr(&state, iv); 

फिर आप गंतव्य के लिए 8 बाइट चतुर्थ भेजने की आवश्यकता होगी: गंतव्य के साथ, आप का उपयोग करें और काउंटर आरंभ करने के लिए एक चतुर्थ जनरेट करना होगा। आप भी अपने कच्चे कुंजी बाइट्स से एक AES_KEY आरंभ करना होगा:

AES_KEY aes_key; 

if (!AES_set_encrypt_key(key, 128, &aes_key)) 
    /* Handle the error */; 

अब आप डेटा को एन्क्रिप्ट करने और इसे इस तरह AES_ctr128_encrypt() करने के लिए, गंतव्य के लिए भेजने के बार-बार कॉल के साथ शुरू कर सकते हैं:

if (!AES_ctr128_encrypt(msg_in, msg_out, msg_len, &aes_key, state->ivec, state->ecount, &state->num)) 
    /* Handle the error */; 

(msg_in सादा टेक्स्ट संदेश युक्त बफर के लिए एक सूचक है, msg_out एक बफर के लिए एक सूचक है जहां एन्क्रिप्टेड संदेश जाना चाहिए, और msg_len संदेश की लंबाई है)।

डिक्रिप्शन, बिल्कुल वैसा ही है, सिवाय इसके कि आप RAND_bytes() साथ चतुर्थ पैदा न करें - इसके बजाय, आप दूसरे पक्ष द्वारा दिए गए मान ले।

महत्वपूर्ण:

  1. करो नहीं कॉल एक बार से अधिक init_ctr() एन्क्रिप्शन प्रक्रिया के दौरान। एन्क्रिप्शन की शुरुआत से पहले काउंटर और IV को शुरू किया जाना चाहिए केवल

  2. किसी भी परिस्थिति में एन्क्रिप्शन पक्ष पर RAND_bytes() से कहीं भी चतुर्थ प्राप्त करने के लिए प्रेरित नहीं किया जा सकता है। इसे एक निश्चित मूल्य पर सेट न करें; हैश फ़ंक्शन का उपयोग न करें; प्राप्तकर्ता के नाम का उपयोग न करें; डिस्क से इसे मत पढ़ो। इसे RAND_bytes() के साथ उत्पन्न करें और इसे गंतव्य पर भेजें। जब भी आप शून्य काउंटर से शुरू करते हैं, तो आप एक पूरी तरह से ताजा चतुर्थ से शुरू होना चाहिए जिसका आपने पहले कभी उपयोग नहीं किया है।

  3. यदि यह संभव है कि आप IV और/या कुंजी को बदले बिना 2 ** 64 बाइट भेज रहे हों, तो आपको काउंटर ओवरफ्लोइंग के लिए परीक्षण करने की आवश्यकता होगी।

  4. त्रुटि-जांच को न छोड़ें। यदि कोई फ़ंक्शन विफल हो जाता है और आप इसे अनदेखा करते हैं, तो यह काफी संभव है (यहां तक ​​कि संभावना है) कि आपका सिस्टम सामान्य रूप से कार्यरत प्रतीत होता है, लेकिन वास्तव में पूरी तरह से असुरक्षित रूप से परिचालन करेगा।

+3

मुझे एक विवरण जोड़ें जो मैंने इसका उपयोग करते समय भाग लिया: num तर्क यह है कि आप कितने ब्लॉक में हैं, काउंटर नहीं। यदि आप पैकेट एन्क्रिप्ट कर रहे हैं (उदाहरण के लिए), हमेशा राज्य-> संख्या शून्य पर सेट करें और अपना काउंटर iv के उच्च बाइट्स में रखें। –

+0

@ माइक एल्किन्स: दरअसल - आप ओपनएसएसएल सीटीआर कार्यान्वयन की अपारदर्शी आंतरिक स्थिति के रूप में दोनों 'num' और 'ecount' का इलाज कर सकते हैं। ज्यादातर मामलों में उन्हें सीधे बदलने के लिए जरूरी नहीं होना चाहिए। – caf

2

यह अपने परीक्षण कार्यक्रम के साथ बुनियादी समस्या की तरह लग रहा है कि fopen कॉल की विधा मान सही नहीं है।

fp=fopen("input.txt","rb"); 
op=fopen("output.txt","wb"); 

और को डिक्रिप्ट में लोगों को:

rp=fopen("recovered.txt","wb"); 
op=fopen("output.txt","rb"); 

उनका कहना है लायक एक दूसरी बात यह है कि ckey शायद एक के रूप में घोषित किया जाना चाहिए मैं तुम्हें यह करने के लिए एन्क्रिप्ट में अपने fopen कॉल बदलने की जरूरत है लगता है 32 बाइट (256 बिट) बफर। यह सच है कि 128-बिट एन्क्रिप्शन केवल कुंजी से डेटा के 16 बाइट्स का उपयोग करता है। लेकिन ओपनएसएसएल फ़ंक्शन AES_set_encrypt_key (कम से कम संस्करण में मैं उपयोग कर रहा हूं) उस बफर से 32 बाइट्स पढ़ता है। यह केवल बाइट्स की उपयुक्त संख्या का उपयोग करता है, लेकिन पढ़ा जाता है। इसका मतलब है कि यदि बफर केवल 16-बाइट्स है और किसी पृष्ठ के अंत में अंत होता है जो स्मृति में एक गैर-पठनीय पृष्ठ के नजदीक होता है, तो इसका परिणाम उल्लंघन हो जाएगा।

ओह - और मैंने अभी देखा है कि वहाँ free पर एक बाहरी कॉल है। free(buffer); कॉल मान्य नहीं है क्योंकि बफर कभी आवंटित नहीं किया गया था। मुझे एहसास है कि आपका कोड सिर्फ एक साधारण परीक्षण है, लेकिन ... अच्छा, हम प्रोग्रामर हैं और खुद की मदद नहीं कर सकते हैं।