赞
踩
RSA算法密钥长度的选择
RSA算法密钥长度的选取直接关系到加解密、签名验签的安全强度和运算速度。密钥的长度实际上是指公钥模N的长度(以Bit为单位),理论上来讲N越大,安全强度越高,算法运算速度越慢。因此,RSA算法密钥长度要结合项目的实际情况来选取,以求在安全性和运算性能之间取得平衡点。例如:有些产品的应用场景要求RSA加解密必须具有很高的实时性,比依托于强大CPU性能,不需要过多考虑RSA运算速度,还有些终端产品如公交刷卡机。如果RSA运算时间过长会导致刷卡交易整体时间延长,用户刷卡体验变差,上下车客流速度变慢,因此这种应用场景不适合选取过高的公钥模长。有些PC端产品,虽然MCU运算性能偏弱,但是增加了一颗带有协处理器的加密芯片来协助MCU完成运算,这样就能很好的实现运算加速,因此不需要过多担心速度问题,可以选取较高的公钥模长来提升系统安全强度。总体来说,现在市场上RSA公钥长度应用较多的是1024位和2048位,简称RSA1204算法和RSA2048算法。
RSA几个特性如下:
(1)密钥长度增长一倍,公钥操作所需时间增加约4倍,私钥操作所需时间增加约8倍,公私钥生成时间约增长16倍。
(2) 一次能加密的密文长度与公钥长度成正比,如RSA1024,一次能加密的内容长度为 1024/8 = 128byte(包含填充字节)。所以非对称加密一般都用于加密对称加密算法的密钥,而不是直接加密内容。
(3) 加密后密文的长度为公钥的长度,例如公钥长度为1024Bit(128Byte),最后生成的密文固定为 1024Bit(128Byte)。
使用帮助:
-h 查看帮助
-s
-o
-v 版本号 例: 0.0.1.0
-t 类型 例: 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
(
K
B
U
I
L
D
O
U
T
P
U
T
)
/
(KBUILD_OUTPUT)/
(KBUILDOUTPUT)/(T).bin -o $(KBUILD_OUTPUT) -v $(REVISION_INFO_S) -t $(REVISION_TYPE_S)
第二种,exe运行(无需环境)。
路径:xBox/Makefile
IMAGE_DFU:
(
I
M
A
G
E
B
I
N
)
@
(IMAGE_BIN) @
(IMAGEBIN)@(PWD)/tools/xBin2Dfu/xBin2Dfu.exe -s
(
K
B
U
I
L
D
O
U
T
P
U
T
)
/
(KBUILD_OUTPUT)/
(KBUILDOUTPUT)/(T).bin -o $(KBUILD_OUTPUT) -v $(REVISION_INFO_S) -t $(REVISION_TYPE_S)
使用脚本时,需要安装第三方库
环境: python 3.6.8
编译: .\make.bat main.py
安装命令: pip install xxx
依赖:rsa, 其余根据提示安装。
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")
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。