Как сжать или закодировать открытый ключ эллиптической кривой и передать его по сети?

Я разрабатываю распределенную цифровую подпись, которая подписывает документ и отправляет его по сети на сервер приложений. Для этого я использую программирование сокетов на Java. Я думаю, что открытый ключ должен быть закодирован или сжат, то есть значения x и y каким-то образом представлены как единые двоичные данные и сохранены в общедоступном реестре или сети, но я не знаю, как это сделать в java.

        // I have class like this 
           public class CryptoSystem{                  

               EllipticCurve ec = new EllipticCurve(new P192());

               //-------------------
               //--------------------

               public ECKeyPair generatekeyPair()
               {
                  return ECKeyPair(ec);

               }


            }    
        // i don't think i have problem in the above


    CryptoSystem crypto = new CryptoSystem();
    ECKeyPair keyPair = crypto.generateKeyPair();
    BigInteger prvKey = keyPair.getPrivateKey();
    ECPoint pubKey = keyPair.getPublicKey();
     // recommend me here to  compress and send it  the public key to a shared network.

Я хочу знать, как кодировать открытый ключ и параметры домена, чтобы верификатор подписи декодировал его для использования. Потому что, когда вы отправляете их по сети верификатору, вам придется кодировать их как однобайтовый массив .i я не использую Bouncy Castle Provider. Вся реализация алгоритма ECDSA - мой проект


person Clickmit Wg    schedule 07.06.2012    source источник
comment
Как вы их представляете в памяти? Это просто большие целые числа, их сериализация должна быть простой.   -  person CodesInChaos    schedule 07.06.2012
comment
Вы хотите использовать точечное сжатие? Это метод, при котором вы сериализуете только координату x и знак координаты y, а затем используете уравнение кривой для восстановления координаты y.   -  person CodesInChaos    schedule 07.06.2012
comment
да, но в дополнение к сжатию я хочу поместить сжатый открытый ключ в общий сетевой реестр, чтобы два или более сервера приложений использовали его для проверки подписи.   -  person Clickmit Wg    schedule 07.06.2012
comment
Какой API вы используете? Например. каково имя класса FQN для экземпляра криптографии и класса ECKeyPair? Хотя, как было сказано, вы можете получить значения BigInteger и сохранить их как есть.   -  person Eugene Kuleshov    schedule 07.06.2012
comment
класс для экземпляра криптографии - мой собственный.   -  person Clickmit Wg    schedule 08.06.2012
comment
см. недавно отредактированный код выше   -  person Clickmit Wg    schedule 08.06.2012


Ответы (2)


Точки эллиптических кривых почти всегда кодируются с использованием кодировки, указанной в X9.62.

Использование точечного сжатия необязательно. Кодирование с использованием точечного сжатия тривиально, но для декодирования сжатой точки требуется немного больше работы, поэтому, если вам действительно не нужно сохранять лишние байты, я бы не стал беспокоиться. Дайте мне знать, если вам это нужно, и я добавлю детали. Вы можете распознать точки в кодировке X9.62 со сжатием точки по первому байту, который будет 0x02 или 0x03.

Кодирование без точечного сжатия действительно просто: начните с 0x04 (чтобы указать отсутствие сжатия). Затем следует сначала координата x, затем координата y, обе слева заполнены нулями до размера в байтах поля:

int qLength = (q.bitLength()+7)/8;
byte[] xArr = toUnsignedByteArray(x);
byte[] yArr = toUnsignedByteArray(y);
byte[] res = new byte[1+2*qLength];
res[0] = 0x04;
System.arraycopy(xArr, 0, res, qLength - xArr.length, xArr.length);
System.arraycopy(yArr, 0, res, 2* qLength - yArr.length, nLength);

Расшифровка, конечно, тривиальная.

person Rasmus Faber    schedule 07.06.2012
comment
спасибо, я понимаю твой ответ. где я должен сохранить открытый ключ, чтобы его могли использовать один или несколько серверов приложений в удаленной области? - person Clickmit Wg; 08.06.2012
comment
как насчет параметров домена (q, a, b, G, n, h), как они передаются приложениям удаленной проверки подписи, потому что в качестве знака u есть динамически выбираемые эллиптические кривые. p-192, p-224, ...., p-512 рекомендуемые параметры области эллиптической кривой - person Clickmit Wg; 08.06.2012
comment
@Clickmit: я предполагаю, что у вас были статические параметры домена и вы просто жестко запрограммировали их на каждом конце. Если у вас есть небольшой список поддерживаемых кривых, я бы сделал что-то вроде добавления целого числа, указывающего, какую кривую вы используете. Если вы хотите кодировать все параметры домена, для этого тоже есть стандарты (найдите структуру ECDomainParameters ASN.1), но я думаю, вам следует найти для этого кодировщик ASN.1 DER. Ручное кодирование кодирования такой структуры нетривиально. - person Rasmus Faber; 08.06.2012
comment
Можно ли добавить процедуру для работы со сжатыми ключами? Спасибо - person CarlosRos; 08.09.2017
comment
не могли бы вы помочь с расшифровкой сжатой точки? - @RasmusFaber ссылка - person user2748161; 16.11.2020

Я почти уверен, что реализация BC использует кодировку X9.63, так что это будут скорее стандартизованные кодировки. Вам нужно будет добавить поставщика Bouncy Castle в JRE (Security.addProvider(new BouncyCastleProvider()), см. Документацию bouncy.

public static void showECKeyEncodings() {

    try {
        KeyPairGenerator kp = KeyPairGenerator.getInstance("ECDSA");
        ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable
                .getParameterSpec("prime192v1");
        kp.initialize(ecSpec);
        KeyPair keyPair = kp.generateKeyPair();

        PrivateKey privKey = keyPair.getPrivate();
        byte[] encodedPrivKey = privKey.getEncoded();
        System.out.println(toHex(encodedPrivKey));

        PublicKey pubKey = keyPair.getPublic();
        byte[] encodedPubKey = pubKey.getEncoded();
        System.out.println(toHex(encodedPubKey));

        KeyFactory kf = KeyFactory.getInstance("ECDSA");
        PublicKey pubKey2 = kf.generatePublic(new X509EncodedKeySpec(encodedPubKey));
        if (Arrays.equals(pubKey2.getEncoded(), encodedPubKey)) {
            System.out.println("That worked for the public key");
        }

        PrivateKey privKey2 = kf.generatePrivate(new PKCS8EncodedKeySpec(encodedPrivKey));
        if (Arrays.equals(privKey2.getEncoded(), encodedPrivKey)) {
            System.out.println("That worked for the private key");
        }

    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(e);
    }

}
person Maarten Bodewes    schedule 08.06.2012
comment
Я не использую повторно реализацию ECDSA над Bouncy Castle. Я реализую самостоятельно, но у меня возникли трудности с кодированием параметров домена, чтобы отправить их по сети в виде однобайтового массива, и они должны быть декодированы на стороне верификатора - person Clickmit Wg; 09.06.2012
comment
В этом случае я бы умолял вас взглянуть на очень разрешительную базовую реализацию Bouncy Castle, если не для копирования, то просто взглянуть на стандартную кодировку X9.62 параметров домена. BSI TR-03111 также имеет (более простой) метод кодирования параметров домена. - person Maarten Bodewes; 10.06.2012
comment
Этот пример, похоже, также работает в JDK 1.8, за исключением того, что вам нужно передать EC в KeyPairGenerator и KeyFactory. - person kravietz; 18.03.2016
comment
Также в JDK 1.8 необходимо заменить prime192v1 на secp192r1. - person kravietz; 18.03.2016
comment
@kravietz Да, и вам нужно использовать ECGenParameterSpec также для генератора пары ключей. Я отредактирую ответ, чтобы отразить эти изменения как можно скорее. Как ни странно, кодировка BC и Oracle отличается; закрытый ключ содержит (необязательный) открытый ключ в случае кодировки Oracles ASN.1, и его нет для BC. Так что оба правильные и совместимые, они просто немного отличаются. - person Maarten Bodewes; 18.03.2016
comment
@ K.Os Пожалуйста, не делай этого. ТАК - это командная работа, я не даю здесь личных советов. - person Maarten Bodewes; 05.12.2018