Создайте файл PEM, используя координаты открытого ключа ec - PullRequest
0 голосов
/ 26 июня 2019

Я пытаюсь создать эллиптический открытый ключ, вычисляя точку на кривой из заданного числа (мой закрытый ключ), поэтому у меня есть координаты (x,y) точки эллиптической кривой

Я получаю координаты по

myPublicKeyCoordinates = myPrivateKeyValue * GPointOnCurve

Как мне создать файл PEM (или DER) для моего открытого ключа?

Мне плевать на язык (java, python, javascript, ...)
потому что я хочу знать, как создать файл (даже если я пишу каждый байт ...)

1 Ответ

2 голосов
/ 28 июня 2019

Предполагая, что вы уже знаете о ITU-T X.680-201508 (язык ASN.1) и ITU-T X.690-201508 (BER (и CER) ) и кодировки DER для данных ASN.1), основным определяющим документом для ключей эллиптических кривых и их представлением является https://www.secg.org/sec1-v2.pdf из Группы по стандартизации для эффективной криптографии (не Комиссия США по секьюриту и обмену).

Раздел C.3 (Синтаксис для открытых ключей эллиптической кривой) говорит, что общим транспортным контейнером для открытого ключа EC является структура X.509 SubjectPublicKeyInfo:

SubjectPublicKeyInfo ::= SEQUENCE {
    algorithm AlgorithmIdentifier {{ECPKAlgorithms}} (WITH COMPONENTS
        {algorithm, parameters}) ,
    subjectPublicKey BIT STRING
}

Возможные "алгоритмы" (что в действительности означает ключевые типы кодирования) - это открытый набор

ECPKAlgorithms ALGORITHM ::= {
    ecPublicKeyType |
    ecPublicKeyTypeRestricted |
    ecPublicKeyTypeSupplemented |
    {OID ecdh PARMS ECDomainParameters {{SECGCurveNames}}} |
    {OID ecmqv PARMS ECDomainParameters {{SECGCurveNames}}},
    ...
}

ecPublicKeyType ALGORITHM ::= {
    OID id-ecPublicKey PARMS ECDomainParameters {{SECGCurveNames}}
}

...

ECDomainParameters получен из C.2:

ECDomainParameters{ECDOMAIN:IOSet} ::= CHOICE {
    specified SpecifiedECDomain,
    named ECDOMAIN.&id({IOSet}),
    implicitCA NULL
}

C.3 упоминает о примерно в середине

Открытый ключ эллиптической кривой (значение типа ECPoint, являющееся строкой OCTET) сопоставляется с subjectPublicKey (значением, закодированным как тип BIT STRING) следующим образом: старший значащий бит значения OCTET STRING становится старший значащий бит значения BIT STRING и т. д. с последовательными битами до тех пор, пока младший значащий бит OCTET STRING не станет младшим значащим битом BIT STRING.

Итак, мы ищем назад и находим

Сама точка эллиптической кривой представлена ​​следующим типом

ECPoint ::= OCTET STRING

, значение которого представляет собой строку октетов, полученную из процедур преобразования, приведенных в разделе 2.3.3.

2.3.3 (Преобразование эллиптической кривой в точку-октет-строку) содержит много слов, но наилучший поддерживаемый формат не использует сжатие точек (и P! = Точка на бесконечности)

  1. Если P = (xP, yP)! = O и сжатие точек не используется, выполните следующие действия:

3,1. Преобразовать элемент поля xP в строку октетов X длиной (log2 q) / 8 октетов, используя процедуру преобразования, указанную в разделе 2.3.5.

3,2. Преобразуйте элемент поля yP в строку октетов Y длиной (log2 q) / 8 октетов, используя процедуру преобразования, указанную в разделе 2.3.5.

3,3. Выход М = 04 16 || X || Y.

2.3.5 - это много слов для "байтового порядка с порядком байтов, длина которого достаточно велика, чтобы в нем содержались все значения в поле" (иначе "оставить в начальных нулях").

Так что теперь мы вечеринка.

С учетом ссылочного ключа FIPS 186-3 на secp256r1 (d=70A12C2DB16845ED56FF68CFC21A472B3F04D7D6851BF6349F2D7D5B3452B38A),

Q является (8101ECE47464A6EAD70CF69A6E2BD3D88691A3262D22CBA4F7635EAFF26680A8, D8A12BA61D599235F67D9CB4D58F1783D3CA43E78F0A5ABAA624079936C0C3A9)

И открытый ключ DER выглядит как

// SubjectPublicKeyInfo
30 XA
   // AlgorithmIdentifier
   30 XB
      // AlgorithmIdentifier.id (id-ecPublicKey (1.2.840.10045.2.1))
      06 07 2A 86 48 CE 3D 02 01
      // AlgorithmIdentifier.parameters, using the named curve id (1.2.840.10045.3.1.7)
      06 08 2A 86 48 CE 3D 03 01 07
   // SubjectPublicKeyInfo.subjectPublicKey
   03 XC 00
      // Uncompressed public key
      04
      // Q.X
      81 01 EC E4 74 64 A6 EA D7 0C F6 9A 6E 2B D3 D8
      86 91 A3 26 2D 22 CB A4 F7 63 5E AF F2 66 80 A8
      // Q.Y
      D8 A1 2B A6 1D 59 92 35 F6 7D 9C B4 D5 8F 17 83
      D3 CA 43 E7 8F 0A 5A BA A6 24 07 99 36 C0 C3 A9

Подсчитайте все байты для XA, XB и XC:

XC = 32 (Q.X) + 32 (Q.Y) + 1 (0x04) + 1 (0x00 для неиспользованных битов) = 66 = 0x42

XB = 19 = 0x13

Тогда XA равно 66 + 19 + 2 (байты тега) + 2 (байты длины) = 89 = 0x59

(И, конечно, если бы любое из наших значений длины превышало 0x7F, нам пришлось бы их правильно кодировать)

Так что теперь мы остались с

30 59 30 13 06 07 2A 86 48 CE 3D 02 01 06 08 2A
86 48 CE 3D 03 01 07 03 42 00 04 81 01 EC E4 74
64 A6 EA D7 0C F6 9A 6E 2B D3 D8 86 91 A3 26 2D
22 CB A4 F7 63 5E AF F2 66 80 A8 D8 A1 2B A6 1D
59 92 35 F6 7D 9C B4 D5 8F 17 83 D3 CA 43 E7 8F
0A 5A BA A6 24 07 99 36 C0 C3 A9

И мы проверяем:

$ xxd -r -p | openssl ec -text -noout -inform der -pubin
read EC key
<paste, then hit CTRL+D>
30 59 30 13 06 07 2A 86 48 CE 3D 02 01 06 08 2A
86 48 CE 3D 03 01 07 03 42 00 04 81 01 EC E4 74
64 A6 EA D7 0C F6 9A 6E 2B D3 D8 86 91 A3 26 2D
22 CB A4 F7 63 5E AF F2 66 80 A8 D8 A1 2B A6 1D
59 92 35 F6 7D 9C B4 D5 8F 17 83 D3 CA 43 E7 8F
0A 5A BA A6 24 07 99 36 C0 C3 A9
Private-Key: (256 bit)
pub:
    04:81:01:ec:e4:74:64:a6:ea:d7:0c:f6:9a:6e:2b:
    d3:d8:86:91:a3:26:2d:22:cb:a4:f7:63:5e:af:f2:
    66:80:a8:d8:a1:2b:a6:1d:59:92:35:f6:7d:9c:b4:
    d5:8f:17:83:d3:ca:43:e7:8f:0a:5a:ba:a6:24:07:
    99:36:c0:c3:a9
ASN1 OID: prime256v1
NIST CURVE: P-256

Печать его как «Закрытый ключ: (256-битный)» - это всего лишь ошибка / изюминка инструмента, там нет закрытого ключа.

Сложнее для заданных кривых параметров, но они плохо взаимодействуют (https://tools.ietf.org/html/rfc5480#section-2.1.1 говорит, что соответствующий CA НЕ ДОЛЖЕН использовать форму указанного параметра или неявную форму, но ДОЛЖЕН использовать именованную форму) .

...