20221320冯泰瑞-实验四密码模块应用实践过程记录

news/2025/3/12 23:25:53/文章来源:https://www.cnblogs.com/feng-tairui/p/18692753

20221320冯泰瑞-实验四密码模块应用实践过程记录

实践要求

  1. 完成电子公文交换系统,系统功能,(15 分)
mindmaproot((电子公文系统))发文公文起草公文查看发文审核(审核员)公文发送公文查询收文公文签收公文查看公文处理公文查询系统管理组织单位用户管理操作员(科员)审核员(科长,处长):至少有一级审核功能系统管理员:至少管理用户账号,组织单位功能安全保密管理员:至少有权限管理功能,密钥管理功能安全审计员:至少有日志查看功能权限设置(安全保密管理员)系统日志数据字典(选做)

系统功能

  • 总体要求
    • 项目类型必须是B/S或C/S架构
    • 项目程序设计语言可以是C,Python,Rust等
  1. 三员制度是指将系统管理员、安全保密管理员和安全审计员三个角色分离,分别负责系统运行、安全保密和安全管理,相互制约,共同保障信息系统安全。三员职责
  • 系统管理员
    • 负责信息系统的日常维护、故障处理和升级更新。
    • 确保系统正常运行,对系统资源进行合理分配。
    • 负责用户账号的创建、修改和删除。
    • 定期备份重要数据,确保数据安全。
  • 安全保密管理员
    • 负责制定和实施安全保密策略,确保信息系统安全。
    • 对用户进行安全意识培训,提高用户安全防范能力。
    • 监控网络安全状况,发现异常情况及时处理。
    • 负责信息系统安全事件的应急响应和处理。
  • 安全审计员
    • 负责对信息系统进行安全审计,评估安全风险。
    • 监督系统管理员和安全保密管理员的工作,确保其履行职责。
    • 对信息系统安全事件进行调查,提出整改建议。
  1. 黄金法则(5 分)
    • 身份鉴别:口令不能存,数据库要保存加盐的SM3Hash值
    • 访问控制:操作员,审核员,安全三员的权限设置
    • 安全审计:至少完成日志查询功能
  2. 密码(15 分)
    • 算法:SM2,SM3,SM4,推荐使用 Key
    • 密钥管理:所有私钥,对称算法密钥等不能明存
  3. 系统量化评估(5分)
    • 按照商用密码应用安全性评估量化评估规则,计算自己系统的得分,只计算应用和数据安全。
  4. 提交要求:
  • 提交实践过程Markdown和转化的PDF文件

  • 代码,文档托管到gitee或github等,推荐 gitclone

  • 记录实验过程中遇到的问题,解决过程,反思等内容,用于后面实验报告

开源仓库

我使用了前辈之前的仓库,仓库地址为青青草原七匹狼/电子公文传输系统,使用git clone命令下载即可。

环境配置

系统部分环境需要进行修改,配置过程如下所示:

个人配置

Windows 11

Python: 3.13

参考博客:(超详细)Python+PyCharm的安装步骤及PyCharm的使用(含快捷键)

Pycharm: Community Edition 2024.3

参考博客:(超详细)Python+PyCharm的安装步骤及PyCharm的使用(含快捷键)

OpenSSL:3.4.0 22 Oct ~2024

参考博客:环境篇-Windows下安装OpenSSL

MySQL:9.0

参考博客:Windows环境下MySQL安装与配置(超详细、超细致)

环境配置

在D盘(推荐)使用git clone https://gitee.com/Electronic-document-transfer-system/Document-transmission.git命令获取源代码,使用Pycharm打开项目,项目结构如下所示。

在左上角中,根据文件->设置->Project:Document-transmission->Python Interpreter的路径打开解释器,点击加号以安装其他包。

在里面搜索如下包进行安装:DjangoPyPDF2captchadjango-sslserverfiletypegmsslmysqlclientstandard-imghdrdjango-simple-captcha包。

接着,需要我们创建名为testdocument的数据库。

在命令行中使用如下命令进行数据表的创建。

python manage.py makemigrations                                             
python manage.py migrate                                                    

显示如下提示代表创建成功。

(.venv) PS D:\信息安全系统设计\Document-transmission-master\Document-transmission-master> python manage.py migrate
System check identified some issues:WARNINGS:
user.MyUser: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.HINT: Configure the DEFAULT_AUTO_FIELD setting or the UserConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
Operations to perform:Apply all migrations: admin, auth, captcha, contenttypes, index, sessions, user
Running migrations:Applying contenttypes.0001_initial... OKApplying contenttypes.0002_remove_content_type_name... OKApplying auth.0001_initial... OKApplying auth.0002_alter_permission_name_max_length... OKApplying auth.0003_alter_user_email_max_length... OKApplying auth.0004_alter_user_username_opts... OKApplying auth.0005_alter_user_last_login_null... OKApplying auth.0006_require_contenttypes_0002... OKApplying auth.0007_alter_validators_add_error_messages... OKApplying auth.0008_alter_user_username_max_length... OKApplying auth.0009_alter_user_last_name_max_length... OKApplying auth.0010_alter_group_name_max_length... OKApplying auth.0011_update_proxy_permissions... OKApplying user.0001_initial... OKApplying admin.0001_initial... OKApplying admin.0002_logentry_remove_auto_add... OKApplying admin.0003_logentry_add_action_flag_choices... OKApplying auth.0012_alter_user_first_name_max_length... OKApplying captcha.0001_initial... OKApplying captcha.0002_alter_captchastore_id... OKApplying index.0001_initial... OKApplying index.0002_auto_20210601_1010... OKApplying index.0003_document_type... OKApplying index.0004_document_lyrics... OKApplying index.0005_auto_20210602_0952... OKApplying index.0006_auto_20210602_0953... OKApplying index.0007_document_key... OKApplying index.0008_auto_20210605_1920... OKApplying sessions.0001_initial... OKApplying user.0002_auto_20210605_1743... OKApplying user.0003_alter_myuser_first_name... OK

index_document表里面有一个外键,不知道有什么用,但是带着这个外键又会报错。我们在SQL命令行把这个外键删了,使用如下命令:

use testdocument;
alter table index_document drop foreign key index_document_label_id_b5ce761f_fk_index_label_id;

之后的报错记录就又少了一条。紧接着,在electronicDocument/settings.py中修改数据库登录的密码,第91行中有如下代码:

        'PASSWORD': '1619553792',

把这个1619553792修改成数据库的密码123456即可。如果登录账户不是root,在上一行中的'USER': 'root'进行类似的修改即可。

代码修改

首先是SSL的问题,如果直接运行项目,可能会报这样的错:

AttributeError: module 'ssl' has no attribute 'wrap_socket'

这是因为包的版本更新了啊,没有这个用法了,把对应文件修改一下就可以。

打开项目中的runsslserver.py文件,第48行有一个SecureHTTPServer类,将其修改为如下所示:

class SecureHTTPServer(ThreadedWSGIServer):def __init__(self, address, handler_cls, certificate, key, ipv6=False):super(SecureHTTPServer, self).__init__(address, handler_cls, ipv6=ipv6)context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)context.load_cert_chain(certificate, key)self.socket = context.wrap_socket(self.socket,server_side=True,)

之后SSL的配置就完成了。

users/views.py,第88行有一个uploadView函数,这个函数需要大改一下。

我们可以看到里面有很多D:/electronicDocument/meida/...这样的路径。这也是我推荐把项目克隆到D盘的原因,这个项目里有很多的文件路径都是绝对路径。

我们的路径里面没有electronicDocument。如果直接把项目克隆到了D盘,直接把它替换成Document-transmission-master即可。不在D盘的情况下把替换为对应路径。其他文件中也会出现类似的问题,如果在运行项目时,出现FileNotFound的问题,通常就是因为这个没有修改,运行过程中出现报错再修改也可以。

还有PyPDF2的一些方法也被修改了,在200行附近,可以看到如下代码:

		file_reader = PdfFileReader("D:\\electronicDocument\\media\\documentFile\\"+str(myFile))file_writer = PdfFileWriter()for page in range(file_reader.getNumPages()):file_writer.addPage(file_reader.getPage(page))

遗憾的是一些方法已经使用不了了,将其修改为如下代码:

        file_reader = PdfReader("D:\\Document-transmission-msaster\\media\\documentFile\\"+str(myFile))file_writer = PdfWriter()for page in range(len(file_reader.pages)):file_writer.add_page(file_reader.pages[page])

这样上传公文的功能就可以使用了。

修改到目前,这种状况只能查看文件名为纯英文的文件,不能上传为文件名含有其他语言字符的文件,这是由于查看公文时传到后台的文件名中的其他语言字符进行了URL编码,但是查找文件的没有将编码转化为对应字符。

play/views.py中,开头第一行写入from urllib.parse import unquote进行包的导入。在第10行左右有一个playview函数,下滑到65行左右有一行代码file = documents.file.url[1::],在这行的下一行添加如下代码:

file = unquote(file)

再下滑到最底部,有一个downloadr函数。同理,在115行左右的file = document.file.url[1::]下一行中添加如下代码:

file = unquote(file)

这样就能进行相关的文件查看和下载了。

到此,代码几乎修改完成。

项目运行

项目需要我们找到development.crtdevelopment.key两个文件,应该在Python中Lib\site-package\sslserver\certs文件夹里面,我的路径是D:\信息安全系 ocument-transmission-master\.venv\Lib\site-packages\sslserver\certs\development.crtD:\信息安全系统设计\Document-transmission-master\.venv\Libckages\sslserver\certs\development.key

在终端中使用如下命令启动服务:

(.venv) PS D:\信息安全系统设计\Document-transmission-master\Document-transmission-master> python manage.py runsslserver --certificate D:\信息安全系 ocument-transmission-master\.venv\Lib\site-packages\sslserver\certs\development.crt --key D:\信息安全系统设计\Document-transmission-master\.venv\Libckages\sslserver\certs\development.key         

--certificate用于指定证书,--key用于指定私钥。

之后可能会有一些报错,应该是因为缺失某些包,按照上述安装包的方式一起安装就可以了;也可能是因为端口已经被占用,这时候需要杀死端口所在进程。

在这之后,如果出现如下提升,便证明服务启动成功:

Watching for file changes with StatReloader
Validating models...System check identified some issues:WARNINGS:
user.MyUser: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.HINT: Configure the DEFAULT_AUTO_FIELD setting or the UserConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.System check identified 1 issue (0 silenced).
December 08, 2024 - 15:54:27
Django version 5.1.4, using settings 'electronicDocument.settings'
Starting development server at https://127.0.0.1:8000/
Using SSL certificate: D:\信息安全系统设计\Document-transmission-master\.venv\Lib\site-packages\sslserver\certs\development.crt
Using SSL key: D:\信息安全系统设计\Document-transmission-master\.venv\Lib\site-packages\sslserver\certs\development.key
Quit the server with CTRL-BREAK.

此时,你的服务已经启动成功,可以在https://127.0.0.1:8000/进行相关操作了。

完成电子公文交换系统,系统功能展示

操作员界面

注册界面

登陆界面

首页

用户中心

发文

发送公文
从本地上传公文(公开)

成功上传

从本地上传公文(私密)

成功上传

查看公文(附有SM3哈希值后16位,可用于文件完整性检验)
公开的公文

私密的公文

审核公文(公文批复)

查询公文

收文

公文签收(下载公文)

查看公文(附有哈希值,可用于文件完整性检验)

查询公文

后台管理员界面(系统管理员、用户管理员)

修改数据库内is_superuser is_staff is_secert的值从0变为1,使得我能顺利地在站点管理页面成功登陆

登录界面

首页

用户管理员

增、删、改用户

需要录入用户名、密码等信息

权限设置(用户认证授权)[是否为超级用户(审计员、安全审计员、安全保密管理员、系统管理员、操作员)]

系统管理员

系统日志(查看公文信息)

可以查看公文标题、上传者、发文机关、上传时间、公文缩略图

组织单位(根据发文单位筛选公文)
以中办电科院为发文机关的公文

以北京电子科技学院为发文机关的公文

黄金法则

身份鉴别:口令不能明存,数据库要保存加盐的SM3Hash值

file = documents.file.url[1::]file = unquote(file)path_doc = os.path.join("D:/信息安全系统设计/Document-transmission-master/Document-transmission-master/", file)# print(path_doc)try:sm3_hash = "openssl dgst -sm3 " + path_docbash_r = os.popen(sm3_hash)info = bash_r.readlines()  # 读取命令行的输出到一个listfor line in info:  # 按行遍历line = line.strip('\r\n')hash_16 =line[-16::]print(hash_16)# print(line)except:print('sm3 error')return render(request, 'play.html', locals())

访问控制:操作员,审核员,安全三员的权限设置

详见前面系统展示部分

安全审计:至少完成日志查询功能

可以查看公文标题、上传者、发文机关、上传时间、公文缩略图

密码

算法:SM2,SM3,SM4,推荐使用 Key

部分代码展示如下:

sm2.py

import binascii
from random import choice
from . import sm3, func
from Cryptodome.Util.asn1 import DerSequence, DerInteger
from binascii import unhexlify
# 选择素域,设置椭圆曲线参数default_ecc_table = {'n': 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123','p': 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF','g': '32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7''bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0','a': 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC','b': '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93',
}class CryptSM2(object):def __init__(self, private_key, public_key, ecc_table=default_ecc_table, mode=0, asn1=False):"""mode: 0-C1C2C3, 1-C1C3C2 (default is 1)"""self.private_key = private_keyself.public_key = public_key.lstrip("04") if public_key.startswith("04") else public_keyself.para_len = len(ecc_table['n'])self.ecc_a3 = (int(ecc_table['a'], base=16) + 3) % int(ecc_table['p'], base=16)self.ecc_table = ecc_tableassert mode in (0, 1), 'mode must be one of (0, 1)'self.mode = modeself.asn1 = asn1def _kg(self, k, Point):  # kP运算Point = '%s%s' % (Point, '1')mask_str = '8'for i in range(self.para_len - 1):mask_str += '0'mask = int(mask_str, 16)Temp = Pointflag = Falsefor n in range(self.para_len * 4):if (flag):Temp = self._double_point(Temp)if (k & mask) != 0:if (flag):Temp = self._add_point(Temp, Point)else:flag = TrueTemp = Pointk = k << 1return self._convert_jacb_to_nor(Temp)def _double_point(self, Point):  # 倍点l = len(Point)len_2 = 2 * self.para_lenif l < self.para_len * 2:return Noneelse:x1 = int(Point[0:self.para_len], 16)y1 = int(Point[self.para_len:len_2], 16)if l == len_2:z1 = 1else:z1 = int(Point[len_2:], 16)T6 = (z1 * z1) % int(self.ecc_table['p'], base=16)T2 = (y1 * y1) % int(self.ecc_table['p'], base=16)T3 = (x1 + T6) % int(self.ecc_table['p'], base=16)T4 = (x1 - T6) % int(self.ecc_table['p'], base=16)T1 = (T3 * T4) % int(self.ecc_table['p'], base=16)T3 = (y1 * z1) % int(self.ecc_table['p'], base=16)T4 = (T2 * 8) % int(self.ecc_table['p'], base=16)T5 = (x1 * T4) % int(self.ecc_table['p'], base=16)T1 = (T1 * 3) % int(self.ecc_table['p'], base=16)T6 = (T6 * T6) % int(self.ecc_table['p'], base=16)T6 = (self.ecc_a3 * T6) % int(self.ecc_table['p'], base=16)T1 = (T1 + T6) % int(self.ecc_table['p'], base=16)z3 = (T3 + T3) % int(self.ecc_table['p'], base=16)T3 = (T1 * T1) % int(self.ecc_table['p'], base=16)T2 = (T2 * T4) % int(self.ecc_table['p'], base=16)x3 = (T3 - T5) % int(self.ecc_table['p'], base=16)if (T5 % 2) == 1:T4 = (T5 + ((T5 + int(self.ecc_table['p'], base=16)) >> 1) - T3) % int(self.ecc_table['p'], base=16)else:T4 = (T5 + (T5 >> 1) - T3) % int(self.ecc_table['p'], base=16)T1 = (T1 * T4) % int(self.ecc_table['p'], base=16)y3 = (T1 - T2) % int(self.ecc_table['p'], base=16)form = '%%0%dx' % self.para_lenform = form * 3return form % (x3, y3, z3)def _add_point(self, P1, P2):  # 点加函数,P2点为仿射坐标即z=1,P1为Jacobian加重射影坐标len_2 = 2 * self.para_lenl1 = len(P1)l2 = len(P2)if (l1 < len_2) or (l2 < len_2):return Noneelse:X1 = int(P1[0:self.para_len], 16)Y1 = int(P1[self.para_len:len_2], 16)if (l1 == len_2):Z1 = 1else:Z1 = int(P1[len_2:], 16)x2 = int(P2[0:self.para_len], 16)y2 = int(P2[self.para_len:len_2], 16)T1 = (Z1 * Z1) % int(self.ecc_table['p'], base=16)T2 = (y2 * Z1) % int(self.ecc_table['p'], base=16)T3 = (x2 * T1) % int(self.ecc_table['p'], base=16)T1 = (T1 * T2) % int(self.ecc_table['p'], base=16)T2 = (T3 - X1) % int(self.ecc_table['p'], base=16)T3 = (T3 + X1) % int(self.ecc_table['p'], base=16)T4 = (T2 * T2) % int(self.ecc_table['p'], base=16)T1 = (T1 - Y1) % int(self.ecc_table['p'], base=16)Z3 = (Z1 * T2) % int(self.ecc_table['p'], base=16)T2 = (T2 * T4) % int(self.ecc_table['p'], base=16)T3 = (T3 * T4) % int(self.ecc_table['p'], base=16)T5 = (T1 * T1) % int(self.ecc_table['p'], base=16)T4 = (X1 * T4) % int(self.ecc_table['p'], base=16)X3 = (T5 - T3) % int(self.ecc_table['p'], base=16)T2 = (Y1 * T2) % int(self.ecc_table['p'], base=16)T3 = (T4 - X3) % int(self.ecc_table['p'], base=16)T1 = (T1 * T3) % int(self.ecc_table['p'], base=16)Y3 = (T1 - T2) % int(self.ecc_table['p'], base=16)form = '%%0%dx' % self.para_lenform = form * 3return form % (X3, Y3, Z3)def _convert_jacb_to_nor(self, Point):  # Jacobian加重射影坐标转换成仿射坐标len_2 = 2 * self.para_lenx = int(Point[0:self.para_len], 16)y = int(Point[self.para_len:len_2], 16)z = int(Point[len_2:], 16)z_inv = pow(z, int(self.ecc_table['p'], base=16) - 2, int(self.ecc_table['p'], base=16))z_invSquar = (z_inv * z_inv) % int(self.ecc_table['p'], base=16)z_invQube = (z_invSquar * z_inv) % int(self.ecc_table['p'], base=16)x_new = (x * z_invSquar) % int(self.ecc_table['p'], base=16)y_new = (y * z_invQube) % int(self.ecc_table['p'], base=16)z_new = (z * z_inv) % int(self.ecc_table['p'], base=16)if z_new == 1:form = '%%0%dx' % self.para_lenform = form * 2return form % (x_new, y_new)else:return Nonedef verify(self, Sign, data):# 验签函数,sign签名r||s,E消息hash,public_key公钥if self.asn1:unhex_sign = unhexlify(Sign.encode())seq_der = DerSequence()origin_sign = seq_der.decode(unhex_sign)r = origin_sign[0]s = origin_sign[1]else:r = int(Sign[0:self.para_len], 16)s = int(Sign[self.para_len:2*self.para_len], 16)e = int(data.hex(), 16)t = (r + s) % int(self.ecc_table['n'], base=16)if t == 0:return 0P1 = self._kg(s, self.ecc_table['g'])P2 = self._kg(t, self.public_key)# print(P1)# print(P2)if P1 == P2:P1 = '%s%s' % (P1, 1)P1 = self._double_point(P1)else:P1 = '%s%s' % (P1, 1)P1 = self._add_point(P1, P2)P1 = self._convert_jacb_to_nor(P1)x = int(P1[0:self.para_len], 16)return r == ((e + x) % int(self.ecc_table['n'], base=16))def sign(self, data, K):"""签名函数, data消息的hash,private_key私钥,K随机数,均为16进制字符串:param self: :param data: data消息的hash:param K: K随机数:return: """E = data.hex()  # 消息转化为16进制字符串e = int(E, 16)d = int(self.private_key, 16)k = int(K, 16)P1 = self._kg(k, self.ecc_table['g'])x = int(P1[0:self.para_len], 16)R = ((e + x) % int(self.ecc_table['n'], base=16))if R == 0 or R + k == int(self.ecc_table['n'], base=16):return Noned_1 = pow(d+1, int(self.ecc_table['n'], base=16) - 2, int(self.ecc_table['n'], base=16))S = (d_1*(k + R) - R) % int(self.ecc_table['n'], base=16)if S == 0:return Noneelif self.asn1:return DerSequence([DerInteger(R), DerInteger(S)]).encode().hex()else:return '%064x%064x' % (R, S)def encrypt(self, data):# 加密函数,data消息(bytes)msg = data.hex()  # 消息转化为16进制字符串k = func.random_hex(self.para_len)C1 = self._kg(int(k, 16), self.ecc_table['g'])xy = self._kg(int(k, 16), self.public_key)x2 = xy[0:self.para_len]y2 = xy[self.para_len:2*self.para_len]ml = len(msg)t = sm3.sm3_kdf(xy.encode('utf8'), ml/2)if int(t, 16) == 0:return Noneelse:form = '%%0%dx' % mlC2 = form % (int(msg, 16) ^ int(t, 16))C3 = sm3.sm3_hash([i for i in bytes.fromhex('%s%s%s' % (x2, msg, y2))])if self.mode:return bytes.fromhex('%s%s%s' % (C1, C3, C2))else:return bytes.fromhex('%s%s%s' % (C1, C2, C3))def decrypt(self, data):# 解密函数,data密文(bytes)data = data.hex()len_2 = 2 * self.para_lenlen_3 = len_2 + 64C1 = data[0:len_2]if self.mode:C3 = data[len_2:len_3]C2 = data[len_3:]else:C2 = data[len_2:-64]C3 = data[-64:]xy = self._kg(int(self.private_key, 16), C1)# print('xy = %s' % xy)x2 = xy[0:self.para_len]y2 = xy[self.para_len:len_2]cl = len(C2)t = sm3.sm3_kdf(xy.encode('utf8'), cl/2)if int(t, 16) == 0:return Noneelse:form = '%%0%dx' % clM = form % (int(C2, 16) ^ int(t, 16))u = sm3.sm3_hash([i for i in bytes.fromhex('%s%s%s' % (x2, M, y2))])return bytes.fromhex(M)def _sm3_z(self, data):"""SM3WITHSM2 签名规则:  SM2.sign(SM3(Z+MSG),PrivateKey)其中: z = Hash256(Len(ID) + ID + a + b + xG + yG + xA + yA)"""# sm3withsm2 的 z 值z = '0080'+'31323334353637383132333435363738' + \self.ecc_table['a'] + self.ecc_table['b'] + self.ecc_table['g'] + \self.public_keyz = binascii.a2b_hex(z)Za = sm3.sm3_hash(func.bytes_to_list(z))M_ = (Za + data.hex()).encode('utf-8')e = sm3.sm3_hash(func.bytes_to_list(binascii.a2b_hex(M_)))return edef sign_with_sm3(self, data, random_hex_str=None):sign_data = binascii.a2b_hex(self._sm3_z(data).encode('utf-8'))if random_hex_str is None:random_hex_str = func.random_hex(self.para_len)sign = self.sign(sign_data, random_hex_str)  # 16进制return signdef verify_with_sm3(self, sign, data):sign_data = binascii.a2b_hex(self._sm3_z(data).encode('utf-8'))return self.verify(sign, sign_data)

sm3.py

import binascii
from math import ceil
from .func import rotl, bytes_to_listIV = [1937774191, 1226093241, 388252375, 3666478592,2842636476, 372324522, 3817729613, 2969243214,
]T_j = [2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169,2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169,2043430169, 2043430169, 2043430169, 2043430169, 2055708042, 2055708042,2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,2055708042, 2055708042, 2055708042, 2055708042
]def sm3_ff_j(x, y, z, j):if 0 <= j and j < 16:ret = x ^ y ^ zelif 16 <= j and j < 64:ret = (x & y) | (x & z) | (y & z)return retdef sm3_gg_j(x, y, z, j):if 0 <= j and j < 16:ret = x ^ y ^ zelif 16 <= j and j < 64:#ret = (X | Y) & ((2 ** 32 - 1 - X) | Z)ret = (x & y) | ((~ x) & z)return retdef sm3_p_0(x):return x ^ (rotl(x, 9 % 32)) ^ (rotl(x, 17 % 32))def sm3_p_1(x):return x ^ (rotl(x, 15 % 32)) ^ (rotl(x, 23 % 32))def sm3_cf(v_i, b_i):w = []for i in range(16):weight = 0x1000000data = 0for k in range(i*4,(i+1)*4):data = data + b_i[k]*weightweight = int(weight/0x100)w.append(data)for j in range(16, 68):w.append(0)w[j] = sm3_p_1(w[j-16] ^ w[j-9] ^ (rotl(w[j-3], 15 % 32))) ^ (rotl(w[j-13], 7 % 32)) ^ w[j-6]str1 = "%08x" % w[j]w_1 = []for j in range(0, 64):w_1.append(0)w_1[j] = w[j] ^ w[j+4]str1 = "%08x" % w_1[j]a, b, c, d, e, f, g, h = v_ifor j in range(0, 64):ss_1 = rotl(((rotl(a, 12 % 32)) +e +(rotl(T_j[j], j % 32))) & 0xffffffff, 7 % 32)ss_2 = ss_1 ^ (rotl(a, 12 % 32))tt_1 = (sm3_ff_j(a, b, c, j) + d + ss_2 + w_1[j]) & 0xfffffffftt_2 = (sm3_gg_j(e, f, g, j) + h + ss_1 + w[j]) & 0xffffffffd = cc = rotl(b, 9 % 32)b = aa = tt_1h = gg = rotl(f, 19 % 32)f = ee = sm3_p_0(tt_2)a, b, c, d, e, f, g, h = map(lambda x:x & 0xFFFFFFFF ,[a, b, c, d, e, f, g, h])v_j = [a, b, c, d, e, f, g, h]return [v_j[i] ^ v_i[i] for i in range(8)]def sm3_hash(msg):# print(msg)len1 = len(msg)reserve1 = len1 % 64msg.append(0x80)reserve1 = reserve1 + 1# 56-64, add 64 byterange_end = 56if reserve1 > range_end:range_end = range_end + 64for i in range(reserve1, range_end):msg.append(0x00)bit_length = (len1) * 8bit_length_str = [bit_length % 0x100]for i in range(7):bit_length = int(bit_length / 0x100)bit_length_str.append(bit_length % 0x100)for i in range(8):msg.append(bit_length_str[7-i])group_count = round(len(msg) / 64)B = []for i in range(0, group_count):B.append(msg[i*64:(i+1)*64])V = []V.append(IV)for i in range(0, group_count):V.append(sm3_cf(V[i], B[i]))y = V[i+1]result = ""for i in y:result = '%s%08x' % (result, i)return resultdef sm3_kdf(z, klen): # z为16进制表示的比特串(str),klen为密钥长度(单位byte)klen = int(klen)ct = 0x00000001rcnt = ceil(klen/32)zin = [i for i in bytes.fromhex(z.decode('utf8'))]ha = ""for i in range(rcnt):msg = zin  + [i for i in binascii.a2b_hex(('%08x' % ct).encode('utf8'))]ha = ha + sm3_hash(msg)ct += 1return ha[0: klen * 2]

sm4.py

# -*-coding:utf-8-*-
import copy
from .func import xor, rotl, get_uint32_be, put_uint32_be, \bytes_to_list, list_to_bytes, pkcs7_padding, pkcs7_unpadding, zero_padding, zero_unpadding# Expanded SM4 box table
SM4_BOXES_TABLE = [0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c,0x05, 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86,0x06, 0x99, 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed,0xcf, 0xac, 0x62, 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa,0x75, 0x8f, 0x3f, 0xa6, 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c,0x19, 0xe6, 0x85, 0x4f, 0xa8, 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb,0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25,0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52,0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38,0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34,0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, 0x1d, 0xf6, 0xe2, 0x2e, 0x82,0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, 0xd5, 0xdb, 0x37, 0x45,0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, 0x8d, 0x1b, 0xaf,0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, 0x0a, 0xc1,0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, 0x89,0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39,0x48,
]# System parameter
SM4_FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc]# fixed parameter
SM4_CK = [0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
]SM4_ENCRYPT = 0
SM4_DECRYPT = 1PKCS7 = 0
ZERO = 1class CryptSM4(object):def __init__(self, mode=SM4_ENCRYPT, padding_mode=PKCS7):self.sk = [0] * 32self.mode = modeself.padding_mode = padding_mode# Calculating round encryption key.# args:    [in] a: a is a 32 bits unsigned value;# return: sk[i]: i{0,1,2,3,...31}.@classmethoddef _round_key(cls, ka):b = [0, 0, 0, 0]a = put_uint32_be(ka)b[0] = SM4_BOXES_TABLE[a[0]]b[1] = SM4_BOXES_TABLE[a[1]]b[2] = SM4_BOXES_TABLE[a[2]]b[3] = SM4_BOXES_TABLE[a[3]]bb = get_uint32_be(b[0:4])rk = bb ^ (rotl(bb, 13)) ^ (rotl(bb, 23))return rk# Calculating and getting encryption/decryption contents.# args:    [in] x0: original contents;# args:    [in] x1: original contents;# args:    [in] x2: original contents;# args:    [in] x3: original contents;# args:    [in] rk: encryption/decryption key;# return the contents of encryption/decryption contents.@classmethoddef _f(cls, x0, x1, x2, x3, rk):# "T algorithm" == "L algorithm" + "t algorithm".# args:    [in] a: a is a 32 bits unsigned value;# return: c: c is calculated with line algorithm "L" and nonline# algorithm "t"def _sm4_l_t(ka):b = [0, 0, 0, 0]a = put_uint32_be(ka)b[0] = SM4_BOXES_TABLE[a[0]]b[1] = SM4_BOXES_TABLE[a[1]]b[2] = SM4_BOXES_TABLE[a[2]]b[3] = SM4_BOXES_TABLE[a[3]]bb = get_uint32_be(b[0:4])c = bb ^ (rotl(bb,2)) ^ (rotl(bb,10)) ^ (rotl(bb,18)) ^ (rotl(bb,24))return creturn (x0 ^ _sm4_l_t(x1 ^ x2 ^ x3 ^ rk))def set_key(self, key, mode):key = bytes_to_list(key)MK = [0, 0, 0, 0]k = [0] * 36MK[0] = get_uint32_be(key[0:4])MK[1] = get_uint32_be(key[4:8])MK[2] = get_uint32_be(key[8:12])MK[3] = get_uint32_be(key[12:16])k[0:4] = xor(MK[0:4], SM4_FK[0:4])for i in range(32):k[i + 4] = k[i] ^ (self._round_key(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ SM4_CK[i]))self.sk[i] = k[i + 4]self.mode = modeif mode == SM4_DECRYPT:for idx in range(16):t = self.sk[idx]self.sk[idx] = self.sk[31 - idx]self.sk[31 - idx] = tdef one_round(self, sk, in_put):out_put = []ulbuf = [0] * 36ulbuf[0] = get_uint32_be(in_put[0:4])ulbuf[1] = get_uint32_be(in_put[4:8])ulbuf[2] = get_uint32_be(in_put[8:12])ulbuf[3] = get_uint32_be(in_put[12:16])for idx in range(32):ulbuf[idx + 4] = self._f(ulbuf[idx],ulbuf[idx + 1],ulbuf[idx + 2],ulbuf[idx + 3],sk[idx])out_put += put_uint32_be(ulbuf[35])out_put += put_uint32_be(ulbuf[34])out_put += put_uint32_be(ulbuf[33])out_put += put_uint32_be(ulbuf[32])return out_putdef crypt_ecb(self, input_data):# SM4-ECB block encryption/decryptioninput_data = bytes_to_list(input_data)if self.mode == SM4_ENCRYPT:if self.padding_mode == PKCS7:input_data = pkcs7_padding(input_data)elif self.padding_mode == ZERO:input_data = zero_padding(input_data)length = len(input_data)i = 0output_data = []while length > 0:output_data += self.one_round(self.sk, input_data[i:i + 16])i += 16length -= 16if self.mode == SM4_DECRYPT:if self.padding_mode == PKCS7:return list_to_bytes(pkcs7_unpadding(output_data))elif self.padding_mode == ZERO:return list_to_bytes(zero_unpadding(output_data))return list_to_bytes(output_data)def crypt_cbc(self, iv, input_data):# SM4-CBC buffer encryption/decryptioni = 0output_data = []tmp_input = [0] * 16iv = bytes_to_list(iv)if self.mode == SM4_ENCRYPT:input_data = pkcs7_padding(bytes_to_list(input_data))length = len(input_data)while length > 0:tmp_input[0:16] = xor(input_data[i:i + 16], iv[0:16])output_data += self.one_round(self.sk, tmp_input[0:16])iv = copy.deepcopy(output_data[i:i + 16])i += 16length -= 16return list_to_bytes(output_data)else:length = len(input_data)while length > 0:output_data += self.one_round(self.sk, input_data[i:i + 16])output_data[i:i + 16] = xor(output_data[i:i + 16], iv[0:16])iv = copy.deepcopy(input_data[i:i + 16])i += 16length -= 16return list_to_bytes(pkcs7_unpadding(output_data))

详细代码详见提交在青青草原七匹狼/电子公文传输系统Gitee库或压缩包里的代码

密钥管理:所有私钥,对称算法密钥等不能明存

系统量化评估

按照商用密码应用安全性评估量化评估规则,计算自己系统的得分,只计算应用和数据安全

1.根据《商用密码应用安全性评估量化评估规则》文件,我们需要关注的测评指标包括:

  • 身份鉴别
  • 通信数据完整性
  • 通信过程中重要数据的机密性
  • 数据存储和传输的安全性

测评对象包括:

  • 用户账号管理
  • 公文的起草、审核、发送和查询
  • 系统日志和审计

2. 评估密码使用安全(D)

用户账号管理

  • 系统实现了身份认证,对口令做了加盐的SHA-256哈希保护。这符合密码使用安全的要求。

公文传输

  • 系统使用非对称密钥(SM2)保护对称密钥,再用对称密钥实现对文件的加解密。这符合密码使用安全的要求。

3. 评估密码算法/技术合规性(A)

密码算法使用

  • 系统使用了SM2算法进行加密,符合商用密码应用安全性评估量化评估规则中对算法的要求。

4. 评估密钥管理安全(K)

密钥管理

  • 私钥保护:系统使用SM2算法,这是一种合规的国产密码算法,用于保护对称密钥,符合密钥管理安全要求。
  • 对称密钥管理:系统使用加盐的SHA-256哈希存储密码,符合安全要求。

5. 计算测评对象评分(Si,j,k)

根据上述评估,每个测评对象的得分如下:

  • 用户账号管理:1(完全符合)
  • 公文传输:1(完全符合)
  • 系统日志和审计:0.5(部分符合,因为虽然有日志记录,但未明确说明密钥管理细节)

6. 计算测评单元得分(Si,j)

测评单元得分为测评对象得分的算术平均值:
image

7. 计算安全层面得分(Si)

应用和数据安全层面的权重为30(根据文件《商用密码应用安全性评估量化评估规则》中的权重设置),则:
image

8. 整体得分计算

根据文件《商用密码应用安全性评估量化评估规则》中的权重和得分计算方法,整体得分为:
image

计算结果为:

image

9. 结合高风险判定

根据《商用密码应用安全性评估量化评估规则》,如果系统存在高风险问题,即使得分较高,也需要结合高风险判定来确定最终的安全评估结果。系统实现了多种安全措施,包括防御XSS、CSRF、SQL注入等,没有明确指出存在高风险问题。

综上所述,电子公文传输系统在应用与数据安全层面的商用密码应用安全性评估量化评估得分较高,表明系统在密码应用安全性方面表现良好。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/876290.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android抓包相关操作指令

adb start-server adb connect 127.0.0.1:16384 adb rootadb shell su # 如果需要root权限mount -o remount,rw /systemadb push D:\\文档\\sixdu文档\\269953fb.0 /data/local/tmp adb push D:\\文档\\sixdu文档\\43b5e6bf.0 /data/local/tmpadb -s emulator-5554 push D:\\文…

四.1 Redis 五大数据类型/结构的详细说明/详细使用(List 列表数据类型详解和使用)

四.1 Redis 五大数据类型/结构的详细说明/详细使用(List 列表数据类型详解和使用) @目录四.1 Redis 五大数据类型/结构的详细说明/详细使用(List 列表数据类型详解和使用)2. list 列表常用指令(详细讲解说明)2.1 lpush/rpush <key><value1><value2>&l…

DeepSeek入门教程

一、简介 DeepSeek-V3 是一款高性能的开源 AI 模型,支持自然语言处理、智能对话生成等任务。其 API 接口与 OpenAI 完全兼容,用户可以通过简单的配置迁移现有项目,同时享受更低的成本和更高的性能。本文档将详细介绍如何快速接入 DeepSeek-V3 API 二、注册与API Key获取 1.注…

Archlinux 玩原神

首先你需要一台装载了archlinux的电脑,配置的话本人:Lenovo TianYi510S-07IMB Intel Core™ i5-10400 12 内存 8.0 GiB 磁盘 1 TB 玩的挺舒服的不会安装arch或者wine的看这里 然后本人是国际服Genshin Impact,国服同理(把下文的Genshin Impact当作yuanshen),参照官网安装…

C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)

前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿,助力技术成长与视野拓宽。欢迎投稿、推荐或自荐优质文章、项目、学习资源等…

JQuery实现轮播图

一、html代码<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </he…

e语言 超级编辑框

本文来自博客园,作者:__username,转载请注明原文链接:https://www.cnblogs.com/code3/p/18692666

clickhouse01 服务器选型, 安装(内核优化), mysql接口协议连接, DBeaver工具使用, 数据格式, 存储引擎, 用户管理

一:clickhouse 简介: https://clickhouse.com/docs/zh #什么是 clickhouse ClickHouse 是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。 1.1:clickhouse 简介:由俄罗斯的搜索公司 yandex 在 2016 年 6 月 15 日开源 操作和mysql很像 1.1.1:列式数据库与行式数据…

【Azure Logic App】使用MySQL 新增行触发器遇见错误 :“Unknowncolumncreated_atinorderclause”

Logic App MySQL Connector: Unknown column created_at in order clause问题描述 使用Azure Logic App服务,用于监控MySQL数据库的数据新增后,触发后续的逻辑处理操作。但是,当Workflow被触发Failed,并且无法执行Workflow中的动作。查看错误信息为 : Unknown column crea…

java集合中的泛型

多态 子类类型赋值给父类 Father f1 = New Son(), 调用子类方法报错。 调用父类方法OK。这个就是多态public class goodStudy{public static void main(String[] args) {ArrayList list = new ArrayList();// 子类类型赋值给父类Person u1 = new User();// 调用子类方法报错u…

java中链表LinkedList

复习一下: ArrayList在java哪一个包中? ArrayList在java --> util包中 import java.util.ArrayList; LinkedList LinkedList: 可以在集合前面增加数据,也可以在后面增加数据,还可以在数据之间增加数据。 LinkedList 新增add package goodStudy; //ArrayList在java-->…

2025-1-21-简易登录界面的实现

前端 我们需要两个输入框,一个登录按钮,像这样(为了好看,用的是element-ui的组件,使用的话需要先去下载文件引用)代码如下系统<el-form ref="form" :model="user" label-width="80px"><el-form-item label="用户名">…