作者:Peter Zhou,AMD工程师;文章来源:AMD开发者社区
目前在Versal上运行椭圆曲线数字签名验证的example 已经有了,请见如下源码:
有时候,可能会用openssl 来验证versal上椭圆曲线的数字签名,可能是为了检验versal上椭圆曲线算法的正确性。但是由于方法不得当,会导致验证不通过,或者走入一些误区,为此,我们写下这篇文章帮助大家注意这些问题。
这个example的流程是这样的:首先,根据私钥来生成一个key,然后再用私钥和临时私钥对一段Hash值进行数字签名,生成的数字签名由R和S这两个部分来组成,然后是验证key,并用Hash值和key来验证之前的数字签名。最后example在versal上是验证成功的。
下面是在openssl下进行椭圆曲线数字签名验证的流程:
/*generate private key with openssl*/
openssl ecparam -genkey -name P-384 -out privkey.pem
/*extract public key from the generated private key*/
openssl ec -in privkey.pem -outform PEM -pubout -out pubkey.pem
/*decode private key from PEM to DER*/
openssl ec -in privkey.pem -outform DER -out privkey.der
/*print private key byte arrary and public key byte array, copy private key byte array to “D” array in AMD API example, run the example and confirm the generated public key is same with openssl*/
openssl ec -text -in privkey.pem
/*copy the hash byte array from AMD API example to a bin file “hash.bin”, sign this file with openssl private key*/
openssl dgst -sha3-384 -sign privkey.der -out sign.sha3-384 hash.bin
/*verify the generated signature with openssl public key*/
openssl dgst -sha3-384 -verify pubkey.pem -signature sign.sha3-384 hash.bin
/*print R/S from the generated signature with openssl, copy the R/S to AMD API example and verify it in example*/
openssl asn1parse -inform der -in sign.sha3-384
解决这个问题的时候,需要注意大小端的问题,openssl用的是大端,而versal上用的是小端。另外还要注意验证程序的流程问题。
下面有一个example用openssl创建一个签名,并用上文所说的xilsecure_versal_ecdsa_server_example.c来验证这个签名,这个example用到了一个Makefile内容如下:
default:
openssl ecparam -genkey -name P-384 -out privkey.pem
openssl ec -text -in privkey.pem > privkey.txt
echo "abc" | head -c 3 > abc.txt
openssl dgst -sha3-384 -sign privkey.pem -out abc.txt.sig abc.txt
openssl dgst -sha3-384 -binary -out abc.txt.hash abc.txt
openssl_to_c.py
用openssl指令生成privkey,创建了一个文件abc.txt,文件中包含abc三个字母。然后用openssl指令对abc.txt文件进行签名,并生成hash。
然后执行一个python脚本,该脚本用于将上述生成的hash转化成c语言数组,以便于copy到xilsecure_versal_ecdsa_server_example.c来验证这个签名。
上述python脚本内容如下:
#!/usr/bin/python3
import numpy as np
def get_D():
with open("privkey.txt", "r") as f:
while True:
line = f.readline().strip()
if line == "priv:":
D = [ ]
for i in range(4):
line = f.readline().strip()
for x in line.split(':'):
if x != '':
D.append(int(x,16))
break
return D
def get_H():
with open("abc.txt.hash", "rb") as f:
data = np.fromfile("abc.txt.hash", dtype=np.ubyte)
return list(data)
def get_RS():
with open("abc.txt.sig", "rb") as f:
data = np.fromfile("abc.txt.sig", dtype=np.ubyte)
r_length = data[3]
r_start = 4 + (r_length-48)
r = data[r_start:r_start+48]
s_length = data[r_start+49]
s_start = r_start+50
s = data[s_start:s_start+48]
return list(r), list(s)
def print_array(name, array):
print(f'const u8 {name}[] = {{')
for i in range(48):
if (i % 8 == 0):
print("\t",end='')
print(f'0x{array[47-i]:02X}, ', end='')
if (i % 8 == 7):
print("")
print(f'}};')
print(f'')
D = get_D()
H = get_H()
R, S = get_RS()
print_array('Hash', H)
print_array('D', D)
print_array('R', R)
print_array('S', S)
需要注意的是,每次运行这个Makefile的时候,生成的key和签名可能都不一样,这是因为是openssl随机生成的。
另外,xilsecure_versal_ecdsa_server_example.c中没有展示整个签名的过程,openssl dgst指令(1) hashing “abc”, (2) performing ECC math on the resulting hash. 而ecdsa example 仅仅展示了第二步,所以您需要用xilsecure SHA3的函数去执行第一步,即hashing “abc”。