Russian Qt Forum
Ноябрь 23, 2024, 20:28 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: OpenSSL RSA_sign работает через раз  (Прочитано 10781 раз)
Magvaj
Гость
« : Август 13, 2009, 19:14 »

Использую RSA_sign и RSA_verify для цифровой подписи. Ключ длиной 2048 бит.

Ключи грузятся нормально... цифровая подпись создаётся и всё вроде бы прекрасно. Но! Если в строке для подписи есть Base64 строка, то он может создать подпись, а может и не создать. С некоторыми ключами работает хоть как-то, а некоторые вообще отказываются принимать наже малюсенькие Base64 строки внутри документа (документ XML).

Пробовал разные алгоритмы для подписи- NID_md5_sha1, NID_sha1, NID_md5, NID_sha1WithRSA.
Пробовал менять длину ключа на 512 бит.
Пробовал использовать вместо RSA_sign RSA_sign_ASN1_OCTET_STRING

Результат один: если в документе содержится Base64- то подпись не создаётся с ошибкой: "error:00000000:lib(0):func(0):reason(0)"

Вот код которым подписываю:

Код:
QString ClientThread::signRSA(QString st)
{
    unsigned char *sigret=new unsigned char[2048];
    unsigned int siglen=0;

    qDebug(st.toAscii().data());
    qDebug(QVariant(strlen(st.toAscii().data())).toString().toAscii());

    int i=RSA_sign_ASN1_OCTET_STRING(0, (unsigned char*)st.toAscii().data(), strlen(st.toAscii().data()), sigret, &siglen, rsa_private);
    if(i==1)
    {
        QString a=QByteArray((char*)sigret, siglen).toBase64();
        delete sigret;
        return a;
    }
    else
    {
        delete sigret;
        qDebug("sign failed!");
        qDebug(QVariant(i).toString().toAscii());
        qDebug(ERR_error_string(i, NULL));
        return "";
    }
}

На самом удачном ключе вот это подписывается:
Код:
<auth login="Magvaj" pass="wmmTMJIyBg15XcOsIFb59zA3ZO8=" />

а это уже нет:
Код:
<sysuser action="add" name="kot" login="kot" pass="NA4k9qXcsfBYRa2sCqo1A5t+3Qc=" key="LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJDZ0tDQVFFQTFpanY4RktFTTN2MklCaW4vL1JQQW9rb1R2cDlwbElKdHVuRVBKZ2dHV092aFdRc2Q3NzcKK2hkOVlWaU0xWVV2Lzg1TmRnNkhibXk4YXFSSEcrT2NvT2R4RmREbnFma0FrNENOUE42SmJnQnNmbFN0MXZGZQorWWpjL2FrNnY3akQvOEwwN2dld0JUTnNYU2JUQjBodUFsNGp0aWVFMTNzN3JwazlnNFQ2bTJCT2p0b0haR2swCm5wMlFKOVBhUHh3SXlIbENJcXBFZ2xINi9wQll4TjVDcFVpSUpGMy9xT2VFanNRSGdpb1RWVE9qWjAxQWYwQUQKM0cvRHRIbXNTODRCTG5aaXNlak5URkpsd3lTNUFDMHR3cW1WVmpOU1Uvcm56Ui8zUmo3Uyt3TS9RNG93clZ3bQpFL3N2SmMrQmJidGk0am1IY0xQeG5jbVhLRmhURTh2SWZ3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0KOExhd46mv9n0EC1LaoqbrcDU6f8WLkdhfJi10/ISIzVIXHGHnrbP6QQgPVt6mqu90OT5AQ==" />

На других не подписывается даже первая строка. Если пароль поставить некодированным- то подпись проходит на всех ключах.

Уже неделю не могу решить загвоздку. Помогите, пожалуйста...

P.S: OpenSSL 0.9.8g
Записан
spectre71
Гость
« Ответ #1 : Август 13, 2009, 19:29 »

Если честно, нифига не понимаю в твоей проблеме, OpenSSL использую пока только для шифрования данных.
Может поможет более свежая версия?
openssl-0.9.8k
Записан
Magvaj
Гость
« Ответ #2 : Август 13, 2009, 19:42 »

Блин, думал если нет ответов- снести тему.

Решение нашлось(как всегда- пока не написал на форум- не получалось, как написал- решилось за две секунды)

Решение: почему-то нельзя использовать функцию strlen() для вычисления размера передаваемой на подпись строки... заменил функцию на sizeof()... и о чудо- работает.

Таким образом: RSA_sign_ASN1_OCTET_STRING(0, (unsigned char*)st.toAscii().data(), sizeof(st.toAscii().data()), sigret, &siglen, rsa_private) работает отменно, даже если сунуть ему 1,4 метровый XML полный Base64...

Вообщем, простите за глупость... все втыкались... я воткнулся...  Строит глазки
Записан
Magvaj
Гость
« Ответ #3 : Август 13, 2009, 19:48 »

На всякий случай замечу- что функция всё равно работает нормально только при алгоритмах NID_md5 или NID_sha1, если использовать двойные типа NID_md5_sha1- всё равно не создаёт подпись...

пожет пригодится тем, кто будет так же мучиться ;-)
Записан
spectre71
Гость
« Ответ #4 : Август 13, 2009, 20:33 »

Блин, думал если нет ответов- снести тему.

Решение нашлось(как всегда- пока не написал на форум- не получалось, как написал- решилось за две секунды)

Решение: почему-то нельзя использовать функцию strlen() для вычисления размера передаваемой на подпись строки... заменил функцию на sizeof()... и о чудо- работает.

Таким образом: RSA_sign_ASN1_OCTET_STRING(0, (unsigned char*)st.toAscii().data(), sizeof(st.toAscii().data()), sigret, &siglen, rsa_private) работает отменно, даже если сунуть ему 1,4 метровый XML полный Base64...

Вообщем, простите за глупость... все втыкались... я воткнулся...  Строит глазки

sizeof(st.toAscii().data())  ==  sizeof(char*)
Я ничего не путаю? Улыбающийся
Записан
Magvaj
Гость
« Ответ #5 : Август 14, 2009, 06:40 »


sizeof(st.toAscii().data())  ==  sizeof(char*)
Я ничего не путаю? Улыбающийся


ну да... а что не так?
Записан
Tonal
Гость
« Ответ #6 : Август 14, 2009, 07:35 »

Решение: почему-то нельзя использовать функцию strlen() для вычисления размера передаваемой на подпись строки... заменил функцию на sizeof()... и о чудо- работает.
Учи язык!

Таким образом: RSA_sign_ASN1_OCTET_STRING(0, (unsigned char*)st.toAscii().data(), sizeof(st.toAscii().data()), sigret, &siglen, rsa_private) работает отменно, даже если сунуть ему 1,4 метровый XML полный Base64...
Этим кодом ты создаёшь подпись для первых 2х или 4х символов строки в зависимости от платформы и компилятора.
Даже в случае пустой строки. Улыбающийся
Потому как sizeof(st.toAscii().data()) всегда равна размеру указателя на QChar.
А сам QChar - это 16-bit Unicode character.

Может тебе будет проще использовать QCA: Qt Cryptographic Architecture?
Или хотя бы поглядеть как оно там используется. Улыбающийся
Записан
Magvaj
Гость
« Ответ #7 : Август 17, 2009, 10:00 »

Учи язык!

Блин... действительно сглупил (ночью кодил- спать хотел)... значит всё таки косяк где-то есть... покурю QCA...
Записан
Magvaj
Гость
« Ответ #8 : Август 20, 2009, 08:59 »

Если кому будет интересно- решение было выдрано из кода OpenSSH.

Перед тем как использовать RSA_sign и RSA_verify необходимо установить какие-то структуры EVP. Сразу говорю- что они делают не знаю, но всё работает.

Код сервера:

Код:
bool ClientThread::setPublicKey(QString key)
{
    SSL_load_error_strings();
    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();
    BIO *mem = BIO_new(BIO_s_mem());
    BIO_puts (mem, key.toAscii().data());
    qDebug(key.toAscii());
    rsa_public=PEM_read_bio_RSAPublicKey(mem, NULL, NULL, NULL);

    if (rsa_public == NULL) return false;
    return true;
}

bool ClientThread::unsignRSA(QString text, QString sign)
{
    QByteArray a=QByteArray::fromBase64(sign.toAscii());
   
    unsigned char digest[2048];
    unsigned int dlen;
    const EVP_MD *evp_md;
    EVP_MD_CTX md;
    if ((evp_md = EVP_get_digestbynid(NID_md5)) == NULL) return false;
    EVP_DigestInit(&md, evp_md);
    EVP_DigestUpdate(&md, (unsigned char*)text.toAscii().data(), strlen(text.toAscii().data()));
    EVP_DigestFinal(&md, digest, &dlen);
   
    return RSA_verify(NID_md5, digest, dlen, (unsigned char*)a.data(), a.length(), rsa_public);
}

Код клиента:

Код:
QString ClientThread::signRSA(QString st)
{
    unsigned char *sigret=new unsigned char[2048];
    unsigned int siglen=0;

    unsigned char digest[2048];
    unsigned int dlen;
    const EVP_MD *evp_md;
    EVP_MD_CTX md;
    if ((evp_md = EVP_get_digestbynid(NID_md5)) == NULL) return false;
    EVP_DigestInit(&md, evp_md);
    EVP_DigestUpdate(&md, (unsigned char*)st.toAscii().data(), strlen(st.toAscii().data()));
    EVP_DigestFinal(&md, digest, &dlen);


    if(RSA_sign(NID_md5, digest, dlen, sigret, &siglen, rsa_private))
    {
        QString a=QByteArray((char*)sigret, siglen).toBase64();
        delete sigret;
        return a;
    }
    else
    {
        delete sigret;
        //qDebug("sign failed!");
        return "";
    }
}

bool ClientThread::setPrivateKey(QString filepath, QString pempass)
{
    SSL_load_error_strings();
  ERR_load_crypto_strings();
  OpenSSL_add_all_algorithms();

    FILE *priv_key_file=NULL;
    priv_key_file=fopen(filepath.toAscii(), "rb");
    if(priv_key_file)
    {
        rsa_private=PEM_read_RSAPrivateKey(priv_key_file, NULL, 0, pempass.toAscii().data());
        if (rsa_private == NULL) return false;
        fclose(priv_key_file);
        return true;
    }
    else return false;
}
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.048 секунд. Запросов: 20.