Spec-Zone.ru › Ruby 2.5

класс OpenSSL::Cipher

Родитель:
Объект

Предоставляет симметричные алгоритмы для шифрования и дешифрования. Доступные алгоритмы зависят от конкретной версии установленного OpenSSL.

Список всех поддерживаемых алгоритмов

Список поддерживаемых алгоритмов можно получить, выполнив

puts OpenSSL::Cipher.ciphers

Создание экземпляра Cipher

Существует несколько способов создания экземпляра Cipher. В целом, алгоритм Cipher классифицируется по его имени, длине ключа в битах и используемому режиму шифрования. Наиболее универсальный способ создания Cipher — следующий

cipher = OpenSSL::Cipher.new('<name>-<key length>-<mode>')

То есть, строка, состоящая из дефисно-связанного сочетания имени, длины ключа и режима. Можно использовать строки как с заглавными, так и с прописными буквами, например:

cipher = OpenSSL::Cipher.new('AES-128-CBC')

Для каждого поддерживаемого алгоритма в классе Cipher определен класс, названный в честь шифра, например, для получения экземпляра AES можно также использовать

# these are equivalent
cipher = OpenSSL::Cipher::AES.new(128, :CBC)
cipher = OpenSSL::Cipher::AES.new(128, 'CBC')
cipher = OpenSSL::Cipher::AES.new('128-CBC')

Наконец, из-за широкого распространения также определены дополнительные классы для различных размеров ключей AES

cipher = OpenSSL::Cipher::AES128.new(:CBC)
cipher = OpenSSL::Cipher::AES192.new(:CBC)
cipher = OpenSSL::Cipher::AES256.new(:CBC)

Выбор режима шифрования или дешифрования

Шифрование и дешифрование часто являются очень похожими операциями для симметричных алгоритмов, это отражается в отсутствии необходимости выбора разных классов для каждой операции; обе операции могут выполняться с использованием одного и того же класса. Тем не менее, после получения экземпляра Cipher, нам нужно указать экземпляру, что именно мы хотим с ним сделать, поэтому необходимо вызвать либо

cipher.encrypt

или

cipher.decrypt

на экземпляре Cipher. Это должно быть первое обращение после создания экземпляра, в противном случае настроенные ранее параметры могут быть потеряны в процессе.

Выбор ключа

Симметричное шифрование требует ключа, который одинаков для шифрования и дешифрования, и после первоначального установления ключа он должен храниться в конфиденциальности. Есть много способов создать небезопасные ключи, наиболее заметным из которых является просто взятие пароля в качестве ключа без дальнейшей обработки пароля. Простой и безопасный способ создания ключа для конкретного Cipher — это

cipher = OpenSSL::AES256.new(:CFB)
cipher.encrypt
key = cipher.random_key # also sets the generated key on the Cipher

Если вам абсолютно необходимо использовать пароли в качестве ключей шифрования, вы должны использовать функцию вывода ключа на основе пароля 2 (PBKDF2), сгенерировав ключ с помощью функциональности OpenSSL::PKCS5#pbkdf2_hmac_sha1 или OpenSSL::PKCS5#pbkdf2_hmac.

Хотя существует #pkcs5_keyivgen, его использование устарело, и его следует использовать только в устаревших приложениях, потому что он не использует новые алгоритмы PKCS#5 v2.

Выбор IV

Режимы шифрования CBC, CFB, OFB и CTR требуют «вектора инициализации» или, коротко, IV. Режим ECB — единственный режим, который не требует IV, но для него практически нет законных случаев использования из-за того, что он недостаточно скрывает паттерны открытого текста. Поэтому

Вы никогда не должны использовать режим ECB, если вы абсолютно уверены, что вам это абсолютно необходимо

По этой причине в любом случае вы получите режим, который явно требует IV. Хотя IV можно рассматривать как общедоступную информацию, т. е. он может быть передан публично после генерации, он все равно должен оставаться непредсказуемым, чтобы предотвратить определенные виды атак. Поэтому, в идеале

Всегда создавайте безопасный случайный IV для каждого шифрования вашего Cipher

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

cipher = ...
cipher.encrypt
key = cipher.random_key
iv = cipher.random_iv # also sets the generated IV on the Cipher

Хотя ключ, как правило, также является случайным значением, его использование в качестве IV — плохая идея. Есть сложные способы, с помощью которых злоумышленник может воспользоваться таким IV. Как общее правило, прямое или косвенное раскрытие ключа следует избегать в любом случае, и исключения следует делать только по уважительным причинам.

Вызов #final

Режимы ECB (который не следует использовать) и CBC являются блочными режимами. Это означает, что в отличие от других потоковых режимов, они работают с блоками данных фиксированного размера, и поэтому требуют шага «завершения», чтобы произвести или правильно расшифровать последний блок данных путем надлежащего обработки какой-либо формы заполнения. Поэтому крайне важно добавить результат #final в ваш буфер шифрования/дешифрования, иначе вы получите ошибки дешифрования или усеченные данные.

Хотя для потоковых шифров это не так уж и необходимо, все же рекомендуется применять ту же схему добавления результата #final и туда — это также позволит вам в будущем легче переключаться между режимами.

Шифрование и дешифрование данных

data = "Very, very confidential data"

cipher = OpenSSL::Cipher::AES.new(128, :CBC)
cipher.encrypt
key = cipher.random_key
iv = cipher.random_iv

encrypted = cipher.update(data) + cipher.final
...
decipher = OpenSSL::Cipher::AES.new(128, :CBC)
decipher.decrypt
decipher.key = key
decipher.iv = iv

plain = decipher.update(encrypted) + decipher.final

puts data == plain #=> true

Аутентифицированное шифрование и связанные данные (AEAD)

Если используемая версия OpenSSL поддерживает это, режим аутентифицированного шифрования (например, GCM или CCM) всегда следует предпочесть любому незащищенному режиму. В настоящее время OpenSSL поддерживает режим AE только в сочетании со связанными данными (AEAD), где дополнительные связанные данные включаются в процесс шифрования для вычисления тега в конце шифрования. Этот тег также будет использоваться в процессе дешифрования и путем проверки его валидности устанавливается подлинность данного шифрованного текста.

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

Связанные данные используются, когда имеется дополнительная информация, такая как заголовки или метаданные, которые также должны быть аутентифицированы, но не обязательно шифруются. Если связанные данные не нужны для шифрования и последующей дешифровки, библиотека OpenSSL по-прежнему требует установки значения — «» можно использовать, если таковых нет.

Пример с использованием GCM (режим Галоа/счётчик). У вас есть 16-байтовый ключ, 12-байтовый (96-битный) nonce и связанные данные auth_data. Убедитесь, что вы не повторно используете пару ключ и nonce. Повторное использование nonce нарушает гарантии безопасности режима GCM.

cipher = OpenSSL::Cipher::AES.new(128, :GCM).encrypt
cipher.key = key
cipher.iv = nonce
cipher.auth_data = auth_data

encrypted = cipher.update(data) + cipher.final
tag = cipher.auth_tag # produces 16 bytes tag by default

Теперь вы получатель. Вам известен ключ, и вы получили nonce, auth_data, encrypted и tag через небезопасную сеть. Обратите внимание, что GCM принимает тег произвольной длины от 1 до 16 байт. Кроме того, вам может потребоваться проверить, что полученный тег имеет правильную длину, или вы позволяете злоумышленникам подделать допустимый тег размером в один байт для сфальсифицированного шифрованного текста с вероятностью 1/256.

raise "tag is truncated!" unless tag.bytesize == 16
decipher = OpenSSL::Cipher::AES.new(128, :GCM).decrypt
decipher.key = key
decipher.iv = nonce
decipher.auth_tag = tag
decipher.auth_data = auth_data

decrypted = decipher.update(encrypted) + decipher.final

puts data == decrypted #=> true

Методы класса Public

OpenSSL::Cipher.ciphers → array[string...] Показать исходный код
static VALUE
ossl_s_ciphers(VALUE self)
{
    VALUE ary;

    ary = rb_ary_new();
    OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
                    (void(*)(const OBJ_NAME*,void*))add_cipher_name_to_ary,
                    (void*)ary);

    return ary;
}

Возвращает имена всех доступных шифров в массиве.

new(string) → cipher Показать исходный код
static VALUE
ossl_cipher_initialize(VALUE self, VALUE str)
{
    EVP_CIPHER_CTX *ctx;
    const EVP_CIPHER *cipher;
    char *name;

    name = StringValueCStr(str);
    GetCipherInit(self, ctx);
    if (ctx) {
        ossl_raise(rb_eRuntimeError, "Cipher already initialized!");
    }
    AllocCipher(self, ctx);
    if (!(cipher = EVP_get_cipherbyname(name))) {
        ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%"PRIsVALUE")", str);
    }
    if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
        ossl_raise(eCipherError, NULL);

    return self;
}

Строка должна быть допустимым именем шифра, например, «AES-128-CBC» или «3DES».

Список имен шифров доступен путем вызова ::ciphers.

Общедоступные методы экземпляра

auth_data = строка → строка Показать исходный код
static VALUE
ossl_cipher_set_auth_data(VALUE self, VALUE data)
{
    EVP_CIPHER_CTX *ctx;
    unsigned char *in;
    long in_len, out_len;

    StringValue(data);

    in = (unsigned char *) RSTRING_PTR(data);
    in_len = RSTRING_LEN(data);

    GetCipher(self, ctx);
    if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
        ossl_raise(eCipherError, "AEAD not supported by this cipher");

    if (!ossl_cipher_update_long(ctx, NULL, &out_len, in, in_len))
        ossl_raise(eCipherError, "couldn't set additional authenticated data");

    return data;
}

Устанавливает дополнительные данные для аутентификации шифра. Это поле должно быть установлено при использовании режимов шифрования AEAD, таких как GCM или CCM. Если не требуется использование связанных данных, этот метод должен все равно вызываться со значением “”. Содержимое этого поля должно быть несекретными данными, которые будут добавлены к шифрованному тексту для создания тега аутентификации, который проверяет содержимое шифрованного текста.

AAD должен быть установлен до шифрования или дешифрования. В режиме шифрования он должен быть установлен после вызова #encrypt и установки #key= и #iv=. При дешифровании аутентифицированные данные должны быть установлены после ключа, IV и, особенно, после установки тега аутентификации. То есть, установите их только после вызова #decrypt, #key=, #iv= и #auth_tag=.

auth_tag(tag_len = 16) → Строка Показать исходный код
static VALUE
ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
{
    VALUE vtag_len, ret;
    EVP_CIPHER_CTX *ctx;
    int tag_len = 16;

    rb_scan_args(argc, argv, "01", &vtag_len);
    if (NIL_P(vtag_len))
        vtag_len = rb_attr_get(self, id_auth_tag_len);
    if (!NIL_P(vtag_len))
        tag_len = NUM2INT(vtag_len);

    GetCipher(self, ctx);

    if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
        ossl_raise(eCipherError, "authentication tag not supported by this cipher");

    ret = rb_str_new(NULL, tag_len);
    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, RSTRING_PTR(ret)))
        ossl_raise(eCipherError, "retrieving the authentication tag failed");

    return ret;
}

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

Тег можно получить только после вызова #final.

auth_tag = строка → строка Показать исходный код
static VALUE
ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
{
    EVP_CIPHER_CTX *ctx;
    unsigned char *tag;
    int tag_len;

    StringValue(vtag);
    tag = (unsigned char *) RSTRING_PTR(vtag);
    tag_len = RSTRING_LENINT(vtag);

    GetCipher(self, ctx);
    if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
        ossl_raise(eCipherError, "authentication tag not supported by this cipher");

    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, tag))
        ossl_raise(eCipherError, "unable to set AEAD tag");

    return vtag;
}

Устанавливает тег аутентификации для проверки целостности зашифрованного текста. Это можно вызвать только в том случае, если шифр поддерживает AE. Тег должен быть установлен после вызова #decrypt, #key= и #iv=, но перед вызовом #final. После завершения всех операций дешифрования тег автоматически проверяется при вызове #final.

Для режима OCB длина тега должна быть задана предварительно с помощью auth_tag_len=.

auth_tag_len = Целое число → Целое число Показать исходный код
static VALUE
ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
{
    int tag_len = NUM2INT(vlen);
    EVP_CIPHER_CTX *ctx;

    GetCipher(self, ctx);
    if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
        ossl_raise(eCipherError, "AEAD not supported by this cipher");

    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL))
        ossl_raise(eCipherError, "unable to set authentication tag length");

    /* for #auth_tag */
    rb_ivar_set(self, id_auth_tag_len, INT2NUM(tag_len));

    return vlen;
}

Устанавливает длину тега аутентификации, который должен быть сгенерирован или предоставлен для шифров AEAD, которые требуют его в качестве входного параметра. Обратите внимание, что не все шифры AEAD поддерживают этот метод.

В режиме OCB длина должна быть задана как при шифровании, так и при дешифровании и должна быть указана до задания IV.

authenticated? → true | false Показать исходный код
static VALUE
ossl_cipher_is_authenticated(VALUE self)
{
    EVP_CIPHER_CTX *ctx;

    GetCipher(self, ctx);

    return (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse;
}

Указывает, использует ли этот экземпляр Шифра режим аутентифицированного шифрования.

block_size → целое число Показать исходный код
static VALUE
ossl_cipher_block_size(VALUE self)
{
    EVP_CIPHER_CTX *ctx;

    GetCipher(self, ctx);

    return INT2NUM(EVP_CIPHER_CTX_block_size(ctx));
}

Возвращает размер блоков в байтах, на которых этот Шифр работает.

decrypt → self Показать исходный код
static VALUE
ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self)
{
    return ossl_cipher_init(argc, argv, self, 0);
}

Инициализирует Шифр для дешифрования.

Убедитесь, что вы вызвали #encrypt или #decrypt перед использованием следующих методов:

  • key=, iv=, random_key, random_iv, pkcs5_keyivgen

Внутренне вызывает EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 0).

encrypt → self Показать исходный код
static VALUE
ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self)
{
    return ossl_cipher_init(argc, argv, self, 1);
}

Инициализирует Шифр для шифрования.

Убедитесь, что вы вызвали #encrypt или #decrypt перед использованием следующих методов:

  • key=, iv=, random_key, random_iv, pkcs5_keyivgen

Внутренне вызывает EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 1).

final → строка Показать исходный код
static VALUE
ossl_cipher_final(VALUE self)
{
    EVP_CIPHER_CTX *ctx;
    int out_len;
    VALUE str;

    GetCipher(self, ctx);
    str = rb_str_new(0, EVP_CIPHER_CTX_block_size(ctx));
    if (!EVP_CipherFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), &out_len))
        ossl_raise(eCipherError, NULL);
    assert(out_len <= RSTRING_LEN(str));
    rb_str_set_len(str, out_len);

    return str;
}

Возвращает оставшиеся данные, содержащиеся в объекте шифра. Дальнейшие вызовы #update или #final вернут мусор. Этот вызов всегда должен выполняться последним в операции шифрования или дешифрования после того, как весь открытый текст или зашифрованный текст были предоставлены экземпляру Шифра.

Если использовался аутентифицированный шифр, возникает CipherError, если тег не удалось аутентифицировать. Вызывайте этот метод только после установки тега аутентификации и передачи всего содержимого зашифрованного текста в шифр.

initialize_copy(p1) Показать исходный код
static VALUE
ossl_cipher_copy(VALUE self, VALUE other)
{
    EVP_CIPHER_CTX *ctx1, *ctx2;

    rb_check_frozen(self);
    if (self == other) return self;

    GetCipherInit(self, ctx1);
    if (!ctx1) {
        AllocCipher(self, ctx1);
    }
    GetCipher(other, ctx2);
    if (EVP_CIPHER_CTX_copy(ctx1, ctx2) != 1)
        ossl_raise(eCipherError, NULL);

    return self;
}
iv = строка → строка Показать исходный код
static VALUE
ossl_cipher_set_iv(VALUE self, VALUE iv)
{
    EVP_CIPHER_CTX *ctx;
    int iv_len = 0;

    StringValue(iv);
    GetCipher(self, ctx);

    if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)
        iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
    if (!iv_len)
        iv_len = EVP_CIPHER_CTX_iv_length(ctx);
    if (RSTRING_LEN(iv) != iv_len)
        ossl_raise(rb_eArgError, "iv must be %d bytes", iv_len);

    if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, (unsigned char *)RSTRING_PTR(iv), -1) != 1)
        ossl_raise(eCipherError, NULL);

    return iv;
}

Устанавливает IV шифра. Обратите внимание, что, поскольку вы никогда не должны использовать режим ECB, IV всегда явно требуется и должен быть задан перед шифрованием. Сам IV может быть безопасно передан публично, но он должен быть непредсказуемым, чтобы предотвратить определенные виды атак. Для создания безопасного случайного IV можно использовать #random_iv.

Вызывайте этот метод только после вызова #encrypt или #decrypt.

iv_len → целое число Показать исходный код
static VALUE
ossl_cipher_iv_length(VALUE self)
{
    EVP_CIPHER_CTX *ctx;
    int len = 0;

    GetCipher(self, ctx);
    if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)
        len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);
    if (!len)
        len = EVP_CIPHER_CTX_iv_length(ctx);

    return INT2NUM(len);
}

Возвращает ожидаемую длину IV в байтах для этого Шифра.

iv_len = целое число → целое число Показать исходный код
static VALUE
ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
{
    int len = NUM2INT(iv_length);
    EVP_CIPHER_CTX *ctx;

    GetCipher(self, ctx);
    if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))
        ossl_raise(eCipherError, "cipher does not support AEAD");

    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, len, NULL))
        ossl_raise(eCipherError, "unable to set IV length");

    /*
     * EVP_CIPHER_CTX_iv_length() returns the default length. So we need to save
     * the length somewhere. Luckily currently we aren't using app_data.
     */
    EVP_CIPHER_CTX_set_app_data(ctx, (void *)(VALUE)len);

    return iv_length;
}

Устанавливает длину IV/nonce Шифра. Обычно блочные шифры не позволяют изменять длину IV, но некоторые используют IV для «nonce». Вам может потребоваться это для межплатформенной совместимости с другими приложениями.

key = строка → строка Показать исходный код
static VALUE
ossl_cipher_set_key(VALUE self, VALUE key)
{
    EVP_CIPHER_CTX *ctx;
    int key_len;

    StringValue(key);
    GetCipher(self, ctx);

    key_len = EVP_CIPHER_CTX_key_length(ctx);
    if (RSTRING_LEN(key) != key_len)
        ossl_raise(rb_eArgError, "key must be %d bytes", key_len);

    if (EVP_CipherInit_ex(ctx, NULL, NULL, (unsigned char *)RSTRING_PTR(key), NULL, -1) != 1)
        ossl_raise(eCipherError, NULL);

    rb_ivar_set(self, id_key_set, Qtrue);

    return key;
}

Устанавливает ключ шифра. Для генерации ключа вы должны использовать либо случайную строку байтов, либо, если ключ должен быть получен из пароля, вы должны использовать функциональность PBKDF2, предоставляемую OpenSSL::PKCS5. Для генерации безопасного случайного ключа можно использовать #random_key.

Вызывайте этот метод только после вызова #encrypt или #decrypt.

key_len → целое число Показать исходный код
static VALUE
ossl_cipher_key_length(VALUE self)
{
    EVP_CIPHER_CTX *ctx;

    GetCipher(self, ctx);

    return INT2NUM(EVP_CIPHER_CTX_key_length(ctx));
}

Возвращает длину ключа в байтах Шифра.

key_len = целое число → целое число Показать исходный код
static VALUE
ossl_cipher_set_key_length(VALUE self, VALUE key_length)
{
    int len = NUM2INT(key_length);
    EVP_CIPHER_CTX *ctx;

    GetCipher(self, ctx);
    if (EVP_CIPHER_CTX_set_key_length(ctx, len) != 1)
        ossl_raise(eCipherError, NULL);

    return key_length;
}

Устанавливает длину ключа шифра. Если шифр — шифр с фиксированной длиной, то попытка установить длину ключа, отличную от фиксированного значения, является ошибкой.

В нормальных условиях вам не нужно вызывать этот метод (и, вероятно, не следует).

Дополнительную информацию см. в EVP_CIPHER_CTX_set_key_length.

имя → строка Показать исходный код
static VALUE
ossl_cipher_name(VALUE self)
{
    EVP_CIPHER_CTX *ctx;

    GetCipher(self, ctx);

    return rb_str_new2(EVP_CIPHER_name(EVP_CIPHER_CTX_cipher(ctx)));
}

Возвращает имя шифра, которое может незначительно отличаться от исходного имени.

padding = целое число → целое число Показать исходный код
static VALUE
ossl_cipher_set_padding(VALUE self, VALUE padding)
{
    EVP_CIPHER_CTX *ctx;
    int pad = NUM2INT(padding);

    GetCipher(self, ctx);
    if (EVP_CIPHER_CTX_set_padding(ctx, pad) != 1)
        ossl_raise(eCipherError, NULL);
    return padding;
}

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

Дополнительную информацию см. в EVP_CIPHER_CTX_set_padding.

pkcs5_keyivgen(пароль, соль = nil, итерации = 2048, хэш = "MD5") → nil Показать исходный код
static VALUE
ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
{
    EVP_CIPHER_CTX *ctx;
    const EVP_MD *digest;
    VALUE vpass, vsalt, viter, vdigest;
    unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH], *salt = NULL;
    int iter;

    rb_scan_args(argc, argv, "13", &vpass, &vsalt, &viter, &vdigest);
    StringValue(vpass);
    if(!NIL_P(vsalt)){
        StringValue(vsalt);
        if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN)
            ossl_raise(eCipherError, "salt must be an 8-octet string");
        salt = (unsigned char *)RSTRING_PTR(vsalt);
    }
    iter = NIL_P(viter) ? 2048 : NUM2INT(viter);
    if (iter <= 0)
        rb_raise(rb_eArgError, "iterations must be a positive integer");
    digest = NIL_P(vdigest) ? EVP_md5() : ossl_evp_get_digestbyname(vdigest);
    GetCipher(self, ctx);
    EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt,
                   (unsigned char *)RSTRING_PTR(vpass), RSTRING_LENINT(vpass), iter, key, iv);
    if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, -1) != 1)
        ossl_raise(eCipherError, NULL);
    OPENSSL_cleanse(key, sizeof key);
    OPENSSL_cleanse(iv, sizeof iv);

    rb_ivar_set(self, id_key_set, Qtrue);

    return Qnil;
}

Генерирует и устанавливает ключ/IV на основе пароля.

ПРЕДУПРЕЖДЕНИЕ: Этот метод совместим с PKCS5 v1.5 только при использовании RC2, RC4-40 или DES с MD5 или SHA1. При использовании чего-либо еще (например, AES) ключ/IV будет сгенерирован с использованием специфичного для OpenSSL метода. Этот метод устарел и больше не должен использоваться. Используйте метод генерации ключа PKCS5 v2 из OpenSSL::PKCS5 вместо этого.

Параметры

  • соль должна быть строкой длиной 8 байт, если она указана.

  • итерации — целое число, по умолчанию 2048.

  • хэш — объект Digest, по умолчанию 'MD5'

Рекомендуется минимальное количество итераций 1000.

random_iv → iv Показать исходный код
# File ext/openssl/lib/openssl/cipher.rb, line 54
def random_iv
  str = OpenSSL::Random.random_bytes(self.iv_len)
  self.iv = str
end

Генерирует случайный IV с помощью OpenSSL::Random.random_bytes и устанавливает его в шифр, а затем возвращает его.

Вы должны вызвать encrypt или decrypt перед вызовом этого метода.

random_key → ключ Показать исходный код
# File ext/openssl/lib/openssl/cipher.rb, line 42
def random_key
  str = OpenSSL::Random.random_bytes(self.key_len)
  self.key = str
end

Генерирует случайный ключ с помощью OpenSSL::Random.random_bytes и устанавливает его в шифр, а затем возвращает его.

Вы должны вызвать encrypt или decrypt перед вызовом этого метода.

reset → self Показать исходный код
static VALUE
ossl_cipher_reset(VALUE self)
{
    EVP_CIPHER_CTX *ctx;

    GetCipher(self, ctx);
    if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1) != 1)
        ossl_raise(eCipherError, NULL);

    return self;
}

Полностью сбрасывает внутреннее состояние Cipher. Благодаря этому один экземпляр Cipher может быть использован несколько раз для задач шифрования или расшифровки.

Внутренне вызывает EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1).

update(данные [, буфер]) → строка или буфер Показать исходный код
static VALUE
ossl_cipher_update(int argc, VALUE *argv, VALUE self)
{
    EVP_CIPHER_CTX *ctx;
    unsigned char *in;
    long in_len, out_len;
    VALUE data, str;

    rb_scan_args(argc, argv, "11", &data, &str);

    if (!RTEST(rb_attr_get(self, id_key_set)))
        ossl_raise(eCipherError, "key not set");

    StringValue(data);
    in = (unsigned char *)RSTRING_PTR(data);
    if ((in_len = RSTRING_LEN(data)) == 0)
        ossl_raise(rb_eArgError, "data must not be empty");
    GetCipher(self, ctx);
    out_len = in_len+EVP_CIPHER_CTX_block_size(ctx);
    if (out_len <= 0) {
        ossl_raise(rb_eRangeError,
                   "data too big to make output buffer: %ld bytes", in_len);
    }

    if (NIL_P(str)) {
        str = rb_str_new(0, out_len);
    } else {
        StringValue(str);
        rb_str_resize(str, out_len);
    }

    if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len))
        ossl_raise(eCipherError, NULL);
    assert(out_len < RSTRING_LEN(str));
    rb_str_set_len(str, out_len);

    return str;
}

Шифрует данные в потоковом режиме. Передавайте последовательные блоки данных методу update, чтобы зашифровать их. Возвращает зашифрованный фрагмент данных. Когда закончите, к результату необходимо добавить результат вызова #final.

Если buffer задан, результат шифрования/расшифровки будет записан в него. buffer будет автоматически изменён в размере.

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API