基于CryptoAPI的文件加解密系统的设计与实现_第1页
基于CryptoAPI的文件加解密系统的设计与实现_第2页
基于CryptoAPI的文件加解密系统的设计与实现_第3页
基于CryptoAPI的文件加解密系统的设计与实现_第4页
基于CryptoAPI的文件加解密系统的设计与实现_第5页
已阅读5页,还剩18页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、基于CryptoAPI的文件加解密系统的设计与实现摘要:随着网络技术的快速发展,使我们的生活丰富多彩,工作的效率也提高了不少.尽管网络的出现给我们带来了很多的福利和方便,但网络安全问题也在时时困扰着我们,病毒、黑客的侵犯,各种威胁之声的不断传出,网络安全问题也就成为了社会关注的重点问题。文件的安全就是安全问题之一,文件可能会包含了很多的机密,一旦被黑客窃取,那损失是不可想象的。所以下面我们简单的谈谈文件加解密的相关算法。因为过于复杂的加密算法实现起来非常困难,所以在过去,许多应用程序只能使用非常简单的加密技术,这样做的结果就是加密的数据很容易就可以被人破译.而使用Microsoft提供的加密应

2、用程序接口(即Cryptography API),或称CryptoAPI,就可以方便地在应用程序中加入强大的加密功能,而不必考虑基本的算法。我们利用CryptoAPI来实现对文件的加密和解密。关键词:文件的加解密,CryptoAPI。1、 设计要求与实现:基于CryptoAPI的文件加解密系统的设计与实现2、 设计环境与工具1 软件环境、工具Windows 8.1、visual studio 20122CryptoAPI加密服务提供者CSP加密服务相关的所有操作都在CSP实现,它是真正实现加密相关服务的独立模块,既可以由软件实现也可以由硬件实现。每个CSP必须包含一个动态链接库和一个签名文件,

3、签名文件用于保证底层CSP的安全性,CryptoAPI接口在加载每个CSP时,需要验证CSP的签名,如果签名无效,则拒绝加载,CSP的签名由微软公司签发.同时,每个CSP都有一个名字和一个类型,名字必须是唯一的,这样便于CryptoAPI找到对应的CSP。CSP是真正实行加密的独立模块,可以由软件实现也可以由硬件实现。CSP必须符合CryptoAPI接口规范.每个CSP有一个密钥库,密钥库用于存储密钥.每个密钥库包括一个或多个密钥容器(Key Containers).每个密钥容器中包含属于一个特定用户的所有密钥对。每个密钥容器被赋予一个唯一的名字。在销毁密钥容器前,CSP将永久保存每一个密钥容

4、器,包括保存每个密钥容器中的公/私钥对。每个CSP都有一个名字和一个类型.每个CSP的名字是唯一的,这样便于CryptoAPI找到对应的CSP。目前已经有9种CSP类型,并且还在增长。下表列出它们支持的密钥交换算法、签名算法、对称加密算法和Hash算法。二、详细设计(1)原理概述CryptoAPI是一组函数,为了完成数学计算,必须具有密码服务提供者模块(CSP).Microsoft通过捆绑RSA Base Provider在操作系统级提供一个CSP,使用RSA公司的公钥加密算法,更多的CSP可以根据需要增加到应用中。事实上,CSP有可能与特殊硬件设备(如智能卡)一起来进行数据加密。Crypto

5、API接口允许简单的函数调用来加密数据,交换公钥,散列一个消息来建立摘要以及生成数字签名。它还提供高级的管理操作,如从一组可能的CSP中使用一个CSP。此外,CryptoAPI还为许多高级安全性服务提供了基础,包括用于电子商务的SET,用于加密客户机/服务器消息的PCT,用于在各个平台之间来回传递机密数据和密钥的PFX,代码签名等等。数据加解密,程序分为四大主要部分:1、 获取CSP句柄:真正实现加密相关服务的独立模块。2、 获取加密密钥:进行加、解密,必然需要构造密钥。两种方法:通过哈希值构造通过随机数构造。3、 数据加密与解密:实现对数据进行加密解密操作。4、 相关资源释放:释放申请的相关

6、资源。(下图为数据加解密的流程)(参考网络安全程序设计教程李红娇著)(2) CryptoAPI应用程序的编译环境包含的头文件 include windows.h include <wincrypt.h包含的静态链接库链接CryptoAPI函数必须有静态库Crypto32。lib的支持,部分CryptoAPI函数可能还需要静态库advapi32。lib及CryptUI。lib的支持.若在VC+6.0和VS2012上编译程序,则需加上以下语句 ifndef _WIN32_WINNT define _WIN32_WINNT 0x0400# endif(3)实验步骤1) 在VS2012

7、下实现基于CryptoAPI的文件加密. a、创建会话密钥为保证数据加密效率,CryptoAPI规定数据加密操作必须基于对称密码进行.于是,加密方进行加密操作首先必须创建会话密钥,一般可以通过调用函数CryptoGenKey或CryptDeriveKey创建,在创建会话密钥时指定加密算法.b、加密数据 在创建会话密钥后,则可以调用CryptEncrypt函数进行加密操作。加密操作需要注意的是每次加密数据块的长度必须根据具体的算法和算法类型确定,一般来说,加密数据块长度为算法规定的基准加密块长度的整数倍。对于分组密码,需为密文数据块预留一个基准块长度的空间。c、安全保存或交换

8、会话密钥数据加密完成后,当在今后的某个时间或其他用户需要解密数据时,必须保存会话密钥以备后用,或者是传输会话密钥给特定用户以使其能正确进行解密操作。2) 在VS2012下实现基于CryptoAPI的文件解密. a、获取会话密钥 根据保存或传输会话密钥方式不同,进行相应的操作正确获取会话密钥b、解密数据利用获取的会话密钥调用函数CryptDecrypt解密数据,它和函数CryptEncrypt互为逆操作.同样的,解密操作需要注意的是每次解密数据块的长度必须根据具体的算法和算法类型确定,一般来说,解密数据块长度为算法基准加密块长度的整数倍.要求: 1)

9、60;算法的详细实现过程。 a) 获得csp句柄 b) 构造密钥 c) 数据加密 d) 数据解密e) 释放相关资源 2)  算法实现的流程图 三、实验结果原文件加密后解密后PS:我们在加密的时候,没有采用通过随机数创建密钥,然后只能通过输入密码创建加密密钥。截图:未加密四、设计总结由于多方尝试并编写Openssl对文件的加解密方法,均以失败告终,所以我们小组决定采用新的加密算法,即Windows CryptoAPI,由微软公司提出的一种安全加密应用服务框架.本次试验的主要内容

10、是基于CryptoAPI的文件加解密系统的设计与实现,在仔细看懂代码的基础上,真正明白了CryptoAPI的结构体系。在加密操作时,首先要创建会话密钥,在创建会话密钥时指定加密算法,注意的是,创建会话密钥时,它制定具体的加密算法应该注意具体的CSP是否支持此算法.我们在做加密的时候,没有加入通过随机数创建会话密钥,只能进行输入密码创建加密密钥.然后是进行数据的加密操作,当完成以后要进行安全保存或者交换会话密钥.解密时要获取会话密钥,然后进行数据解密.CryptoAPI除直接用于加密数据外,还为许多高级安全性服务提供了基础,包括用于电子商务的SET,用于加密客户机/服务器消息的PCT,用于在各个

11、平台之间来回传递机密数据和密钥的PFX,代码签名等等.通过此次编写程序,我对基于CryptoAPI的文件加解密系统有了更深层次的了解,对之前做过的基于CryptoAPI 实现文件完整性校验的实验理解的更加透彻.在编写程序的过程中,遇到了很多棘手的问题,但是这些问题,我通过了找老师,上网查询问题出错的原因等方法努力的寻求答案,到现在为止,程序已经顺利完成,运行无阻。自己根据要求,从零开始做一份实验真的不容易,需要对整体结构局势进行把握,在做之前要做好多重准备工作,例如运行环境(软、硬件环境)、输入的形式和输入值的范围、输出的形式描述、功能描述。细节决定成败,对于我而言,这次的作业让我清楚认识到,

12、注重细节的重要性,有时候一个字母的大小写,几个变量的数据类型的统一性,考虑后选择的更为合适的数据类型,重复执行的问题等等,这些都让我不断进步.5、 源代码加密:ifndef _WIN32_WINNT#define_WIN32_WINNT 0x0400endifinclude<stdio。hinclude<string。h>include<iostream#includeconio。h#includewindows。hincludewincrypt。h>defineMY_ENCODING_TYPE (PKCS_7_ASN_ENCODING X509_ASN_ENCO

13、DING)defineKEYLENGTH 0x00800000defineENCRYPT_ALGORITHMCALG_RC4defineENCRYPT_BLOCK_SIZE 8 classEncpublic:HCRYPTPROVGetCryptProv();BOOLEncryptFile(PCHARszSource, PCHARszDestination, PCHARszPassword); HCRYPTKEYGenKeyByPassword(HCRYPTPROVhCryptProv,PCHARszPassword);;includeiostreaminclude"Enc。h”usi

14、ngnamespacestd;/ 功能:加密原文szSource文件,加密后的数据存储在szDestination文件中/ 参数:/ szSource:原文文件名/ szDestination:加密后数据存储文件/ szPassword:用户输入的密码BOOLEnc::EncryptFile(PCHARszSource, PCHARszDestination, PCHARszPassword) / 变量申明与初始化。FILE hSource; FILE *hDestination; HCRYPTPROVhCryptProv; HCRYPTKEYhKey; PBYTEpbBuffer; DWOR

15、DdwBlockLen; DWORDdwBufferLen; DWORDdwCount; / 打开原文文件。 if(hSource = fopen(szSource,”rb”)cout<”原文文件”szSource”已经打开. n”;else cout<"打开原文文件出错!”<endl; / 打开目标文件. if(hDestination = fopen(szDestination,"wb”)cout"目标文件”szDestination<”已经打开。 n”endl;elsecout<<”打开目标文件出错!"<e

16、ndl; /获取加密服务者句柄hCryptProv = GetCryptProv();/ 创建会话密钥。if(!szPassword strcmp(szPassword,"”)=0 ) /hKey = GenKeyByRandom( hCryptProv, hDestination);当输入密码为空时,则创建随机的加密密钥,并导出创建的密钥保存到文件中。cout<”你输入的密钥为空!请正确输入!"endl; else / 当输入密码不为空时,则通过输入密码创建加密密钥hKey=GenKeyByPassword( hCryptProv, szPassword); / 因

17、为加密算法按ENCRYPT_BLOCK_SIZE 大小块加密,所以被加密的/ 数据长度必须是ENCRYPT_BLOCK_SIZE 的整数倍.下面计算一次加密的/ 数据长度。dwBlockLen = 1000 - 1000 ENCRYPT_BLOCK_SIZE; / 确定加密后密文数据块大小。 若是分组密码模式,则必须有容纳额外块的空间if(ENCRYPT_BLOCK_SIZE 1) dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE; elsedwBufferLen = dwBlockLen; / 分配内存空间。 if(pbBuffer = (BYTE

18、)malloc(dwBufferLen)cout”已经为缓冲区分配了内存. n”;else cout<<”所需内存不够。 n”; / 循环加密原文件do / 每次从原文件中读取dwBlockLen字节数据. dwCount = fread(pbBuffer, 1, dwBlockLen, hSource); if(ferror(hSource)) cout<"读取明文文件出错!n”;/-/ 加密数据。 if(!CryptEncrypt(hKey,/密钥0,/如果数据同时进行散列和加密,这里传入一个散列对象feof(hSource),/如果是最后一个被加密的块,输入T

19、RUE。如果不是输入FALSE./这里通过判断是否到文件尾来决定是否为最后一块。0,/保留pbBuffer,/输入被加密数据,输出加密后的数据dwCount,/输入被加密数据实际长度,输出加密后数据长度dwBufferLen))/pbBuffer的大小。 cout”加密数据时出错。 n”; /-/ 把加密后数据写到密文文件中fwrite(pbBuffer, 1, dwCount, hDestination); if(ferror(hDestination) cout”写入密文时出错。”; while(!feof(hSource)); /-/ 关闭文件if(hSource)if(fclose(h

20、Source))cout<”关闭原文文件出错!”;if(hDestination)if(fclose(hDestination))cout”关闭目标文件出错!";/-/ 释放内存空间。 if(pbBuffer) free(pbBuffer); /-/ 销毁会话密钥if(hKey)if(!(CryptDestroyKey(hKey))cout<”销毁会话密钥时出错”endl;/-/ 释放CSP句柄if(hCryptProv)if(!(CryptReleaseContext(hCryptProv, 0))cout<"释放CSP句柄时出错”<endl;re

21、turn(TRUE); / end Encryptfile/获取加密提供者句柄HCRYPTPROVEnc:GetCryptProv()HCRYPTPROVhCryptProv; / 加密服务提供者句柄/获取加密提供者句柄if(CryptAcquireContext(hCryptProv, / 加密服务提供者句柄NULL, / 密钥容器名,这里使用登陆用户名MS_ENHANCED_PROV, / 加密服务提供者PROV_RSA_FULL, / 加密服务提供者类型,可以提供加密和签名等功能0)) / 标志cout”加密服务提供者句柄获取成功!n"else/重新建立一个新的密钥集if(!C

22、ryptAcquireContext(&hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET)cout<"重新建立一个新的密钥集出错!”;returnhCryptProv;/ GenKeyByRandom:通过输入密码创建会话密钥/ 参数:hCryptProv CSP句柄/ szPassword输入密码HCRYPTKEYEnc::GenKeyByPassword(HCRYPTPROVhCryptProv,PCHARszPassword)HCRYPTKEYhKey; HCRYPTHASHhHa

23、sh;/-/ 创建哈希句柄。 if(CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash)cout”一个哈希句柄已经被创建。 n”;else cout<”Error during CryptCreateHash!n"; /-/ 计算输入密码的哈希值. if(CryptHashData(hHash, (BYTE )szPassword, strlen(szPassword), 0) cout<<"密码已经被添加到了哈希表中。 n”; else cout"计算输入密码的哈希值时出错。 n”; /

24、-/ 通过哈希值创建会话密钥。 if(CryptDeriveKey(hCryptProv, ENCRYPT_ALGORITHM, hHash, KEYLENGTH, hKey) cout”通过密码的哈希值获得了加密密钥. n”; else cout<”Error during CryptDeriveKey!n”; /-/ 销毁哈希句柄。 if(hHash) if(!(CryptDestroyHash(hHash))cout”Error during CryptDestroyHash”<endl; hHash = 0;/返回创建的会话密钥returnhKey;解密:ifndef_WI

25、N32_WINNT#define _WIN32_WINNT 0x0400endif#includestdio.hinclude<string。hincludeconio。h#include<windows.h#include<wincrypt.h#include<iostreamdefineMY_ENCODING_TYPE (PKCS_7_ASN_ENCODING X509_ASN_ENCODING)defineKEYLENGTH 0x00800000#defineENCRYPT_ALGORITHMCALG_RC4#defineENCRYPT_BLOCK_SIZE 8

26、classDec /加密文件的方法public:HCRYPTPROVGetCryptProv(); /方法的原型BOOLDecryptFile(PCHARszSource, PCHARszDestination, CHAR *szPassword); HCRYPTKEYGenKeyByPassword(HCRYPTPROVhCryptProv,PCHARszPassword); /通过输入口令创建会话密钥,我们的密码HCRYPTKEYGenKeyFromFile(HCRYPTPROVhCryptProv,FILE hSource);;#ifndef _WIN32_WINNT#define_WI

27、N32_WINNT 0x0400#endif#includestdio。h#include<string。h>#includeconio.hincludewindows。h#includewincrypt。h#includeiostreamdefineMY_ENCODING_TYPE (PKCS_7_ASN_ENCODING X509_ASN_ENCODING)defineKEYLENGTH 0x00800000defineENCRYPT_ALGORITHMCALG_RC4defineENCRYPT_BLOCK_SIZE 8 includeiostream>#include&

28、quot;Dec。h"usingnamespacestd;/功能:解密密文szSource文件,解密后的数据存储到szDestination文件中/BOOLDec::DecryptFile(PCHARszSource, /密文文件名PCHARszDestination, /解密后数据存储文件PCHARszPassword) /口令,即密码,其实口令和密码是两回事,了解一下就行了,作用一样 /-/ 局部变量申明与初始化。FILE *hSource; FILE *hDestination; HCRYPTPROVhCryptProv; HCRYPTKEYhKey; PBYTEpbBuffe

29、r; DWORDdwBlockLen; DWORDdwBufferLen; DWORDdwCount; BOOL status = FALSE; /-/ 打开密文文件。 if(!(hSource = fopen(szSource,"rb"))) cout<”打开密文文件出错!”endl;/-/ 打开目标文件,用于存储解密后的数据。 if(!(hDestination = fopen(szDestination,”wb")cout<”打开明文文件出错!”<endl;/获取加密服务者句柄hCryptProv = GetCryptProv();/获取或

30、创建会话密钥if(!szPassword| strcmp(szPassword,"”)=0 ) /-/从密文文件导入保存的会话密钥hKey = GenKeyFromFile( hCryptProv,hSource); else /-/ 通过输入密码重新创建会话密钥。 hKey=GenKeyByPassword( hCryptProv, szPassword); / 计算一次解密的数据长度,它是ENCRYPT_BLOCK_SIZE 的整数倍dwBlockLen = 1000 1000 % ENCRYPT_BLOCK_SIZE; dwBufferLen = dwBlockLen; /-/

31、 分配内存空间。 if(!(pbBuffer = (BYTE *)malloc(dwBufferLen))cout”所需内存不够!"<endl; /-/ 解密密文文件,解密后数据保存在目标文件do /-/ 每次从密文文件中读取dwBlockLen字节数据。 dwCount = fread(pbBuffer, 1, dwBlockLen, hSource); if(ferror(hSource)cout"读取密文文件出错!"endl;/-/ 解密数据if(!CryptDecrypt(hKey, 0, feof(hSource), 0, pbBuffer, dw

32、Count)cout<"解密数据时出错!"<endl; /-/ 把解密后的数据写入目标文件中。 fwrite(pbBuffer, 1, dwCount, hDestination); if(ferror(hDestination))cout”把解密后的数据写入目标文件中时出错!"<<endl; while(!feof(hSource); status = TRUE; /-/ 关闭文件if(hSource)if(fclose(hSource)cout<”关闭原文件出错"<endl;if(hDestination)if(f

33、close(hDestination)cout”关闭目标文件出错"<endl; /-/ 释放内存空间if(pbBuffer) free(pbBuffer); /-/ 销毁会话密钥if(hKey)if(!(CryptDestroyKey(hKey)cout<<"销毁会话密钥时出错"endl; /-/ 释放CSP句柄if(hCryptProv)if(!(CryptReleaseContext(hCryptProv, 0)cout<<”释放CSP句柄时出错!"endl; return status; / end Decryptfi

34、leHCRYPTPROVDec:GetCryptProv()HCRYPTPROVhCryptProv; / 加密服务提供者句柄/获取加密提供者句柄if(CryptAcquireContext(&hCryptProv, / 加密服务提供者句柄NULL, / 密钥容器名,这里使用登陆用户名MS_ENHANCED_PROV, / 加密服务提供者PROV_RSA_FULL, / 加密服务提供者类型,可以提供加密和签名等功能0)) / 标志cout”加密服务提供者句柄获取成功!n”;/cout"加密服务提供者句柄获取成功”endl;else/重新建立一个新的密钥集if(!CryptAc

35、quireContext(hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET))cout<”重新建立一个新的密钥集出错!”<<endl;returnhCryptProv;HCRYPTKEYDec::GenKeyFromFile(HCRYPTPROVhCryptProv,FILE hSource)HCRYPTKEYhKey; PBYTEpbKeyBlob; DWORDdwKeyBlobLen; /从密文文件中获取密钥数据块长度,并分配内存空间。 fread(dwKeyBlobLen, sizeof

36、(DWORD), 1, hSource); if(ferror(hSource) | feof(hSource))cout<”读取密文文件中密钥数据块长度出错!”<endl; if(!(pbKeyBlob = (BYTE )malloc(dwKeyBlobLen)cout”内存分配出错”endl; /-/ 从密文文件中获取密钥数据块fread(pbKeyBlob, 1, dwKeyBlobLen, hSource); if(ferror(hSource) | feof(hSource))cout<”读取密文文件中密钥数据块出错!”endl; /-/ 导入会话密钥到 CSP。

37、if(!CryptImportKey(hCryptProv, pbKeyBlob, dwKeyBlobLen, 0, 0, hKey)cout<”Error during CryptImportKey!”endl; if(pbKeyBlob) free(pbKeyBlob);/返回导出的会话密钥returnhKey;HCRYPTKEYDec::GenKeyByPassword(HCRYPTPROVhCryptProv,PCHARszPassword)HCRYPTKEYhKey; HCRYPTHASHhHash;/-/ 创建哈希句柄。 if(CryptCreateHash(hCryptPr

38、ov, CALG_MD5, 0, 0, &hHash))cout”一个哈希句柄已经被创建。 n”;else cout<”Error during CryptCreateHash!”endl; /-/ 计算输入密码的哈希值. if(CryptHashData(hHash, (BYTE )szPassword, strlen(szPassword), 0) cout<”此密码已经被添加到了哈希表中。 n" else cout<”Error during CryptHashData”endl; / 通过哈希值创建会话密钥.if(CryptDeriveKey(hCr

39、yptProv, ENCRYPT_ALGORITHM, hHash, KEYLENGTH, hKey) cout”从这个密码的哈希值获得了一个加密密钥。 n"; else cout<”哈希值创建会话密钥时出错!"endl; / 销毁哈希句柄. if(hHash) if(!(CryptDestroyHash(hHash)))cout"销毁哈希句柄时出错”endl; hHash = 0;/返回创建的会话密钥returnhKey;主函数ifndef _WIN32_WINNTdefine_WIN32_WINNT 0x0400endifinclude”Enc。h”/引

40、入我们写的加密头文件include”Dec。h"/引入我们写的解密头文件includestdio。hincludestring。h>includeiostreamincludeconio。h/需要的库include<windows.h/需要的库include<wincrypt。h>/需要的库usingnamespacestd;defineMY_ENCODING_TYPE (PKCS_7_ASN_ENCODING X509_ASN_ENCODING) /* 这些宏定义有用,不可去除/#defineKEYLENGTH 0x00800000HCRYPTPROVGet

41、CryptProv(); /获取加密提供者句柄的方法void main(void) Encenc; /加密对象Decdec; /解密对象PCHARszSource; /原文文件名PCHARszDestination; /加密后数据存储文件CHARszPassword100 = "”; /用户输入口令,这里为ID码char response; /提示密码信息选择int choose; /处理方式选择,是加密还是解密 1加密 2解密intendflag=1;char done;docout<”请你选择处理方式:”endl;cout"1.加密”endl;cout<<”2。解密”endl;coutendl;cinchoose;switch(choose)case 1:/加密模块if(!(szSource=(char )malloc(100)) /c语言的分配内存方法cout<<”内存分配失败。"endl;if(!(szDestination=(char *)malloc(100)cout<<”内存分配失败。”endl;cout”加密一个文件. nn”;cout<”请输入需要被加密文件的名称(绝对路径): "endl; /这里要很注意,输入的需是绝对路径,如:d:mytesta.txtcin

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论