Получить открытый ключ ECDSA только из координаты x, используя библиотеку Crypto ++ - PullRequest
0 голосов
/ 06 февраля 2019

Я реализую демон безопасности в области автомобильной связи.

Я мог бы получить сообщение с подписью и сжатой координатой X точки для проверки этой подписи.Эллиптическая кривая может быть либо secp256, либо brainpoolp256r1, а алгоритм - ECDSA.

Мой вопрос: как мне восстановить точку ECC (и, следовательно, открытый ключ), используя только сжатую X-координату с Crypto ++?библиотека?

Я перешел по некоторым ссылкам, которые объясняют это (и многие другие) https://www.cryptopp.com/wiki/Point_Compression Ключи Crypto ++ и Compressed EC , но они не соответствуют моей проблеме.

Я пытался создать код для решения проблемы, но он не работает:

#include <string>
#include <iostream>
#include <cryptopp/cryptlib.h>
#include <cryptopp/ecp.h>
#include <cryptopp/eccrypto.h>
#include <cryptopp/hex.h>
#include <cryptopp/oids.h>
#include <cryptopp/osrng.h>

using namespace CryptoPP;
using std::cout;
using std::endl;
using std::string;

int main() 
{
    string compactPoint = "937120662418500f3ad7c892b1db7e7c2d85ec48c74e99d64dcb7083082bb4f3";

    AutoSeededRandomPool generator;
    ECDSA<ECP, SHA256>::PublicKey pubKey;
    OID curve       = ASN1::secp256r1();


    StringSource ss (compactPoint, true, new CryptoPP::HexDecoder);
    ECP::Point point;

    pubKey.GetGroupParameters().GetCurve().DecodePoint (point, ss, ss.MaxRetrievable());

    std::cout << "Result after decompression X: " << std::hex << point.x << std::endl;
    std::cout << "Result after decompression Y: " << std::hex << point.y << std::endl;

    return 0;
}

Не могли бы вы мне помочь, пожалуйста?

1 Ответ

0 голосов
/ 06 февраля 2019

Самым простым решением, вероятно, является добавление "02" oe "03" к компактному представлению .Crypto ++ затем декодирует его как сжатый открытый ключ.

$ cat test.cxx

#include "cryptlib.h"
#include "eccrypto.h"
#include "ecp.h"
#include "hex.h"
#include "oids.h"

#include <string>
#include <iostream>
#include <iomanip>

int main(int argc, char* argv[])
{
    using namespace CryptoPP;

    ECDSA<ECP, SHA256>::PublicKey pubKey;
    pubKey.AccessGroupParameters().Initialize(ASN1::secp256r1());

    std::string compactPoint = "02" /* compressed */
        "937120662418500f3ad7c892b1db7e7c"
        "2d85ec48c74e99d64dcb7083082bb4f3";

    StringSource ss (compactPoint, true, new HexDecoder);
    ECP::Point point;

    pubKey.GetGroupParameters().GetCurve().DecodePoint (point, ss, ss.MaxRetrievable());

    std::cout << "Result after decompression X: " << std::hex << point.x << std::endl;
    std::cout << "Result after decompression Y: " << std::hex << point.y << std::endl;

    return 0;
}

И затем собирает и запускает программу.Обратите внимание, что библиотека решает для части y координаты.

cryptopp$ g++ test.cxx ./libcryptopp.a -o test.exe
cryptopp$ ./test.exe
Result after decompression X: 937120662418500f3ad7c892b1db7e7c2d85ec48c74e99d64dcb7083082bb4f3h
Result after decompression Y: cfcaf74eae3ceec5993928f04970cfef343b9a6b22727fa81926bd21f256ec56h

И чтобы избавить вас от необходимости искать ее, вы можете установить открытый элемент для publicKey, используя:

pubKey.SetPublicElement(point);

std::cout << "X: " << std::hex << pubKey.GetPublicElement().x << std::endl;
std::cout << "Y: " << std::hex << pubKey.GetPublicElement().y << std::endl;

Работа с дополнительным кодом дает ожидаемый результат:

$ ./test.exe
Result after decompression X: 937120662418500f3ad7c892b1db7e7c2d85ec48c74e99d64dcb7083082bb4f3h
Result after decompression Y: cfcaf74eae3ceec5993928f04970cfef343b9a6b22727fa81926bd21f256ec56h
X: 937120662418500f3ad7c892b1db7e7c2d85ec48c74e99d64dcb7083082bb4f3h
Y: cfcaf74eae3ceec5993928f04970cfef343b9a6b22727fa81926bd21f256ec56h

Если интересно, вот код, который вы используете для декодирования точки из ecp.cpp:

bool ECP::DecodePoint(ECP::Point &P, BufferedTransformation &bt, size_t encodedPointLen) const
{
    byte type;
    if (encodedPointLen < 1 || !bt.Get(type))
        return false;

    switch (type)
    {
    case 0:
        P.identity = true;
        return true;
    case 2:
    case 3:
    {
        if (encodedPointLen != EncodedPointSize(true))
            return false;

        Integer p = FieldSize();

        P.identity = false;
        P.x.Decode(bt, GetField().MaxElementByteLength());
        P.y = ((P.x*P.x+m_a)*P.x+m_b) % p;

        if (Jacobi(P.y, p) !=1)
            return false;

        P.y = ModularSquareRoot(P.y, p);

        if ((type & 1) != P.y.GetBit(0))
            P.y = p-P.y;

        return true;
    }
    case 4:
    {
        if (encodedPointLen != EncodedPointSize(false))
            return false;

        unsigned int len = GetField().MaxElementByteLength();
        P.identity = false;
        P.x.Decode(bt, len);
        P.y.Decode(bt, len);
        return true;
    }
    default:
        return false;
    }
}

Я упоминаю об этом на случай, если вы захотите решить для y координаты себя, заполните point, а затем позвоните SetPublicElement напрямую.


Вы также можете добавить 03 вместо 02.Разница в том, что декодирование возвращает либо y, либо p-y.Изменчивость вводится из-за модульного квадратного корня, показанного выше.Нам нужно увидеть алгоритм генерации, чтобы определить, какое значение должно быть.

Вот разница при использовании 03 вместо 02:

$ ./test.exe
X: 937120662418500f3ad7c892b1db7e7c2d85ec48c74e99d64dcb7083082bb4f3h
Y: 303508b051c3113b66c6d70fb68f3010cbc46595dd8d8057e6d942de0da913a9h

Уведомление 03 производитy координата 303508b051c3113b66c6d70fb68f3010cbc46595dd8d8057e6d942de0da913a9h вместо 02 и cfcaf74eae3ceec5993928f04970cfef343b9a6b22727fa81926bd21f256ec56h.

...