我尝试通过根据给定数字(我的私钥)计算曲线上的点来创建椭圆形公钥,因此我具有椭圆形曲线点的坐标(x,y)
我的坐标是
myPublicKeyCoordinates = myPrivateKeyValue * GPointOnCurve
如何为我的公钥构建PEM
(或DER
)文件?
我不在乎语言(java, python, javascript, ...
)
因为我想知道如何构建文件(即使我写了每个字节...)
答案 0 :(得分:2)
假设您已经了解ITU-T X.680-201508(ASN.1语言)和ITU-T X.690-201508(ASN.1数据的BER(和CER)和DER编码),这是椭圆曲线的主要定义文件密钥及其表示法是有效密码学标准组(而非美国证券交易委员会)的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 STRING)被映射到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。使用第2.3.5节中指定的转换例程,将字段元素xP转换为长度为(log2 q)/ 8个八位位组的八位位组字符串X。
3.2。使用第2.3.5节中指定的转换例程,将字段元素yP转换为长度为(log2 q)/ 8个八位位组的八位位组字符串。
3.3。输出M = 04 16 || X ||是的。
2.3.5是“大尾数字节顺序,其长度足以容纳字段中的所有值”(也称为“留在前导零”中)的全部单词。
所以我们现在聚会。
给出secp256r1(d=70A12C2DB16845ED56FF68CFC21A472B3F04D7D6851BF6349F2D7D5B3452B38A
)上的FIPS 186-3参考密钥,
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
将其打印为“ Private-Key:(256位)”只是该工具的错误/怪癖,那里没有私钥。
对于指定的参数曲线来说,事情要难一些,但是它们之间的互操作性不好(https://tools.ietf.org/html/rfc5480#section-2.1.1说,合格的CA一定不要使用指定的参数形式或隐式形式,而必须使用命名形式)。