首页 > 编程语言 >[python] bin转dfu 脚本 RSA2048 签名 解密 公钥 私钥

[python] bin转dfu 脚本 RSA2048 签名 解密 公钥 私钥

时间:2022-10-31 23:01:55浏览次数:49  
标签:bin 公钥 私钥 self rsa print path privkey out


/lib/

import hashlib
import os
import sys
import time
from datetime import datetime

import rsa


class my_sign():

pubkey = ""
privkey = ""

def __init__(self, path):
self.py_path = path
self.pubkey_path = self.py_path + '\\key\\public.pem'
self.privkey_path = self.py_path + '\\key\\private.pem'
self.keys_path = self.py_path + '\\key\\keys.h'
self.read_key()
rsa.key.find_p_q = self.find_p_q # 替换库函数

# 重写RSA库,使得秘钥长度为256或512
def find_p_q(self, nbits, getprime_func, accurate):
total_bits = nbits * 2
shift = 0 # 取消偏移,使长度为256
pbits = nbits + shift
qbits = nbits - shift
# Choose the two initial primes
p = getprime_func(pbits)
q = getprime_func(qbits)

def is_acceptable(p: int, q: int):
if p == q:
return False

if not accurate:
return True

# Make sure we have just the right amount of bits
found_size = rsa.common.bit_size(p * q)
return total_bits == found_size

# Keep choosing other primes until they match our requirements.
change_p = False
while not is_acceptable(p, q):
# Change p on one iteration and q on the other
if change_p:
p = getprime_func(pbits)
else:
q = getprime_func(qbits)

change_p = not change_p

# We want p > q as described on
return max(p, q), min(p, q)

def get_data(self, path):
data = []
if(path.find(".bin") > -1):
with open(path, 'rb') as f:
data = f.read()
f.close()
return data

def hex_output(self, bytes_s):
i = 0
s = ""
for data in bytes_s:
if(i >= 16):
i = 0
s = s[:-1] + "\n"
i = i + 1
s = s + '0x' + ('%02X' % data) + ", "
return s[:-2]

def buff_output(self, input_s, buf_head):
input_s = input_s.replace("\n", "\n ")
input_s = " " + input_s
input_s = "const static unsigned char " + \
buf_head + "[] = {\n" + input_s + "};"

return input_s

def get_out_path(self, src_path, out_path):
if out_path is not None:
file_path = out_path
# print("file_path", file_path)
if((file_path.endswith('\\') is not True) and file_path.find('\\') > 0):
file_path = file_path + '\\'
if((file_path.endswith('/') is not True) and file_path.find('/') > 0):
file_path = file_path + '/'
filename = file_path + os.path.split(src_path)[1]
else:
filename = src_path
filename = filename.replace(".bin", ".dfu")
return filename

def get_head_info(self, md5_val, file_size, version, type):
hrad_info = []
file_size = file_size.to_bytes(4, byteorder='big', signed=False)
# print(file_size)
version = version.split(".")
version = list(map(int, version))
version = bytes(version)
if(type == "factory"):
type = bytes([0])
elif(type == "engineer"):
type = bytes([1])
elif(type == "user"):
type = bytes([2])
else:
type = bytes([255])
# print(type, 16 - len(file_size + version) - 1)
null_bytes = bytes(16 - len(file_size + version) - 1)
# print(null_bytes)

# 读取RSA钥匙
if(self.privkey or self.privkey):
self.read_key()

# 用RSA2048签名MD5(私钥签名)
crypto = self.privkey_sign(md5_val)
if(len(crypto) < 1):
print("私钥签名失败")
hrad_info = crypto + file_size + version + type + null_bytes
return hrad_info

# md5采用加盐方式签名
def md5_opt(self, data, salt):
obj = hashlib.md5(salt.encode('utf-8'))
obj.update(data)
print("MD5:", obj.digest().hex())
return obj.digest()

# md5常规签名
def md5_opt1(self, data):
data_sha = hashlib.md5(data).digest()
print("MD5:", data_sha.hex())
return data_sha

# 创建一个新RSA钥匙
def create_key(self):
start = datetime.now()
try:
try:
# 备份当前秘钥
if os.path.exists(self.pubkey_path) == True:
os.rename(self.pubkey_path, self.pubkey_path + '.' +
str(int(time.time())) + ".bak")

if os.path.exists(self.privkey_path) == True:
os.rename(self.privkey_path, self.privkey_path + '.' +
str(int(time.time())) + ".bak")

if os.path.exists(self.keys_path) == True:
os.rename(self.keys_path, self.keys_path + '.' +
str(int(time.time())) + ".bak")
except Exception:
print("备份秘钥失败!")
print(self.pubkey_path)
print(self.privkey_path)
print(self.keys_path)
try:
# 生成密钥
(self.pubkey, self.privkey) = rsa.newkeys(2048)
except Exception:
print("生成秘钥失败!")

# 保存密钥
with open(self.pubkey_path, 'wb') as f:
f.write(self.pubkey.save_pkcs1())
f.close()

with open(self.privkey_path, 'wb') as f:
f.write(self.privkey.save_pkcs1())
f.close()
try:
self.generateh_h_file()
except Exception:
print("生成H文件秘钥失败!")

except Exception:
print("秘钥创建失败!")
print("创建秘钥用时:" + str((datetime.now() - start)))

# 读取RSA钥匙
def read_key(self):
try:
with open(self.pubkey_path, 'rb') as f:
self.pubkey = rsa.PublicKey.load_pkcs1(f.read())
f.close()
except Exception:
print("公钥秘钥读取错误,可能不存在。")
try:
with open(self.privkey_path, 'rb') as f:
self.privkey = rsa.PrivateKey.load_pkcs1(f.read())
f.close()
except Exception:
print("私钥秘钥读取错误,可能不存在。")

# 查看 RSA钥匙
def show_key(self):
try:
# 读取RSA钥匙
if(self.privkey or self.privkey):
self.read_key()
print("公钥:", self.pubkey.hex())
print("私钥:", self.privkey.hex())
except Exception:
print("秘钥读取错误,可能不存在。")

# 生成秘钥H文件
def generateh_h_file(self):
out_s = "#ifndef __KEY_RAS_H__\n"
out_s = out_s + "#define __KEY_RAS_H__\r\n"
# n --> modulus rsa.
out_buff = self.hex_output(rsa.transform.int2bytes(self.privkey.n))
out_s = out_s + self.buff_output(out_buff, "key_m")
out_s = out_s + "\r\n"
# e --> public Exponent
out_buff = self.hex_output(rsa.transform.int2bytes(self.privkey.e))
out_s = out_s + self.buff_output(out_buff, "key_e")

out_s = out_s + "\r\n"
# d --> private Exponent
out_buff = self.hex_output(rsa.transform.int2bytes(self.privkey.d))
out_s = out_s + self.buff_output(out_buff, "key_ex")

out_s = out_s + "\r\n"
# p --> prime1
out_buff = self.hex_output(rsa.transform.int2bytes(self.privkey.p))
out_s = out_s + self.buff_output(out_buff, "key_p1")

out_s = out_s + "\r\n"
# q --> prime2
out_buff = self.hex_output(rsa.transform.int2bytes(self.privkey.q))
out_s = out_s + self.buff_output(out_buff, "key_p2")

out_s = out_s + "\r\n"
# exp1 --> exponent1
out_buff = self.hex_output(rsa.transform.int2bytes(self.privkey.exp1))
out_s = out_s + self.buff_output(out_buff, "key_e1")

out_s = out_s + "\r\n"
# exp2 --> exponent2
out_buff = self.hex_output(rsa.transform.int2bytes(self.privkey.exp2))
out_s = out_s + self.buff_output(out_buff, "key_e2")

out_s = out_s + "\r\n"
# coef --> coefficient
out_buff = self.hex_output(rsa.transform.int2bytes(self.privkey.coef))
out_s = out_s + self.buff_output(out_buff, "key_c")

out_s = out_s + "\r\n#endif\n"
with open(self.keys_path, 'w') as f:
f.write(out_s)
f.close()

# RSA使用私钥签名
def privkey_sign(self, data):
keylength = rsa.common.byte_size(self.privkey.n)
padded = rsa.pkcs1._pad_for_signing(data, keylength)
payload = rsa.transform.bytes2int(padded)
encrypted = self.privkey.blinded_encrypt(payload)
block = rsa.transform.int2bytes(encrypted, keylength)
return block

# RSA使用公钥解签
def pubkey_decrypt(self, data):
keylength = rsa.common.byte_size(self.pubkey.n)
encrypted = rsa.transform.bytes2int(data)
decrypted = rsa.core.decrypt_int(
encrypted, self.pubkey.e, self.pubkey.n)
text = rsa.transform.int2bytes(decrypted, keylength)
try:
if len(text) > 0:
if(text[0] == 0 and text[1] == 1):
text = text[2:]
for i in range(0, len(text)):
if(text[i] != 255):
return text[i+1:]
return 0
except Exception:
print("公钥解签失败!")

# RSA使用公钥签名
def pubkey_sign(self, data):
crypto = rsa.encrypt(data, self.pubkey)
return crypto

# RSA使用私钥钥解签
def privkey_decrypt(self, data):
message = rsa.decrypt(data, self.privkey)
return message

主程序:

import getopt
import os
import sys

from lib.mysign import my_sign


def show_help():
print("-h 查看帮助")
print("-s <path> bin文件路径 例: E:\\123.bin")
print("-o <path> dfu文件输出路径 例: D:\\")
print("-v <version num> 版本号 例: 0.0.1.0")
print("-t <type> 类型 例: factory或user或engineer")
print("-k 查看秘钥 例: ")
print("-c 创建秘钥 例: ")
print("完整例子: xxx.exe -s E:\\123.bin -o D:\\ -v 0.0.1.0 -t factory")


if __name__ == "__main__":
# print(sys.argv)
py_path = os.path.dirname(sys.argv[0])

mysign = my_sign(py_path)

sour_path = None
out_path = None
pack_version = None
pack_type = None

try:
opts, args = getopt.getopt(sys.argv[1:], '-h-s:-o:-v:-t:-k-c',
['help', 'source=', 'out=', 'version=', 'type=', 'key', 'newkey'])
except Exception:
print("参数错误!")
sys.exit()

for opt_name, opt_value in opts:
if opt_name in ('-h', '--help'):
show_help()
sys.exit()
elif(opt_name in ('-c', '--newkey')):
mysign.create_key()
elif(opt_name in ('-s', '--source')):
sour_path = opt_value
elif(opt_name in ('-o', '--out')):
out_path = opt_value
elif(opt_name in ('-v', '--version')):
pack_version = opt_value
elif(opt_name in ('-t', '--type')):
pack_type = opt_value
elif(opt_name in ('-k', '--key')):
mysign.show_key()
sys.exit()

# print(sour_path)
if sour_path is not None:
data = mysign.get_data(sour_path)
else:
sys.exit()
# print("sour_path:", sour_path)

if len(data) != 0:
size = os.path.getsize(sour_path)
md5_val = mysign.md5_opt1(data)
# 得到输出路径
out_path = mysign.get_out_path(sour_path, out_path)
print("out path:", out_path)
# 得到头信息
head_info = mysign.get_head_info(
md5_val, size, pack_version, pack_type)
# 写出dfu文件
with open(out_path, 'wb') as f:
f.write(head_info + data)
f.close()

else:
print("err: Invalid parameter")

##Compile Command

使用脚本时,需要安装第三方库
环境: python 3.6.8
编译: .\make.bat main.py
安装命令: pip install xxx
依赖:rsa, 其余根据提示安装。

使用帮助:
-h 查看帮助
-s <path> bin文件路径 例: E:\123.bin
-o <path> dfu文件输出路径 例: D:\
-v <version num> 版本号 例: 0.0.1.0
-t <type> 类型 例: factory或user或engineer
-k 查看秘钥 例:
-c 创建秘钥 例:
完整例子: xxx.exe -s E:\folk.bin -o D:\ -v 0.0.1.0 -t factory

钥匙路径:.\xBin2Dfu\key\
(生成的钥匙目录里面会含有keys.h文件,请放置指定地点使用。例:/utils/rsa/)


两种使用方式:
第一种,脚本运行。(需要python环境并安装第三方RSA库)。
路径:xBox/Makefile
使用方式:
IMAGE_DFU: $(IMAGE_BIN)
@python $(PWD)/tools/xBin2Dfu/xBin2Dfu.py -s $(KBUILD_OUTPUT)/$(T).bin -o $(KBUILD_OUTPUT) -v $(REVISION_INFO_S) -t $(REVISION_TYPE_S)

第二种,exe运行(无需环境)。
路径:xBox/Makefile
IMAGE_DFU: $(IMAGE_BIN)
@$(PWD)/tools/xBin2Dfu/xBin2Dfu.exe -s $(KBUILD_OUTPUT)/$(T).bin -o $(KBUILD_OUTPUT) -v $(REVISION_INFO_S) -t $(REVISION_TYPE_S)


标签:bin,公钥,私钥,self,rsa,print,path,privkey,out
From: https://blog.51cto.com/xuejianqiang/5811370

相关文章

  • [keil][python][单片机] keil 集成bin文件生成 boot+app合并 dfu生成
    一、首先配置keil执行工具.\file_handling.bat@L!L$K输出文件名根据自身定义参数名注释@L输出文件名(上图所示位置)!L输出文件名.axf$Kkeil路径二、编写bat脚本(此处......
  • MySQLdebug binaries
    mysql-5.7.21-winx64-debug-test.zip解压之后怎么使用啊,怎么才能用NavicatforMySQL连接,求帮忙参考教程:MySQL压缩解压包的安装配置Mysql过程怎么单步debug看图说话,第四步,传......
  • 【XSY4186】Binomial(结论,数位DP)
    题面Binomial题解设\(\operatorname{ord}(n)\)表示\(n\)分解质因数后\(p\)的幂次,那么我们就是对于每一个\(k\)要求有多少\(0\leqm\leqn\)使得\(\operatorn......
  • C++11绑定器bind及function机制
    前言之前在学muduo网络库时,看到陈硕以基于对象编程的方式,大量使用boost库中的bind和function机制,如今,这些概念都已引入至C++11,包含在头文件<functional>中。本篇文章主要......
  • 【面试题】 为什么说 bind 的实现非常考验对原型链的理解?
    前言bind的实现其实非常考验对原型链的理解。bind和apply,call是JS修改this指向的三把利器......
  • Maven Central & JCenter & Bintray
    MavenCenter是maven的权威中央仓库;JCenter,是一个代码库,相当于一个公共的存储控件,简单的来讲就是你把你写好的aar文件及一些文档描述文件之类的东西打包上传到jCenter服务器......
  • Mapreduce中Combiner的使用及误区
    问题提出: 众所周知,Hadoop框架使用Mapper将数据处理成一个<key,value>键值对,再网络节点间对其进行整理(shuffle),然后使用Reducer处理数据并进行最终输出。  在上述过程......
  • LeetCode 2458. Height of Binary Tree After Subtree Removal Queries
    原题链接在这里:https://leetcode.com/problems/height-of-binary-tree-after-subtree-removal-queries/题目:Youaregiventhe root ofa binarytree with n node......
  • 「MySQL高级篇」MySQL日志、事务原理 -- undolog、redolog、binlog、两阶段提交
    引言日志日志,在我们平时开发中主要的用途在于监控、备份,但在MySQL中,日志的功能远远不止这些,分别有用于记录的慢查询日志,回滚版本的undolog,宕机恢复的redolog、全量备份的bin......
  • bind实现
    Function.prototype.myBind=function(context){//if(!(typeofthis=='function')){//1.判断调用者是否为一个函数判thrownewError('调......