Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > OpenSSL, пример использования


Автор: shutffl 7.11.2012, 16:03
Доброго времени суток!

Пишу ПО, испольующее свой сетевой протокол (а как иначе?), шифрующийся при передаче информации. Встала проблема работы с алгоритмами шифрования. В результате выбор пал на Blowfish. Так как ПО кроссплатформенное, то в качестве библиотеки шифрования была выбрана OpenSSL, включающая в себя (помимо прочего) Blowfish. После пары недель мучений и поисков док (которых особо нет) таки получилось что-то рабочее. С чем и хочу поделиться, вдруг кто-то сталкнется с подобной задачей.

Представленный далее код выполнен в виде законченного тестового приложения, демонстрирующего шифрование строки и последовательности из символов в шестнадцатиричной системе счисления (хексами). Дешифрование происходит только по первому шифру ибо нет смысла из одной и той же зашифрованной последовательности производить дешифрование.

Код с комментариями ниже.
Код

#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <openssl/evp.h>

//////////////////

#define BUFFER_SIZE 1024
#define CRYPT_SIZE 42

//////////////////

using namespace std;

//////////////////

// Passphrase key
unsigned char key[16] = {
    0x6b,0x60,0xcb,0x5b,
    0x82,0xce,0x90,0xb1,
    0xcc,0x2b,0x6c,0x55,
    0x6a,0x6b,0x6c,0x6d
};
// Init vector (not use and not needed, coz 0x00)
unsigned char iv[] = {0x00};

//////////////////

/*
 * Encrypt function
 *  Parameters:
 *  - data - string to encrypt
 *  - result - result encrypted string
 */
int do_bf_encrypt(unsigned char *data, unsigned char *result, unsigned char *key) {
    int result_len = 0;
    EVP_CIPHER_CTX ctx;

    // init context
    EVP_CIPHER_CTX_init(&ctx);

    // init encryption mechanism
    if (-1 == EVP_EncryptInit(&ctx, EVP_bf_cbc(), key, iv)) {
        return -1;
    }

    // encrypt data
    if (-1 == EVP_EncryptUpdate(&ctx, result, &result_len, data, strlen((const char *)data))) {
        return -1;
    }

    // finalize encryption
    if (-1 == EVP_EncryptFinal(&ctx, result+result_len, &result_len)) {
        return -1;
    }

    // clear context
    EVP_CIPHER_CTX_cleanup(&ctx);

    return 0;
}

//////////////////

/*
 * Decrypt function
 *  Parameters:
 *  - data - string to decrypt
 *  - result - result decrypted string
 *  - key
 */
int do_bf_decrypt(unsigned char *data, unsigned char *result, unsigned char *key) {
    int result_len = 0;
    EVP_CIPHER_CTX ctx;

    // init context
    EVP_CIPHER_CTX_init(&ctx);

    // init decrypt mechanism
    if (-1 == (EVP_DecryptInit(&ctx, EVP_bf_cbc(), key, iv))) {
        return -1;
    }

    // decrypt data
    if (-1 == EVP_DecryptUpdate(&ctx, result, &result_len, data, strlen((const char*)data))) {
        return -1;
    }

    // finalize decryption
    if (-1 == EVP_DecryptFinal(&ctx, result+result_len, &result_len)) {
        return -1;
    }

    // clear context
    EVP_CIPHER_CTX_cleanup(&ctx);

    return 0;
}

//////////////////

int main(int argc, char **argv) {
    unsigned char data_hex[] = {
        0x31, 0x32, 0x33, // 123
        0x61, 0x62, 0x63, // abc
        0x41, 0x42, 0x43, // ABC
        0x00
    };
    unsigned char result[CRYPT_SIZE];
    unsigned char decrypt_result[BUFFER_SIZE];
    unsigned char data[BUFFER_SIZE] = "123abcABC";

    memset(result, 0x00, CRYPT_SIZE);

    cout << "String (data): " << data << endl;
    cout << "String (data_hex): " << data_hex << endl;

    // try encrypt
    try {
        do_bf_encrypt(data, result, key);
        cout << "Encrypt result (data): " << result << endl;
        do_bf_encrypt(data_hex, result, key);
        cout << "Encrypt result (data_hex): " << result << endl;
    }
    catch (int e) {
        cerr << "Some error here" << endl;
        return EXIT_FAILURE;
    }

    // try decrypt
    try {
        memset(decrypt_result, 0x00, BUFFER_SIZE);
        do_bf_decrypt(result, decrypt_result, key);
        cout << "Decrypt result (data): " << decrypt_result << endl;
    }
    catch (int e) {
        cerr << "Some error here" << endl;
        return EXIT_FAILURE;
    }
    cout << "String (data, after encrypt): " << data << endl;
    cout << "String (data_hex, after encrypt): " << data_hex << endl;

    return EXIT_SUCCESS;
}


Вывод:
Код

String (data): 123abcABC
String (data_hex): 123abcABC
Encrypt result (data): ▒*aa▒Ԏ▒▒▒'|?▒
Encrypt result (data_hex): ▒*aa▒Ԏ▒▒▒'|?▒
Decrypt result (data): 123abcABC
String (data, after encrypt): 123abcABC
String (data_hex, after encrypt): 123abcABC


Хотелось бы уточнить, все ли тут правильно сделано? Не забываем, что этот пример только для коротких строк. Для длинных строк или файлов нужно использовать в цикле EVP_EncryptUpdate / EVP_DecryptUpdate, дабы шифровать кусками по, например, BUFFER_SIZE.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)