0%

ECDSA

参考:Elliptic Curve Digital Signature Algorithm

ECDSA,椭圆曲线数字签名算法,也即使用了椭圆曲线密码学数字签名算法

wikipeida 的定义如下:

In cryptography, the Elliptic Curve Digital Signature Algorithm (ECDSA) offers a variant of the Digital Signature Algorithm (DSA) which uses elliptic curve cryptography.

可以把 ECDSA 可以拆解成两部分:ECC 和 DSA。

ECDSA

Fundamentals

The Fundamentals of an ECDSA Authentication System - ==强力推荐!==

虽然椭圆曲线有无数个,但只有很小一部分适合 ECC,NIST推荐使用这些椭圆曲线并将其写入标准,每个曲线都有一个名称并由一个参数集来定义,参数集由 Prime Modulus p, the Prime Order n, the Coefficient a, the Coefficient b, and the x and y coordinates of the Base Point G(x,y) on the curve 组成。如 Curve P-192 的参数如下:

私钥是个随机数,公钥由私钥和椭圆曲线产生,公钥由 x 和 y 值组成:

数字签名由私钥,椭圆曲线,随机数和消息的摘要产生:

验证结果由公钥,椭圆曲线,数字签名和消息的摘要产生:

Digital signature

参考:Can I extract R and S from an ECDSA signature in bit form, and vica versa?

ECDSA 数字签名由 r 和 s 组成,r 和 s 的长度和私钥 d 长度相同。

实际使用的 ECDSA 一般是 DER 格式的文件,除了 r 和 s 外还有其他信息。

以一个例子来说明 DER 格式 ECDSA 数字签名的格式:

1
2
3
4
5
6
7
8
0x30, 0x45, // Sequence of length 69 to follow
0x02, 0x21, // Integer of length 33 to follow
0x00, // If first byte of the 32 byte integer is >0x7F, an extra 0x00 byte is prepended
// Here come the 32 bytes (r):
0xC5, 0x79, 0xA7, 0xB6, 0x01, 0xBF, 0x5D, 0x69, 0x93, 0x50, 0x58, 0x02, 0xE5, 0x8C, 0xFA, 0x61, 0x2F, 0x7C, 0x72, 0xA5, 0x47, 0xEC, 0x6E, 0x2B, 0x72, 0x88, 0xDE, 0x5C, 0xC7, 0x10, 0x1D, 0xE8,
0x02, 0x20, // Integer of length 32 to follow
// Here come the 32 bytes (s):
0x1D, 0xF6, 0x15, 0xA8, 0x9B, 0xC8, 0x41, 0x89, 0x0F, 0x59, 0xEF, 0x3F, 0x04, 0x5D, 0x52, 0x41, 0xAE, 0xB7, 0x95, 0xE2, 0xC6, 0x4B, 0xE3, 0xA5, 0xD1, 0x85, 0xB8, 0x8F, 0x95, 0x4E, 0xB4, 0x01,

0x30 代表着下面是个 Sequence,长度为 0x45,0x02 代表下面是个 Integer,长度是 0x21,然后是另一个 Integer,长度是 0x20。

为什么第一个 integer 的长度是 0x21 呢,因为 integer 是带符号类型的,所以如果第一个字节的 MSB 是 1( > 0x7F),就要额外在前面补个 0x00。

工具

参考:

https://github.com/warner/python-ecdsa

openssl 提供了 ECDSA 的一些命令。

生成 EC 私钥

1
openssl ecparam -name secp224r1 -genkey -out sk.pem

https://www.openssl.org/docs/manmaster/man1/ecparam.html

其中,-name secp2241r1 是椭圆曲线参数,使用 openssl ecparam -list_curves 可以查看所有的椭圆曲线参数。

从 EC 私钥中提取公钥

1
openssl ec -in sk.pem -pubout -out vk.pem

https://www.openssl.org/docs/manmaster/man1/ec.html

签名

1
openssl dgst -sha256 -sign sk.pem -out data.sig data

https://www.openssl.org/docs/manmaster/man1/dgst.html

其中,-sha256 是消息摘要算法。

验签

1
openssl dgst -sha256 -verify vk.pem -signature data.sig data

从证书中提取公钥

1
openssl x509 -in cert.pem  -noout -pubkey > vk.pem

https://www.cnblogs.com/pixy/p/4722381.html

查看私钥

1
openssl ec -in sk.pem -text -noout

查看公钥

1
openssl ec -in vk.pem -pubin -text -noout

SHA256 计算

1
openssl dgst -sha256 file

https://www.cnblogs.com/gordon0918/p/5382541.html

由 R 和 S 生成 .DER 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#! /usr/bin/env python
# Author : Snow Yang

import struct, sys

def print_usage():
print ""
print "Usage:"
print sys.argv[0]
print " <r> <s>"
sys.stdout.flush()

def main():
if len(sys.argv) != 3 or len(sys.argv[1]) != 64 or len(sys.argv[2]) != 64:
print_usage()
sys.exit(2)

r = sys.argv[1]
s = sys.argv[2]

try:
r = r.decode('hex')
s = s.decode('hex')
except:
print_usage()
sys.exit(2)

int_len_r = 0x20
int_len_s = 0x20
if r[0] > '\x7F':
int_len_r += 1
if s[0] > '\x7F':
int_len_s += 1
seq_len = 0x04 + int_len_r + int_len_s

with open('sig.der', 'wb') as f:
f.write('\x30')
f.write(struct.pack('<B', seq_len))

f.write('\x02')
f.write(struct.pack('<B', int_len_r))
if int_len_r > 0x20:
f.write('\x00')
f.write(r)

f.write('\x02')
f.write(struct.pack('<B', int_len_s))
if int_len_s > 0x20:
f.write('\x00')
f.write(s)

if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
pass
坚持原创技术分享,您的支持将鼓励我继续创作!