Предполагая, что вы уже знаете о 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! = Точка на бесконечности)
- Если 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 НЕ ДОЛЖЕН использовать форму указанного параметра или неявную форму, но ДОЛЖЕН использовать именованную форму) .