实验报告
1.OpenEuler-OpenSSL编译
任务详情:
- 下载最新的OpenSSL源码
- 用自己的8位学号建立一个文件夹,cd 你的学号,用pwd获得绝对路径
- 参考https://www.cnblogs.com/rocedu/p/5087623.html先在Ubuntu中完成OpenSSL编译安装,然后在OpenEuler中重现 ./config --prefix=..(学号目录的绝对路径)指定OpenSSL编译链接
- 提交 test_openssl.c 编译运行截图
- 加分项:在Windows中编译OpenSSL,记录编译过程,提交相关文档(推荐MarkDown格式)
完成情况:
test_openssl.c :
#include <stdio.h>
#include <openssl/evp.h>
int main(){
OpenSSL_add_all_algorithms();
return 0;
}
编译命令:
gcc -o test_openssl.c -lcrypto -lssl
./test;echo $?
解压源代码
make
sudo+make+install
test_openssl.c+编译运行
编译链接
复现
加分项1CodeBlocks配置openssl
加分项2加动态库
加分项3加头文件
加分项4测试Base64效果
密码引擎-2-电子钥匙功能测试
任务详情: 0 参考附件中的视频 1 解压"资源"中“龙脉密码钥匙驱动实例工具等”压缩包 2 在Ubuntu中运行 “龙脉密码钥匙驱动实例工具等\mToken-GM3000\skf\samples\linux_mac”中例程,提交运行结果截图 3 加分项:运行“龙脉密码钥匙驱动实例工具等\mToken-GM3000\skf\samples\windows”中例程,提交运行结果截图
完成情况:
安装龙脉电子钥匙并导入证书
在ubuntu中成功测试加密
在ubuntu中成功认证
在ubuntu中成功测试加密
在windows中测试加密
在Windows中测试验签
实验一-密码引擎-3-加密API研究
任务详情
密码引擎API的主要标准和规范包括: 1 微软的Crypto API 2 RAS公司的PKCS#11标准 3 中国商用密码标准:GMT 0016-2012 智能密码钥匙密码应用接口规范,GMT 0018-2012密码设备应用接口规范等 研究以上API接口,总结他们的异同,并以龙脉GM3000Key为例,写出调用不同接口的代码,提交博客链接和代码链接。 内容: 0 查找各种标准的原始文档,研究学习(至少包含Crypto API,PKCS#11,GMT 0016-2012,GMT 0018-2012)(5分) 1 总结这些API在编程中的使用方式(5分) 2 列出这些API包含的函数,进行分类,并总结它们的异同(10分) 3 以龙脉GM3000Key为例,写出调用不同接口的代码(Crypto API,PKCS#11,SKF接口),把运行截图加入博客,并提供代码链接(10分)
0 、查找各种标准的原始文档,研究学习(至少包含Crypto API,PKCS#11,GMT 0016-2012,GMT 0018-2012)
(1)Crypto API:
作为一部分 Microsoft Windows 提供的应用程序编程接口 (API),CryptoAPI 提供了一组函数。这些函数允许应用程序在对用户的敏感私钥数据提供保护时,以灵活的方式对数据进行加密或数字签名。实际的加密操作是由称为加密服务提供程序 (CSP) 的独立模块执行。
CryptoAPI是一组函数,为了完成数学计算,必须具有密码服务提供者模块(CSP)。Microsoft通过捆绑RSA Base Provider在操作系统级提供一个CSP,使用RSA公司的公钥加密算法,更多的CSP可以根据需要增加到应用中。事实上,CSP有可能与特殊硬件设备(如智能卡)一起来进行数据加密。CryptoAPI接口允许简单的函数调用来加密数据,交换公钥,散列一个消息来建立摘要以及生成数字签名。它还提供高级的管理操作,如从一组可能的CSP中使用一个CSP。此外,CryptoAPI还为许多高级安全性服务提供了基础,包括用于电子商务的SET,用于加密客户机/服务器消息的PCT,用于在各个平台之间来回传递机密数据和密钥的PFX,代码签名等等。
(2)PKCS#11:
在密码系统中,PKCS#11是公钥加密标准(PKCS, Public-Key Cryptography Standards)中的一份子 ,由RSA实验室(RSA Laboratories)发布[1],它为加密令牌定义了一组平台无关的API ,如硬件安全模块和智能卡。
PKCS#11标准定义了与密码令牌(如硬件安全模块(HSM)和智能卡)的独立于平台的API,并将API本身命名为“Cryptoki”(来自“加密令牌接口”,发音为“crypto-key” - 但是“PKCS#11”通常用于指代API以及定义它的标准)。 API定义了最常用的加密对像类型(RSA密钥,X.509证书,DES / 三重DES密钥等)以及使用,创建/生成,修改和删除这些对象所需的所有功能。
(3)GMT 0016-2012:
本标准规定了基于PKI密码体制的智能密码钥匙密码应用接口,描述了密码应用接口的函数、数据类型、参数的定义和设备的安全要求。
本标准适用于智能密码钥匙产品的研制、使用和检测。
(4)GMT 0018-2012:
本标准规定了公钥密码基础设施应用技术体系下服务类密码设备的应用接口标准,
本标准适用于服务类密码设备的研制使用,以及基于该类密码设备的应用开发,也可用于指导该类密码设备的检测
1、总结这些API在编程中的使用方式
(1)Crypto API
使用CryptoAPI编写一个文件保护程序,具有如下功能:
(1)给定明文文件,生成加密文件,同时产生文件的数字签名文件;
(2)给定密文文件,解密出明文文件,并验证签名的正确性。
在不安全的网络上进行安全的数据传输涉及三个方面的要求:信息隐藏,身份鉴别和完整性检验。CryptoAPI除了提供上述三个功能外还提供标准的ASN.1编码、解码,信息解密,数字证书和证书存储区的管理,证书信任列表、吊销列表和证书有效性检查等功能。
信息隐藏
信息隐藏的意义是保障信息内容只能被特定的人获取。信息隐藏通常是使用某种形式的密码学方式。数据加密算法能保障信息的安区隐藏和传输。数据加密算法是将明文数据经过一定的变换使其看上去是一组毫无意义的数据。在没有加密密钥的情况下,对于好的加密算法想从密文获取明文信息是不可能的。被加密的数据可以是任意的ASCII编码文本文件,数据库文件,和任意需要进行安全传输的数据。这里,“信息”是指任意的一段数据,“明文”是指任意一段没有被加密的数据,“密文”是指任意一段加密的数据。被加密的数据可以在不安全的通道上进行传输而不伤害其安全性。之后,密文可以被还原成明文.
数据加密和解密的概念是:对数据加密的时候需要一个加密密钥,相当于门上的一把钥匙。解密的时候,需要使用一个解密密钥来解开数据。加密密钥、解密密钥可以相同也可以不相同。
加密密钥必须小心保存,给其它用户的时候也必须通过安全的通道传递。对解密密钥的访问权限必须小心控制,因为拥有解密密钥意味着可以解开所有相应加密密钥加密的信息。
身份鉴别
安全通讯的前提是通讯的双方知道对方的身份。身份鉴别的任务就是鉴别一个用户或者实体的真实身份。标识用户身份的文档通常被称为信任状或者凭证。
身份鉴别有时候也用来判定接受的数据就是被发送的数据。如果A向B发送了一段数据,B需要鉴别这段数据就是A发出去的,而不是其它冒充A发出去的。为了满足这类验证的需求,CryptoAPI提供数字签名和校验函数,用来对信息进行鉴别。
因为在计算机网网络上传输的数据与用户之间并没有物理连接,因此对数据进行鉴别的凭证也必须能够在网络上进行传输。这种凭证必须由受信任的凭证发行机构发行。
数字证书就是平常说的证书就是这种凭证,是计算机在网络上进行身份验证的有效凭证。
数字证书是由一个被称为证书机构的信任组织或实体颁发的凭证。它包含与证书对应的用户公钥以及其它一些记录证书主题和用户信息的数据。证书机构只有在验证了证书主题和证书对应的用户公钥的有效性之后才会签发证书。
证书申请者和证书机构之间交换签发证书信息可以使用物理介质,比如软盘,进行传输。通常,这种信息都是在计算机网络上进行完成的。证书机构使用被信任的服务程序处理用户的请求和证书的签发工作。
完整性检测
任何通过不安全介质传输的信息都可以被意外或蓄意的修改。在现实世界中,盖章、签名就是用来提供和证明信息完整性的工具。
信息的接收者不但需要确定信息是由谁发送的,还要确定自己收到的信息是发送者发送的信息,而没有任何的变化。要建立数据的完整性检测机制,不仅要发送信息本身,还要发送用来校验数据的信息,这一信息通常被称作哈希值。数据和验证信息都可以与数字签名一起发送来证明其完整性。
(2)PKCS#11
架构:
会话状态:
对象:
(3)GMT 0016-2012
下列文件对于本文件的应用是必不可少的凡是注日期的引用文件,仅注日期的版本适用于本文件。凡是不注日期的引用文件,其最新版本(包括所有的修改单)适用于本文件。
①GM/T 0006 密码应用标识规范
②GM/T0009 SM2密码算法使用规范
术语和定义
下列术语和定义适用于本文件
应用 application
包括容器、设备认证密钥和文件的一种结构,具备独立的权限管理。
容器container
密码设备中用于保存密钥所划分的唯一性存储空间。
设备device
本标准中将智能密码钥匙统称为设备
设备认证 device authentication智能密码钥匙对应用程序的认证
设备认证密钥 device authentication key用于设备认证的密钥。
设备标签 label
设备的别名,可以由用户进行设定并存储于设备内部。
消息鉴别码 message authentication code; MAC消息鉴别算法的输出。
管理员PIN administrator PIN管理员的口令,为ASCII字符串
用户PIN user PIN
用户的口令,为ASCII字符串。
缩略语
下列缩略语适用于本规范: API 应用编程接口(Application Programming Interface)
PKI 公钥基础设施(Public Key Infrastructure)
PKCS#1
公钥密码使用标准系列规范中的第1部分,定义RSA公开密钥算法加密和签名机制(the Public-Key Cryptography Standard Part 1)
PKCS#5 公钥密码使用标准系列规范中的第5部分,描述一种利用从口令派生出来的安全密
钥加密字符串的方法(the Public-Key Cryptography Standard Part 5)
PIN 个人身份识别码(Personal Identification Number)
MAC 消息鉴别码(Message Authentication Code)
(4)GMT 0018-2012
规范性引用文件
下列文件对于本文件的应用是必不可少的。凡是注日期的引用文件,仅注日期的版本适用于本文件,凡是不注日期的引用文件,其最新版本(包括所有的修改单)适用于本文件。
GM/T0006密用标识规范 GM/T0009SM2密码算法使用规范
术语和定义
以下术语和定义活用干本文件
算法标识algorithm ideutifier
用于对密码算法进行唯一标识的符号。
非对称密码算法/公钥密码算法 asymmetric cryptographic algorithm/public key cryptographic algorithm加解密使用不同密钥的密码算法。
解密 decipherment/decryption加密过程对应的逆过程。
设备密钥device key pair
存储在设备内部的用于设备管理的非对称密钥对包含签名密钥对和加密密钥对。
加密encipherment/encryption
对数据进行密码变换以产生密文的过程。
密钥加密密钥key encrypt key;KEK对密钥进行加密保护的密钥。
公钥基础设施public key infrastructure;PKI
用公钥密码技术建立的普遍适用的基础设施,为用户提供证书管理和密钥管理等安全服务。
私钥访问控制码private key access password
用于验证私钥使用权限的口令字。
对称密码技术/对称密码体制 symmetric cryptographic technique
原发者和接收者均采用同秘密密钥进行变换的密码技术(体制)。其中,加密密钥与解密密钥相同或者一个密钥可以从另一个密钥导出的密码体制。
会话密钥session key
处于层次化密钥结构中的最低层,仅在一次会话中使用的密钥。
用户密钥 user key
存储在设备内部的用于应用密码运算的非对称密钥,包含签名密钥对和加密密钥对。
符号和缩略语
下列缩略语适用于本部分:
ECC 椭圆曲线算法(Elliptic Curve Cryptography)
IPK 内部加密公钥(Internal Public Key)
ISK
内部加密私钥(Interal Private Key) EPK
外部加密公钥(Extenal Public Key) KEK 密钥加密密钥(Key Encrypt Key)
2、列出这些API包含的函数,进行分类,并总结它们的异同
(1)Crypto API
主要函数:
a) 主函数
void main(void)
b) 加密文件
BOOL EncryptFile(PCHAR szSource, PCHAR szDestination, PCHAR szPassword);
c) 解密文件
BOOL DecryptFile(PCHAR szSource, PCHAR szDestination, PCHAR szPassword);
d) 签名文件
BOOL SignFile (PCHAR szSource, PCHAR szDestination);
e) 验证签名
BOOL VerifyFile (PCHAR szSource, PCHAR szDestination);
f) 错误处理
void HandleError(char *s);
加密文件:
a) 打开源文件
hSource = fopen(szSource,"rb")
b) 取得密钥容器(CSP)句柄
CryptAcquireContext(&hCryptProv,NULL,NULL,PROV_RSA_FULL,0)
c) 根据用户输入的密码创建一个会话密钥(即对称密钥,用于对原文件加密)
//创建一个Hash对象
CryptCreateHash(hCryptProv,CALG_MD5, 0, 0, &hHash)
//用用户输入的密码产生一个散列
CryptHashData(hHash, (BYTE *)szPassword, strlen(szPassword), 0)
//通过散列生成一个会话密钥
CryptDeriveKey(hCryptProv, ENCRYPT_ALGORITHM,hHash, KEYLENGTH, &hKey))
//销毁Hash对象
CryptDestroyHash(hHash);
注: 会话密钥即对称密钥,用于对原文件进行加密;非对称密钥由于效率非常低,所以一般不用于对数据直接加密,而是对会话密钥进行加密,然后把它传送给对方。对 方通过非对称密钥解密获得这个会话密钥,然后再对数据文件进行解密。可以看出,一个会话密钥的生存期可以限制在这次通信中,即每次通信都用不同的会话密钥 加密,而非对称密钥则必须是长期使用的。在此例中,加解密过程中没有使用到非对称 RSA密钥对,而只在数字签名及验证使用它。
d) 加密数据文件
CryptEncrypt(
hKey, //密钥
0, //如果数据同时进行散列和加密,这里传入一个散列对象
feof(hSource), //如果是最后一个被加密的块,输入TRUE.如果不是输
//入FALSE这里通过判断是否到文件尾来决定是否为最后一块
0, //保留
pbBuffer, //输入被加密数据,输出加密后的数据
&dwCount, //输入被加密数据实际长度,输出加密后数据长度
dwBufferLen) //pbBuffer的大小
注:查看完整代码时可以发现这是一个循环加密的过程,pbBuffer循环读入待加密文件的固定长度的内存块;当然你也可以将pbBuffer设得很大,一次读入整个文件,但那样浪费内存空间,而且影响扩展性(存在缓冲区溢出的可能)。
e) 清理工作,如释放Buffer空间、密钥句柄、CSP句柄等。
if(pbBuffer)
free(pbBuffer);
if(hKey)
CryptDestroyKey(hKey);
if(hHash)
CryptDestroyHash(hHash);
if(hCryptProv)
CryptReleaseContext(hCryptProv, 0);
解密文件:
a) 打开加密文件(同上)
b) 取得密钥容器(CSP)句柄(同上)
c) 根据用户输入的密码创建一个会话密钥(即对称密钥,用于对原文件解密)(同上)
注: 这里要求用户输入的密码与加密时输入的密码相同。在实际应用中,这个所谓用户输入的“密码”其实只是一个产生密钥的种子,一旦产生完会话密钥,则用户完全 可以忘记当初输入的“密码”,接收方可以使用传过来的密钥直接对加密文件进行解密,而不用再重复一次“生成密钥”的过程。
d) 解密数据文件
CryptDecrypt(
hKey, //密钥
0, //如果数据同时进行散列和加密,这里传入一个散列对象
feof(hSource), //如果是最后一个被加密的块,输入TRUE.如果不是输.
//入FALSE这里通过判断是否到文件尾来决定是否为最后一块。
0, //保留
pbBuffer, //输入被加密数据,输出加密后的数据
&dwCount)) //输入被加密数据实际长度,输出加密后数据长度
e) 清理工作,如释放Buffer空间、密钥句柄、CSP句柄等。
签名文件:
a) 打开源文件(同上)
b) 取得密钥容器(CSP)句柄(同上)
c) 取得签名用的密钥句柄(非对称RSA密钥)
CryptGetUserKey(
hCryptProv, // 我们已经得到的CSP句柄
AT_SIGNATURE, // 这里想得到signature key pair
&hKey)) // 返回密钥句柄
d) 导出签名用密钥对的公钥,保存在pbKeyBlob中
CryptExportKey(hKey, NULL,PUBLICKEYBLOB, 0, pbKeyBlob,&dwBlobLen)
e) 计算数据文件的Hash值,保存在Hash对象hHash中
//生成一个空的Hash对象
CryptCreateHash(hCryptProv,CALG_MD5,0,0,&hHash)
//计算数据文件的Hash值,保存在Hash对象中
CryptHashData(hHash,pbBuffer,dwCount,0)
f) 对数据文件的Hash值进行签名,数字签名保存在pbSignature中
CryptSignHash(hHash, AT_SIGNATURE, NULL, 0, pbSignature, &dwSigLen)
g) 清理工作,如释放Buffer空间、密钥句柄、CSP句柄等。
签名文件:
a) 打开源文件(同上)
b) 取得密钥容器(CSP)句柄(同上)
c) 取得签名用的密钥句柄(非对称RSA密钥)
CryptGetUserKey(
hCryptProv, // 我们已经得到的CSP句柄
AT_SIGNATURE, // 这里想得到signature key pair
&hKey)) // 返回密钥句柄
d) 导出签名用密钥对的公钥,保存在pbKeyBlob中
CryptExportKey(hKey, NULL,PUBLICKEYBLOB, 0, pbKeyBlob,&dwBlobLen)
e) 计算数据文件的Hash值,保存在Hash对象hHash中
//生成一个空的Hash对象
CryptCreateHash(hCryptProv,CALG_MD5,0,0,&hHash)
//计算数据文件的Hash值,保存在Hash对象中
CryptHashData(hHash,pbBuffer,dwCount,0)
f) 对数据文件的Hash值进行签名,数字签名保存在pbSignature中
CryptSignHash(hHash, AT_SIGNATURE, NULL, 0, pbSignature, &dwSigLen)
g) 清理工作,如释放Buffer空间、密钥句柄、CSP句柄等。(同上)
验证签名:
a) 打开文件(同上)
b) 取得密钥容器(CSP)句柄(同上)
c) 导入 pbKeyBlob 公钥
CryptImportKey(hCryptProv, pbKeyBlob, dwBlobLen, 0, 0, &hPubKey)
注:必须是与签名时所用的私钥配对的公钥,在此例中,这个公钥在生成数字签名时已经导出到pbKeyBlob中。
d) 计算数据文件的Hash值,保存在Hash对象hHash中。(同上)
e) 验证数字签名
CryptVerifySignature(hHash, pbSignature, dwSigLen,hPubKey,NULL, 0)
f) 清理工作,如释放Buffer空间、密钥句柄、CSP句柄等。(同上)
(2)PKCS#11
根据机制标记,可以分为几类:
CKF_ENCRYPT:加密类
CKF_DECRYPT:解密类
CKF_DIGEST:摘要类
CKF_SIGN:签名类
CKF_SIGN_RECOVER:可恢复签名类
CKF_VERIFY:验证类
CKF_VERIFY_RECOVER:可恢复验证类
CKF_GENERATE:密钥产生
CKF_GENERATE_KEY_PAIR:密钥对产生
CKF_WRAP:密钥封装
CKF_UNWRAP:密钥解封
CKF_DERIVE:密钥派生
(3)GMT 0016-2012
(4)GMT 0018-2012
下列文件对于本文件的应用是必不可少的。凡是注日期的引用文件,仅注日期的版本适用于本文件,凡是不注日期的引用文件,其最新版本(包括所有的修单)适用于本文件,
GM/T0006 密码应用标识规范 和GM/T0009 SM2密码算法使用规范
3、以龙脉GM3000Key为例,写出调用不同接口的代码(Crypto API,PKCS#11,SKF接口),把运行截图加入博客,并提供代码链接
(1)Crypto API
二、PKCS#11实现
DES:
DES3:
RC2:
RC4:
RSA:
AES:
三、SKF接口实现
龙脉GM3000Key调用不同接口的 代码
1、SKF,encryptData.sin
#include "../../include/skfapi.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Win32Dlg.h"
#define TRUE 1
#define FALSE 0
#define ERROR_THROW(r) {if((r) != SAR_OK) goto END_OF_FUN;}
#pragma comment(lib, "../../lib/mtoken_gm3000.lib")
void main()
{
ULONG ulRslt = SAR_OK;
HANDLE hdev = NULL;
HANDLE happ = NULL;
HANDLE hcont = NULL;
HANDLE hkey = NULL;
char szDevName[256] = {0};
char szAppName[256] = {0};
char szContName[256] = {0};
char pUserPin[64] = {'0', '1', '2', '3', '4', '5', '6', '\0'};
ULONG ulDevNameLen = 256;
ULONG ulAppNameLen = 256;
ULONG ulContNameLen = 256;
ULONG ulRetryCount = 0;
BYTE pbData[2048] = {0};
BYTE pbEncryptedData[2048] = {0};
BYTE *pbEncrypted_ptr = pbEncryptedData;
ULONG ulEncryptedDataLen = 2048;
ECCPUBLICKEYBLOB ecc_pub = {0};
PECCCIPHERBLOB pecc_cipher = NULL;
ULONG ulEccpubLen = sizeof(ECCPUBLICKEYBLOB);
BLOCKCIPHERPARAM bp = {0};
ulRslt = SKF_EnumDev(TRUE, szDevName, &ulDevNameLen);
ERROR_THROW(ulRslt)
char *pdevname = szDevName;
ulRslt = SKF_ConnectDev(pdevname, &hdev);
ERROR_THROW(ulRslt)
ulRslt = SKF_EnumApplication(hdev, szAppName, &ulAppNameLen);
ERROR_THROW(ulRslt)
char *pappname = szAppName;
ulRslt = SKF_OpenApplication(hdev, pappname, &happ);
ERROR_THROW(ulRslt)
{
CWin32Dlg dlg;
if(dlg.RegisterClass())
{
return ;
}
if(dlg.CreateInstance())
{
return ;
}
while(dlg.ProcessNextMessage())
{
}
memset(pUserPin, 0 , sizeof(pUserPin));
strncpy(pUserPin, dlg.GetPin(), 64);
}
ulRslt = SKF_VerifyPIN(happ, USER_TYPE, pUserPin, &ulRetryCount);
ERROR_THROW(ulRslt)
ulRslt = SKF_EnumContainer(happ, szContName, &ulContNameLen);
ERROR_THROW(ulRslt)
char *pcontname = szContName;
ulRslt = SKF_OpenContainer(happ, pcontname, &hcont);
ERROR_THROW(ulRslt)
//公钥从证书解析
ulRslt = SKF_ExportPublicKey(hcont, FALSE, (BYTE *)&ecc_pub, &ulEccpubLen);
ERROR_THROW(ulRslt)
//此处需要保存Cipher,解密时需要导入
pecc_cipher = (PECCCIPHERBLOB)malloc(sizeof(ECCCIPHERBLOB) + 64);
memset(pecc_cipher, 0, sizeof(ECCCIPHERBLOB) + 64);
ulRslt = SKF_ECCExportSessionKey(hcont, SGD_SM1_ECB, &ecc_pub, pecc_cipher, &hkey);
ERROR_THROW(ulRslt)
//根据加密模式设定IV
memcpy(bp.IV, "12345678", 8);
bp.IVLen = 8;
bp.PaddingType = 1;
ulRslt = SKF_LockDev(hdev, 0xFFFFFFFF);
ERROR_THROW(ulRslt)
ulRslt = SKF_EncryptInit(hkey, bp);
if(ulRslt != SAR_OK)
{
SKF_UnlockDev(hdev);
goto END_OF_FUN;
}
//分组计算时,SKF_EncryptUpdate每包数据长度为1024字节时,计算速度最快
ulRslt = SKF_EncryptUpdate(hkey, pbData, 1024, pbEncrypted_ptr, &ulEncryptedDataLen);
if(ulRslt != SAR_OK)
{
SKF_UnlockDev(hdev);
goto END_OF_FUN;
}
pbEncrypted_ptr += ulEncryptedDataLen;
ulEncryptedDataLen = 1024;
ulRslt = SKF_EncryptFinal(hkey, pbEncrypted_ptr, &ulEncryptedDataLen);
if(ulRslt != SAR_OK)
{
SKF_UnlockDev(hdev);
goto END_OF_FUN;
}
ulRslt = SKF_UnlockDev(hdev);
END_OF_FUN:
if(hkey != NULL)
SKF_CloseHandle(hkey);
if(hcont != NULL)
SKF_CloseContainer(hcont);
if(happ != NULL)
SKF_CloseApplication(happ);
if(hdev != NULL)
SKF_DisConnectDev(hdev);
if(pecc_cipher != NULL)
{
free(pecc_cipher);
pecc_cipher = NULL;
}
return ;
}
2、Crypto API
EncryptFile.sln
#include "generic.h"
#include <cstdio>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
bool EncryptFile(const string &strSource,
const string &strDestination,
const string &strPassword);
//--------------------------------------------------------------------
// Begin main.
void main(void)
{
char szSrcFile[1024] = {0}; //sourcefile
char szTgtFile[1024] = {0}; //encryptfile
char szPassword[1024] = {0}; //password
printf("\nEncrypt a file.\n\nEnter the name of the file to be encrypt:\n");
scanf("%s", szSrcFile);
printf("Enter the name of the output file:\n");
scanf("%s", szTgtFile);
printf("Enter the password to encrypt the file:\n");
scanf("%s", szPassword);
if(EncryptFile(szSrcFile, szTgtFile, szPassword))
{
printf("Encrypt file successfully.\n");
}
else
{
printf("Encrypt file failed.\n");
}
}
//--------------------------------------------------------------------
// Code for the function EncryptFile called by main.
bool EncryptFile(const string &strSource,
const string &strDestination,
const string &strPassword)
{
//--------------------------------------------------------------------
// Declare and initialize local variables.
FILE *hSource = NULL;
FILE *hDestination = NULL;
HCRYPTPROV hCryptProv = NULL;
HCRYPTKEY hKey = NULL;
HCRYPTHASH hHash = NULL;
//--------------------------------------------------------------------
// Open source file.
BeginAction("Open source file for read");
if(NULL != (hSource = fopen(strSource.c_str(), "rb")))
{
ActionSuccess();
}
else
{
ActionFailed(GetLastError());
return FALSE;
}
//--------------------------------------------------------------------
// Open destination file.
BeginAction("Open target file for write");
if(NULL != (hDestination = fopen(strDestination.c_str(), "wb")))
{
ActionSuccess();
}
else
{
ActionFailed(GetLastError());
return FALSE;
}
// Get a CSP handle.
BeginAction("CryptAcquireContext()");
if(CryptAcquireContext(&hCryptProv,
TEST_CONTAINER,
CSP_NAME,
PROV_RSA_FULL,
0))
{
ActionSuccess();
}
else // Container does not exists, let us create a new one.
{
ActionFailed(GetLastError());
BeginAction("CryptAcquireContext() CRYPT_NEWKEYSET");
if(CryptAcquireContext(&hCryptProv,
TEST_CONTAINER,
CSP_NAME,
PROV_RSA_FULL,
CRYPT_NEWKEYSET))
{
ActionSuccess();
}
else
{
ActionFailed(GetLastError());
return FALSE;
}
}
HCRYPTPROV_Holder holder(hCryptProv);
BeginAction("CryptCreateHash()");
if(CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash))
{
ActionSuccess();
}
else
{
ActionFailed(GetLastError());
return FALSE;
}
BeginAction("CryptHashData()");
if(CryptHashData(hHash,
(BYTE *) strPassword.c_str(),
strPassword.length(),
0))
{
ActionSuccess();
}
else
{
ActionFailed(GetLastError());
return FALSE;
}
BeginAction("CryptDeriveKey()");
if(CryptDeriveKey(hCryptProv, ENCRYPT_ALGORITHM, hHash, KEYLENGTH, &hKey))
{
ActionSuccess();
}
else
{
ActionFailed(GetLastError());
return FALSE;
}
BeginAction("CryptDestroyHash()");
if(CryptDestroyHash(hHash))
{
hHash = NULL;
ActionSuccess();
}
else
{
ActionFailed(GetLastError());
return FALSE;
}
DWORD dwBlockLen = 0;
DWORD dwBufferLen = 0;
DWORD dwCount = 0;
dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
//--------------------------------------------------------------------
// Determine the block size. If a block cipher is used,
// it must have room for an extra block.
if(ENCRYPT_BLOCK_SIZE > 1)
{
dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE;
}
else
{
dwBufferLen = dwBlockLen;
}
vector<BYTE> pbBuffer;
pbBuffer.resize(dwBufferLen);
//--------------------------------------------------------------------
// In a do loop, encrypt the source file and write to the source file.
do
{
//--------------------------------------------------------------------
// Read up to dwBlockLen bytes from the source file.
dwCount = fread(&pbBuffer[0], 1, dwBlockLen, hSource);
if(ferror(hSource))
{
ShowSysError("Read plain text", GetLastError());
return FALSE;
}
//--------------------------------------------------------------------
// Encrypt
if(!CryptEncrypt(hKey,
0,
feof(hSource), //file end
0,
&pbBuffer[0], // [in] sourcefile; [out] encryptdata
&dwCount, //encryptdatalength
dwBufferLen)) // encrypt data length
{
ShowSysError("CryptEncrypt()", GetLastError());
return FALSE;
}
//--------------------------------------------------------------------
// Write data to the destination file.
fwrite(&pbBuffer[0], 1, dwCount, hDestination);
if(ferror(hDestination))
{
ShowSysError("Write cipher text", GetLastError());
return FALSE;
}
}
while(!feof(hSource));
//--------------------------------------------------------------------
// End the do loop when the last block of the source file has been
// read, encrypted, and written to the destination file.
//--------------------------------------------------------------------
// Close files.
if(hSource)
{
fclose(hSource);
}
if(hDestination)
{
fclose(hDestination);
}
if(hKey)
{
CryptDestroyKey(hKey);
}
return TRUE;
} // End of Encryptfile
EnumCerts.sln
#include <windows.h>
#include <wincrypt.h>
#include <iostream>
#define CSP_NAME "Longmai mToken GM3000 CSP V1.1"
using namespace std;
int main(int argc, char* argv[])
{
HCRYPTPROV hCryptProv = NULL;
cout << "Attempt to acquire context for CSP...";
if(!CryptAcquireContext(
&hCryptProv,
NULL,
CSP_NAME,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT
))
{
cout << endl << "Can't acquire context, Error code = 0x" << hex << GetLastError() << dec << endl;
return -1;
}
else
cout << "OK." << endl;
HCERTSTORE hCertStore = NULL;
cout << "Attempt to open the certificate storage...";
hCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM, // The store provider type.
0, // The encoding type is not needed.
hCryptProv, // Use the epassNG HCRYPTPROV.
CERT_SYSTEM_STORE_CURRENT_USER,
L"MY"
);
if(NULL == hCertStore)
{
cout << endl << "Can't open certificates store. Error code = 0x" << hex << GetLastError() << dec << endl;
}
else
cout << "OK." << endl;
// Enum the certficates. pCertContext must be NULL at the first time.
PCCERT_CONTEXT pCertContext = NULL;
DWORD dwTotalCert = 0;
while(pCertContext = CertEnumCertificatesInStore( hCertStore, pCertContext))
{
if(NULL == pCertContext)
break;
//////////////////////////////////////////////////////////////////////////
// How to get the subject name, see below:
// First we must get the length of the subject name.
DWORD dwNameLen = 0;
dwNameLen = CertGetNameString(
pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0, NULL, NULL, 0
);
if(0 == dwNameLen)
{
cout << "Can't get the subject name of the certificate." << endl;
break;
}
// Now let's alloc memory for the subject name.
char* pszTemp = NULL;
pszTemp = new char[dwNameLen + 1]; // Plus 1 to hold the '\0'.
if(NULL == pszTemp)
break;
ZeroMemory(pszTemp, dwNameLen + 1);
// Second call to CertGetNameString() to get the subject name.
if(CertGetNameString(
pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
NULL,
pszTemp,
dwNameLen + 1))
{
cout << "Oh, the subject name is : " << pszTemp << endl;
}
// Free the memory allocated for the subject name.
delete[] pszTemp;
pszTemp = NULL;
++dwTotalCert;
// Ok, we got the subject name.
//////////////////////////////////////////////////////////////////////////
}
if(0 == dwTotalCert)
{
cout << "No certficate find." << endl;
}
// Close the store.
if(CertCloseStore(hCertStore, 0))
{
cout << "Store closed. All information free." << endl;
}
else
{
cout << "Store closed. But some information in use." << endl;
}
getchar();
return 0;
}
3、PKCS#11
PKCStest.sln
#include "AESTest.h"
#include "common.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
AESTest::AESTest(char* dll_file_path):CBaseAll(dll_file_path)
{
m_hKey = 0;
}
AESTest::~AESTest()
{
}
void AESTest::Test()
{
if(CKR_OK != BaseAllStart())
return;
GenerateKey();
if(m_hKey == 0)
{
BaseAllEnd();
return ;
}
crypt_Single();
crypt_Update();
BaseAllEnd();
}
void AESTest::GenerateKey()
{
do{
SHOW_INFO("Generate Des key to test...");
CK_OBJECT_CLASS oClass = CKO_SECRET_KEY;
CK_KEY_TYPE keyType = CKK_AES;
CK_BBOOL bTrue = true;
CK_BBOOL bFalse = false;
CK_ULONG ulLen = 16;
CK_MECHANISM mechanism = {CKM_AES_KEY_GEN, NULL_PTR, 0};
CK_ATTRIBUTE Destem[] = {
{CKA_CLASS, &oClass, sizeof(CK_OBJECT_CLASS)},
{CKA_KEY_TYPE, &keyType, sizeof(CK_KEY_TYPE)},
{CKA_TOKEN, &bFalse, sizeof(CK_BBOOL)},
{CKA_PRIVATE, &bTrue, sizeof(CK_BBOOL)},
{CKA_ENCRYPT, &bTrue, sizeof(CK_BBOOL)},
{CKA_DECRYPT, &bTrue, sizeof(CK_BBOOL)},
{CKA_VALUE_LEN, &ulLen, sizeof(CK_ULONG)},
};
CK_ULONG ulCount = 7;
//generate key:
START_OP("generate AES key...")
CK_RV rv = m_gToken->C_GenerateKey(hSession, &mechanism, Destem, ulCount, &m_hKey);
CHECK_OP(rv)
}while(0);
}
void AESTest::crypt_Single()
{
const CK_ULONG DATA_LENGTH = 1024*3;
CK_BYTE bIn[DATA_LENGTH] = {0}, bTemp[DATA_LENGTH] = {0}, bOut[DATA_LENGTH] = {0};
CK_ULONG ulIn = 0, ulOut = 0, ulTemp = 0;
CK_ULONG Mechanism[3] = {CKM_AES_CBC, CKM_AES_ECB, CKM_AES_CBC_PAD};
CK_BYTE_PTR bHint[3] = {(CK_BYTE_PTR)"CKM_AES_CBC: ",\
(CK_BYTE_PTR)"CKM_AES_ECB: ",
(CK_BYTE_PTR)"CKM_AES_CBC_PAD: "};
SHOW_INFO("\nAES: C_Encrypt/C_Decrypt: \n");
for(int i=0;i<3;i++)
{
ulIn = 1024;
if(i==2)//pad
ulIn = 1000;
for(register CK_ULONG i0 = 0;i0<ulIn;i0++)
bIn[i0] = (CK_BYTE)i0;
SHOW_INFO("\n* * * * * * * * * * * \n");
SHOW_INFO(bHint[i]);
//ecnrypt init:
CK_BYTE iv[16] = {'*','2','1','0','4','z','y','b','*','2','1','0','4','z','y','b'};
CK_MECHANISM ckMechanism = {Mechanism[i], iv, 16};
START_OP("Encrypting initialize.")
CK_RV rv = m_gToken->C_EncryptInit(hSession, &ckMechanism, m_hKey);
CHECK_OP(rv)
START_OP("Encrypt the message.")
//Get the encrypted buffer's size:
//{{{Here, I do not invoke "C_Encrypt" twice for I had declared bTemp with a size=1024.
//If you do not declare the result's buffer previous,
//you should invoke twice to get the buffer's size, such as:[Decrypt is similar]
rv = m_gToken->C_Encrypt(hSession, bIn, ulIn, NULL, &ulTemp);
//}}}
CheckRV("C_Encrypt[get buffer's size]", rv);
//encrypt:
rv = m_gToken->C_Encrypt(hSession, bIn, ulIn, bTemp, &ulTemp);
CheckRV("C_Encrypt", rv);
CHECK_OP(rv);
SHOW_INFO("Data encrypted: \n");
ShowData(bTemp, ulTemp);
START_OP("Decrypting initialize.");
rv = m_gToken->C_DecryptInit(hSession, &ckMechanism, m_hKey);
CHECK_OP(rv);
START_OP("Decrypt the message.");
//Get buffer's size:
rv = m_gToken->C_Decrypt(hSession, bTemp, ulTemp, NULL, &ulOut);
//Get decrypted data:
rv = m_gToken->C_Decrypt(hSession, bTemp, ulTemp, bOut, &ulOut);
CHECK_OP(rv);
SHOW_INFO("Data decrypted: \n");
ShowData(bOut, ulOut);
START_OP("Compare the original message and decrypted data: ");
if(0 == memcmp(bIn, bOut, ulOut))
{
CHECK_OP(CKR_OK);
}
else
{
SHOW_INFO("....[FAILED]\n");
}
}
}
void AESTest::crypt_Update()
{
const CK_ULONG DATA_LENGTH = 1024*3;
CK_BYTE bIn[DATA_LENGTH] = {0}, bTemp[DATA_LENGTH] = {0}, bOut[DATA_LENGTH] = {0};
CK_ULONG ulIn = 0, ulOut = 0, ulTemp = 0;
CK_ULONG Mechanism[3] = {CKM_AES_CBC, CKM_AES_ECB, CKM_AES_CBC_PAD};
CK_BYTE_PTR bHint[3] = {(CK_BYTE_PTR)"CKM_AES_CBC: ",\
(CK_BYTE_PTR)"CKM_AES_ECB: ",\
(CK_BYTE_PTR)"CKM_AES_CBC_PAD: "};
SHOW_INFO("\n* * * * * * * * * * * * * * * *\n");
for(int i=0;i<3;i++)
{
ulIn = 1024;
if(i == 2)
{//PAD
ulIn = 1000;
}
for(register CK_ULONG i0 = 0;i0<ulIn;i0++)
bIn[i0] = (CK_BYTE)i0;
SHOW_INFO("\n");
SHOW_INFO("\nAES: C_EncryptUpdate/C_DecryptUpdate: \n");
SHOW_INFO(bHint[i]);
//ecnrypt init:
CK_BYTE iv[16] = {'*','2','1','0','4','z','y','b','*','2','1','0','4','z','y','b'};
CK_MECHANISM ckMechanism = {Mechanism[i], iv, sizeof(iv)};
START_OP("Encrypting initialize.")
CK_RV rv = m_gToken->C_EncryptInit(hSession, &ckMechanism, m_hKey);
CHECK_OP(rv)
CK_ULONG ulEncrypted = 0;
START_OP("Encrypt the message.");
//invoked twice:
const CK_ULONG ulEnc1stPice = 33;
rv = m_gToken->C_EncryptUpdate(hSession, bIn, ulEnc1stPice, NULL, &ulTemp);//get buffer's size.
rv = m_gToken->C_EncryptUpdate(hSession, bIn, ulEnc1stPice, bTemp, &ulTemp);
//}}}
CheckRV("C_Encrypt[get buffer's size]", rv);
ulEncrypted+=ulTemp;
ulTemp = 0;
//encrypt:
//invoked twice:
rv = m_gToken->C_EncryptUpdate(hSession, &(bIn[ulEnc1stPice]), ulIn-ulEnc1stPice, NULL, &ulTemp);//get buffer's size.
rv = m_gToken->C_EncryptUpdate(hSession, &(bIn[ulEnc1stPice]), ulIn-ulEnc1stPice, &(bTemp[ulEncrypted]), &ulTemp);
CheckRV("C_Encrypt", rv);
CHECK_OP(rv);
ulEncrypted+=ulTemp;
ulTemp = 0;
START_OP("C_EncryptFinal...");
rv = m_gToken->C_EncryptFinal(hSession, NULL, &ulTemp);//Get buffer's size:
rv = m_gToken->C_EncryptFinal(hSession, &(bTemp[ulEncrypted]), &ulTemp);
CHECK_OP(rv);
ulEncrypted+=ulTemp;
ulTemp = 0;
SHOW_INFO("Data encrypted: \n");
ShowData(bTemp, ulEncrypted);
START_OP("Decrypting initialize.");
rv = m_gToken->C_DecryptInit(hSession, &ckMechanism, m_hKey);
CHECK_OP(rv);
START_OP("Decrypt the message.");
CK_ULONG ulDecrypt = 0;
const CK_ULONG ulDec1stPice = 17;
rv = m_gToken->C_DecryptUpdate(hSession, bTemp, ulDec1stPice, NULL, &ulOut);//Get buffer's size
rv = m_gToken->C_DecryptUpdate(hSession, bTemp, ulDec1stPice, bOut, &ulOut);
ulDecrypt +=ulOut;
ulOut = 0;
//Get decrypted data:
rv = m_gToken->C_DecryptUpdate(hSession, &(bTemp[ulDec1stPice]), ulEncrypted-ulDec1stPice, NULL, &ulOut);//Get buffer's size
rv = m_gToken->C_DecryptUpdate(hSession, &(bTemp[ulDec1stPice]), ulEncrypted-ulDec1stPice, &(bOut[ulDecrypt]), &ulOut);
CHECK_OP(rv);
ulDecrypt +=ulOut;
ulOut = 0;
START_OP("C_DecryptFinale...");
rv = m_gToken->C_DecryptFinal(hSession, NULL, &ulOut);//Get buffer's size
rv = m_gToken->C_DecryptFinal(hSession, &(bOut[ulDecrypt]), &ulOut);
CHECK_OP(rv);
ulDecrypt +=ulOut;
SHOW_INFO("Data decrypted: \n");
ShowData(bOut, ulDecrypt);
START_OP("Compare the original message and decrypted data: ");
if(0 == memcmp(bIn, bOut, ulDecrypt))
{
CHECK_OP(CKR_OK);
}
else
{
SHOW_INFO("....[FAILED]\n");
}
}
}
getusbinfos.sln
#include "stdafx.h"
#include "getinfos.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define PKCS_LIB_NAME "gm3000_pkcs11.dll"
//Initialize the token Cryptoki library:
CGetInfos::CGetInfos():m_hDll(NULL_PTR)
{
m_path = PKCS_LIB_NAME;
}
//Free the token Cryptoki library:Finish.
CGetInfos::~CGetInfos()
{
//if load library failed ,but m_pToke is NULL, so call C_Finalize will be wrong
if(m_pToken != NULL)
{
m_pToken->C_Finalize(NULL_PTR);
m_pToken = NULL_PTR;
}
if(m_hDll)
{
FreeLibrary(m_hDll);
}
}
unsigned long CGetInfos::GetSlotInfos(CK_SLOT_INFO_PTR pSlotInfo)
{
CK_RV rv = CKR_OK;
CK_ULONG ulCount = 0;
CK_SLOT_ID_PTR pSlotList = NULL_PTR;
rv = m_pToken->C_GetSlotList(FALSE, NULL_PTR, &ulCount);
if((rv != CKR_OK) || (ulCount <= 0))
return CKR_DEVICE_ERROR;
pSlotList = (CK_SLOT_ID_PTR)new CK_SLOT_ID [ulCount];
if (pSlotList == NULL_PTR)
{
return CKR_HOST_MEMORY;
}
rv = m_pToken->C_GetSlotList(FALSE, pSlotList, &ulCount);
if((rv != CKR_OK) || (ulCount <= 0))
{
delete [] pSlotList;
pSlotList = NULL_PTR;
return CKR_SLOT_ID_INVALID;
}
/*Get slot information for the first slot*/
for (unsigned int i = 0; i < ulCount; ++i)
{
rv = m_pToken->C_GetSlotInfo(pSlotList[i], pSlotInfo);
if(rv != CKR_OK)
{
delete [] pSlotList;
pSlotList = NULL_PTR;
return CKR_FUNCTION_FAILED;
}
//ShowSlotInfo(pSlotInfo);
}
delete [] pSlotList;
pSlotList = NULL_PTR;
return CKR_OK;
}
unsigned long CGetInfos::GetTokenInfos(CK_TOKEN_INFO_PTR pTokenInfo)
{
CK_RV rv = CKR_OK;
CK_ULONG ulCount = 0;
CK_SLOT_ID_PTR pSlotList = NULL_PTR;
rv = m_pToken->C_GetSlotList(TRUE, NULL_PTR, &ulCount);
if((rv != CKR_OK) || (ulCount <= 0))
return CKR_DEVICE_ERROR;
pSlotList = (CK_SLOT_ID_PTR)new CK_SLOT_ID [ulCount];
rv = m_pToken->C_GetSlotList(TRUE, pSlotList, &ulCount);
if((rv != CKR_OK) || (ulCount <= 0))
{
delete [] pSlotList;
pSlotList = NULL_PTR;
return CKR_TOKEN_NOT_PRESENT;
}
/*Get slot information for the first token*/
for (unsigned int i = 0; i < ulCount; ++i)
{
rv = m_pToken->C_GetTokenInfo(pSlotList[i], pTokenInfo);
if(rv != CKR_OK)
{
delete [] pSlotList;
pSlotList = NULL_PTR;
return CKR_FUNCTION_FAILED;
}
//ShowTokenInfo(pTokenInfo);
}
delete [] pSlotList;
pSlotList = NULL_PTR;
return CKR_OK;
}
bool CGetInfos::CheckRV(const char* szInfo, unsigned long rv)
{
printf(szInfo);
if(CKR_OK == rv)
{
//printf(" ... OK.\n");
return true;
}
printf(" ... FAILED. ");
switch(rv)
{
case CKR_SLOT_ID_INVALID:
printf("[CKR_SLOT_ID_INVALID]");
break;
case CKR_TOKEN_NOT_PRESENT:
printf("[CKR_TOKEN_NOT_PRESENT]");
break;
case CKR_FUNCTION_FAILED:
printf("[CKR_FUNCTION_FAILED]");
break;
case CKR_DEVICE_ERROR:
printf("[CKR_DEVICE_ERROR]");
break;
case CKR_HOST_MEMORY:
printf("[CKR_HOST_MEMORY]");
break;
default:
printf("[Unknown ERROR: 0x%08X]", rv);
}
printf("\n");
return false;
}
void CGetInfos::ShowSlotInfo(CK_SLOT_INFO_PTR slotinfo)
{
printf("\nSlot information:\n");
char DescBuffer[65] = {0};
memcpy(DescBuffer,slotinfo->slotDescription,64);
DescBuffer[64] = 0;
int i = 0;
for(i = 63; i > 0; --i)
if(' ' == DescBuffer[i])
DescBuffer[i] = '\0';
else
break;
printf("\tSlotDescription = %s\n", DescBuffer);
char manuBuffer[33] = {0};
memcpy(manuBuffer,slotinfo->manufacturerID,32);
manuBuffer[32] = 0;
for(i = 31; i > 0; --i)
if(' ' == manuBuffer[i])
manuBuffer[i] = '\0';
else
break;
printf("\tManufacturerID = %s\n", manuBuffer);
printf("\tFlags = %08X\n", slotinfo->flags);
printf("\tFirmwareVersion.major = %d\n", slotinfo->firmwareVersion.major);
printf("\tFirmwareVersion.minor = %d\n", slotinfo->firmwareVersion.minor);
printf("\tHardwareVersion.major = %d\n", slotinfo->hardwareVersion.major);
printf("\tHardwareVersion.minor = %d\n\n", slotinfo->hardwareVersion.minor);
}
void CGetInfos::ShowTokenInfo(CK_TOKEN_INFO_PTR tokenInfo)
{
printf("\nToken information:\n");
char label[33] = {0};
memcpy(label, tokenInfo->label, 32);
printf("\tLabel = %s\n", label);
char manuBuffer[33] = {0};
memcpy(manuBuffer,tokenInfo->manufacturerID,32);
manuBuffer[32] = 0;
printf("\tManufacturerID = %s\n", manuBuffer);
char modelBuffer[17] = {0};
memcpy(modelBuffer,tokenInfo->model,16);
manuBuffer[16] = 0;
printf("\tModel = %s\n", modelBuffer);
char SNBuffer[17] = {0};
memcpy(SNBuffer,tokenInfo->serialNumber,16);
manuBuffer[16] = 0;
printf("\tSerialNumber = %s\n", SNBuffer);
printf("\tFlags = 0x%08X\n", tokenInfo->flags);
printf("\tulMaxSessionCount = %d\n", tokenInfo->ulMaxSessionCount);
printf("\tulSessionCount = %d\n", tokenInfo->ulSessionCount);
printf("\tulMaxRwSessionCount = %d\n",tokenInfo->ulMaxRwSessionCount);
printf("\tulRwSessionCount = %d\n",tokenInfo->ulRwSessionCount);
printf("\tulMaxPinLen = %d\n",tokenInfo->ulMaxPinLen);
printf("\tulMinPinLen = %d\n",tokenInfo->ulMinPinLen);
printf("\tulTotalPublicMemory = %d\n", tokenInfo->ulTotalPublicMemory);
printf("\tulTotalPrivateMemory = %d\n", tokenInfo->ulTotalPrivateMemory);
printf("\tulFreePublicMemory = %d\n", tokenInfo->ulFreePublicMemory);
printf("\tulFreePrivateMemory = %d\n", tokenInfo->ulFreePrivateMemory);
printf("\tHardwareVersion.major = %d\n", tokenInfo->hardwareVersion.major);
printf("\tHardwareVersion.minor = %d\n", tokenInfo->hardwareVersion.minor);
printf("\tFirmwareVersion.major = %d\n", tokenInfo->firmwareVersion.major);
printf("\tFirmwareVersion.minor = %d\n", tokenInfo->firmwareVersion.minor);
printf("\tToken utcTime = %d\n", 0);
}
unsigned long CGetInfos::GetCryptokiInfos(CK_INFO_PTR pInfo)
{
memset(pInfo, 0, sizeof(pInfo));
if(m_pToken->C_GetInfo(pInfo) != CKR_OK)
{
return CKR_FUNCTION_FAILED;
}
return CKR_OK;
}
void CGetInfos::ShowCryptokiInfos(CK_INFO_PTR pInfo)
{
printf("\nCryptoki informations:\n");
printf("\tCryptokiVersion.major = %d\n", pInfo->cryptokiVersion.major);
printf("\tCryptokiVersion.minor = %d\n", pInfo->cryptokiVersion.minor);
printf("\tLibraryVersion.major = %d\n", pInfo->libraryVersion.major);
printf("\tLibraryVersion.minor = %d\n", pInfo->libraryVersion.minor);
printf("\tFlags = 0x%08X\n", pInfo->flags);
char LibDescBuffer[33] = {0};
memcpy(LibDescBuffer,pInfo->libraryDescription,32);
LibDescBuffer[32] = 0;
printf("\tLibraryDescription = %s\n", LibDescBuffer);
char manuBuffer[33] = {0};
memcpy(manuBuffer,pInfo->manufacturerID,32);
manuBuffer[32] = 0;
printf("\tManufacturerID = %s\n\n", manuBuffer);
}
bool CGetInfos::LoadLib()
{
#if defined(WIN32)
m_hDll = LoadLibrary(m_path);
#else
m_hDll = dlopen(m_path, RTLD_NOW);
#endif
if(m_hDll == NULL_PTR)
{
printf("Load Library Error!");
return false;
}
typedef CK_RV (* C_GETFUNCTIONLISTPROC)(CK_FUNCTION_LIST_PTR_PTR);
C_GETFUNCTIONLISTPROC pC_GetFunctionList = (C_GETFUNCTIONLISTPROC)GetProcAddress(m_hDll,"C_GetFunctionList");
if(pC_GetFunctionList == NULL_PTR)
{
printf("Get function list failed.\n");
return false;
}
if(CKR_OK!=pC_GetFunctionList(&m_pToken))
{
printf("Get function list failed.\n");
return false;
}
if(CKR_OK != m_pToken->C_Initialize(NULL_PTR))
{
printf("Call C_Initialize failed.\n");
return false;
}
return true;
}
0 2人一组,创建一个文件,文件名为小组成员学号,内容为小组成员学号和姓名
1 在Ubuntu中使用OpenSSL用SM4算法加密上述文件,然后用龙脉eKey解密,提交代码和运行结果截图
2 在Ubuntu中基于OpenSSL产生一对公私钥对(SM2算法)
3 在Ubuntu中使用OpenSSL用SM3算法计算上述文件的Hash值,然后用OpenSSL SM2算法计算Hash值的签名,用龙脉eKey进行验签,提交代码和运行结果截图
4 加分项:在Windows中重现上述过程
1. 在Ubuntu中使用OpenSSL用SM4算法加密上述文件,然后用龙脉eKey解密,提交代码和运行结果截图
加密
代码:
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
void tEVP_Encrypt()
{
unsigned char key[EVP_MAX_KEY_LENGTH]; //密钥
unsigned char iv[EVP_MAX_KEY_LENGTH];//初始化向量
EVP_CIPHER_CTX* ctx;//EVP算法上下文
unsigned char out[1024];//输出密文缓冲区
int outl;//密文长度
int outltmp;
const char *msg="20201225zxp";//待加密的数据
int rv;
int i;
//初始化函数才能用!
ctx = EVP_CIPHER_CTX_new();
//设置key和iv(可以采用随机数和可以是用户输入)
for(i=0;i<24;i++)
{
key[i]=i;
}
for(i=0;i<8;i++)
{
iv[i]=i;
}
//初始化密码算法结构体
EVP_CIPHER_CTX_init(ctx);
//设置算法和密钥以
rv = EVP_EncryptInit_ex(ctx,EVP_sm4_cbc(),NULL,key,iv);
if(rv!=1)
{
printf("Err\n");
return;
}
//数据加密
rv = EVP_EncryptUpdate(ctx,out,&outl,(const unsigned char*)msg,strlen(msg));
if(rv!=1)
{
printf("Err\n");
return;
}
//结束数据加密,把剩余数据输出。
rv = EVP_EncryptFinal_ex(ctx,out+outl,&outltmp);
if(rv!=1)
{
printf("Err\n");
return;
}
outl = outl +outltmp;
printf("原文为:%s\n",msg);
//打印输出密文
printf("密文长度:%d\n密文数据:\n",outl);
for(i=0;i<outl;i++)
{
printf("0x%02x ",out[i]);
}
printf("\n");
}
int main()
{
OpenSSL_add_all_algorithms();
tEVP_Encrypt();
return 0;
}
用龙脉eKey解密
代码
#include "skfapi.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
extern "C"
{
int sm4_self_test(HANDLE hdev);
int main()
{
HANDLE hdev = NULL;
char szDevName[256] = {0};
ULONG ulDevNameLen = 256;
SKF_EnumDev(TRUE, szDevName, &ulDevNameLen);
SKF_EnumDev(TRUE, szDevName, &ulDevNameLen);
SKF_EnumDev(TRUE, szDevName, &ulDevNameLen);
SKF_ConnectDev(szDevName, &hdev);
printf("connected \n");
sm4_self_test(hdev);
return 0;
}
int sm4_self_test(HANDLE hdev)
{
UINT8 Cipher[32] = {0x6d,0xde,0xaf,0x2c,0x3d,0xff,0x44,0xc2,0x2d,0x71,0xb8,0x56,0x8d,0xae,0x3e,0x72,0xa0,0x2e,0x8b,0xb6,0x78,0x5f,0x60,0x7d,0x49,0x86,0x61,0xef,0x6d,0xcf,0xa8,0x2,};
UINT8 TempData[32] = {0};
ULONG TempLen = sizeof(TempData);
UINT8 key[16] = {0x32,0x30,0x32,0x30,0x31,0x32,0x30,0x31,
0x32,0x30,0x32,0x30,0x31,0x32,0x30,0x32};
HANDLE hkey = NULL;
BYTE iv[64] = {0};
BLOCKCIPHERPARAM bp = {0};
SKF_SetSymmKey(hdev, key, SGD_SM4_ECB, &hkey);
bp.PaddingType = 0;
memcpy(bp.IV,iv, 8);
bp.IVLen = 8;
SKF_DecryptInit(hkey, bp);
SKF_Decrypt(hkey, Cipher, sizeof(Cipher), TempData, &TempLen);
int i;
for(i=0;i<32;i++) printf("0x%x ",TempData[i]);
return 0;
}
}
2. 在Ubuntu中基于OpenSSL产生一对公私钥对(SM2算法)
3.在Ubuntu中使用OpenSSL用SM3算法计算上述文件的Hash值,然后用OpenSSL SM2算法计算Hash值的签名,用龙脉eKey进行验签
加分项:在Windows中重现上述过程
在windows下中使用OpenSSL用SM4算法加密上述文件
基于OpenSSL产生一对公私钥对(SM2算法)
SM3算法签名
电子公文传输系统安全性设计与实现
电子公文传输系统的设计部分:
一、设计目标
提高行政工作效率:电子公文传输系统可以实现电子化办公,减少了纸质公文的使用和传输,缩短了传输时间,节约了人力和物力资源,提高了办公效率。
提高行政工作质量:电子公文传输系统可以实现对管理员的密码进行加密管理,保证了公文系统的安全性。保障公文的真实性和保密性,降低了公文信息泄露的风险,提高了办公质量。
提高行政工作透明度:电子公文传输系统可以实现公文流转的透明化和公开化,方便了行政机关内部和社会公众对公文流转进程和结果的监督和评价。在系统中的每个用户能够根据自己的权限看到,相关的信息。密级高的信息则是进行了严格保密的的。
实现行政信息化:电子公文传输系统可以与行政机关管理信息系统相连,我们的公文传输系统有着一键归档的功能,通过建立归档的文件夹,然后将内容进行归档处理,实现公文信息的自动化管理和处理,提高了行政管理的科学化和规范化水平。
降低行政成本:电子公文传输系统可以减少纸张、印章、快递、邮寄等行政成本,同时也加快了公文传输速度,降低了行政工作的成本和时间成本。
二、组成内容
公文系统的组成包括以下内容:
1. 文件格式:公文系统应支持各种常见的公文格式,包括红头、版面等。在文件传输和下载时使用PDF格式,防止被篡改和保证文件传输时不出现格式改变。
2. 文件接收:公文系统的接收功能可实现电子公文接收、扫描件接收,接收范围按照用户权限设置,收到公文后可进入收文箱,在公文处理完成后进入文件归档。
3. 文件归档:公文系统的文件归档功能可将文件按照用户设定的规则进行归档,例如按照发文时间、文件类型等分类归档,同时支持打标签、搜索等高级功能。
4. 文件发送:公文系统的发送功能可以将已写好的公文文件发送给指定人员或者部门,在发送时可以进行安全控制,确保公文安全。
5. 管理员用户功能:公文系统应提供管理员用户功能,管理员能够管理公文系统的基础数据,例如机构、用户、角色、权限等的管理。
6. 公文写作:公文系统应支持公文的写作、编辑、格式控制、附件管理,公文撰写过程中应有自动保存功能,避免因为操作失误导致数据丢失。
综上所述,我们组队公文系统是一个涵盖公文的整个生命周期的系统,包括公文的接收、审核、处理、发送、归档、查询等功能,同时支持各种常见的公文格式,提高公文处理效率,真正实现电子化办公。
三、架构设计
公文系统的组成包括前端、后端和数据库三部分:
前端主要由View层编写,包括网页端的界面设计、呈现和交互逻辑等。
界面设计:设计公文系统界面的样式和布局,进行交互元素的处理,包括页面头部、底部、导航条、按钮等元素,以及页面表格、列表等的样式设计和排版。
交互逻辑:制定前端交互逻辑,设定页面的流程和功能,包括用户登录、公文查看、公文编辑、公文流转等功能的处理。
后端主要由Bath或其他编程语言编写,包括服务器端的逻辑处理,数据库管理、安全保障等。
服务器端逻辑:负责公文系统所有接口的实现,包括用户登录、公文编辑、公文查询、公文权限控制、公文流转等功能的实现。
数据库管理:使用数据库管理工具navicat对公文系统的整体数据库进行管理,包括公文信息、用户信息、日志信息等的存储和管理。
安全保障:负责公文系统的安全保障措施,包括安全验证、加解密处理、访问控制等。
我们的公文系统采用前后端分离的架构,通过API进行前后端数据的传递和交互。同时也需要进行系统测试和维护,确保公文系统的正常运行和稳定性。
四、下一步改进
1.增加业务逻辑:公文系统应该根据实际的业务需求,增加相应的业务逻辑,例如增加会议管理、工作计划等功能,从而实现更加全面的业务覆盖。
2.强化安全保障:公文系统中的安全保障措施应该更加完善,例如增加对公文的数字签名、加密、认证等安全控制,防止信息泄露和篡改。
3.提高效率:公文系统应该在处理效率方面进行优化,例如增加自动化流程控制和批量处理功能,缩短公文处理时间,提高办公效率。
4.优化用户体验:公文系统应该优化用户体验,例如提高系统的响应速度,改善界面设计,加强用户教育和培训等。
5.数据可视化分析:公文系统应该增加数据可视化分析功能,例如统计公文的处理状态和效率,分析公文流程的瓶颈,提供数据支持决策。
电子公文传输系统的实现部分:
一、系统概述
我们的电子公文传输系统一共由13个网页组成:
- login.js
这段代码是一个前端代码中常用的API接口请求代码,使用的库是http,其中包括了多个函数,分别用于不同的请求类型:
apiGetCaptcha:用于获取验证码图片的函数,使用的是get请求,参数为params;
apiLogin:用于用户登录的函数,使用的是post请求,参数为params;
apiAdminLogin:用于管理员登录的函数,使用的是post请求,参数为params;
apiLogout:用于用户注销登录的函数,使用的是post请求,参数为params;
apiSendCodeMsg:用于向用户发送验证码的函数,使用的是get请求,参数为params;
apiForgetPassword:用于用户忘记密码后找回密码的函数,使用的是post请求,参数为params;
apiRegister:用于用户注册的函数,使用的是post请求,参数为params。
这些函数都是用于与后端接口进行交互,完成各种用户操作的。例如,用户登录、注册、找回密码等操作都需要通过这些函数与后端接口进行交互,从而实现用户的操作需要
CategoryAPI.js
这段代码是一组用于学科管理的API接口,其主要功能是实现对学科的增删改查等操作。
这些API接口是通过调用一个名为"http"的模块来实现网络请求的。该模块提供了get、post、put等方法来实现不同的网络请求方式。通过调用这些API接口,可以实现对学科列表的管理,包括增删改查、申请、审核等操作。
logAPI.js
本段代码主要实现了对日志的增加、修改、删除、查询等操作,并分别对应不同的接口地址。
总的来说,这段代l码提供了完整的日志管理的接口,方便开发者进行业务开发,并且提供了各种接口来满足不同需求的使用。
lorgAPI.js
该代码段是一个学科组织的RESTful API接口集合。使用了JavaScript语言编写,后端应该采用了Node.js技术。其中,使用了模块化的技术,导出各个接口函数。
可以看出,该代码段主要用于管理学科组织,提供了非常丰富的API接口,可以满足各种需求。开发者可以根据自己的实际需求进行接口的选择和使用。
UserAPI.js
上述代码是一个使用Vue框架的前端项目中的一部分,其中定义了一些关于用户管理的API接口。
其中,apiUserList接口用于获取用户列表,apiUserPage接口用于获取分页后的用户列表,apiUserListAll接口用于获取所有用户信息,apiUserOne接口用于获取单个用户信息,apiUserSelf接口用于获取当前用户的信息,apiUserAdd接口用于新增用户,apiUserUpdate接口用于更新用户信息,apiUserCharge接口用于用户充值,apiUserDel接口用于删除用户,apiUserBan接口用于禁用用户。
这些接口都是通过http请求访问后端API服务进行数据的增删改查操作。在前端项目中,这些API接口将被应用于用户管理模块,使用户能够进行相应的用户管理操作。
FileTypeAPI.js
以上代码是一个文件类型管理的API接口,包含对文件类型的增删改查等操作。总体而言,这些API接口提供了文件类型管理相关的各种操作,并且针对不同的用户和角色,提供了不同层次的数据访问权限控制。
FileSendAPI.js
这段代码是一个文件传输模块的接口API,主要包括以下功能:
文件传输列表的获取:通过调用apiFileSendList和apiFileSendSelf函数,以GET方法获取文件传输列表,区别在于apiFileSendList获取整个列表,而apiFileSendSelf获取与用户相关的列表。
文件传输页面的获取:通过调用apiFileSendPage函数,以GET方法获取指定页数和页大小的文件传输列表。
文件传输的添加:通过调用apiFileSendAdd函数,以POST方法添加一条文件传输记录。
文件传输的更新:通过调用apiFileSendUpdate函数,以PUT方法更新一条文件传输记录。
文件传输的删除:通过调用apiFileSendDel函数,以DELETE方法删除一条文件传输记录。
文件传输的审核:通过调用apiFileSendChecked函数,以GET方法获取需要审核的文件传输列表。
文件传输的申请:通过调用apiFileSendApply函数,以GET方法获取需要申请的文件传输列表。
文件传输的关闭:通过调用apiFileSendClose函数,以GET方法关闭指定的文件传输。
用户相关文件传输的获取:通过调用apiFileSendEmpSelf函数,以GET方法获取与用户相关的文件传输列表。
文件传输的接受和拒绝:通过调用apiFileSendAccept和apiFileSendUnAccept函数,以GET方法接受或拒绝指定的文件传输。
FileCategoryListAPI.js
上述代码是一个前端项目中的API接口,通过调用定义的各个API函数,可以获取或发送对应的HTTP请求。
以上的API接口主要是用于文件分类列表相关的操作。其中,apiFileCategoryListList函数是获取文件分类列表并分页的函数;apiFileCategoryListAdd函数是新增一个文件分类的函数;apiFileCategoryListUpdate函数是更新某个文件分类的函数;apiFileCategoryListDel函数是删除某个文件分类的函数。
还有其他的函数,比如apiFileCategoryListSelf函数,可以获取用户自己创建的文件分类列表;apiFileCategoryListChecked函数,可以获取被选中的文件分类;apiFileCategoryListApply函数,可以获取当前申请的文件分类;apiFileCategoryListClose函数,可以关闭某个文件分类。
总之,
以上的API接口覆盖了文件分类列表的基本操作,可以方便地实现对文件分类的管理。
FileCategoryAPI.js
上述代码涉及到一个文件类别管理的相关 API 接口,在具体实现上,这些功能都是通过向服务器发送不同的 HTTP 请求实现的,请求的路径和参数不同,从而区分不同的功能。其中使用到的 HTTP 请求库为 http,从前端代码中看不出具体实现方式。
FileAPI.js
上述代码是一个文件管理系统的前端接口请求模块,包含了一系列的API请求函数。
其中http和request是基于axios库进行封装的请求方法,params为请求参数。通过调用这些请求函数,能够实现与后端API进行数据交互的功能,实现文件管理系统的各项操作。
二、系统底层架构
1.Base controller
该代码为一个基础的控制器类,用于对某个实体类进行 CRUD 操作。其中根据要求实现了增加、分页、按 id 查找、按 id 删除和更新等常用操作,并在每个操作前使用了一个自定义注解 @LogAnno 来记录日志。其中要求实现的方法有:
save 方法,用于新增实体,接受一个 E 类型的参数,返回一个保存成功的消息。
list 方法,用于分页查询实体,接受两个 int 类型的参数 currentPage 和 size,返回一个 IPage<E> 类型的结果。
detail 方法,用于根据 id 查询实体,接受一个 Serializable 类型的参数 id,返回一个 R<E> 类型的结果。
delete 方法,用于根据 id 删除实体,接受一个 List<Serializable> 类型的参数 ids,返回一个删除成功的消息。
update 方法,用于更新实体,接受一个 E 类型的参数,返回一个更新成功的消息。
page 方法,用于分页查询实体并根据名字模糊查询,接受三个参数:int 类型的 page 和 pageSize,和一个字符串类型的 name,返回一个 R<Page> 类型的结果。
2.Category controller
本段代码是一个Java后端控制器类,用于处理与“类别”相关的请求。首先,它导入了一些需要用到的类和注解,并继承了一个BaseController类,说明它是一个实际处理请求的类。然后,它定义了一个CategoryService对象,并在listAll()方法中使用了LambdaQueryWrapper查询所有类别并返回。接下来,它使用了一个自定义的LogAnno注解,在delete()方法中记录了删除操作的日志,该方法会根据传入的id列表删除对应的数据,并在删除之前检查是否有属于该类别的用户存在,如果存在则返回错误信息,否则返回删除成功信息。这个类是整个类别管理模块的核心,处理了所有和类别有关的请求,包括添加、删除、查询和修改等。
3.Code controller
本文介绍了一个验证码控制器CodeController,使用了Spring框架进行开发。在这个控制器中,我们应用了注解和Kaptcha库,通过生成一张带有验证码的图片来防止机器人或恶意攻击者对网站进行攻击。
首先,我们需要引入一些依赖项和库。这个程序使用了com.google.code.kaptcha库来生成带有验证码的图片,并且使用了Lombok库来避免繁琐的日志记录。我们也使用了Spring的注解和依赖注入机制。这些库能够让我们更快、更加轻松地实现这个功能。
方法开始部分,我们首先设置了响应头的一些选项,阻止了浏览器对验证码图片进行缓存。接下来我们使用captchaProducer.createText()方法生成了图像上的验证码文本,并使用HttpSession API将文本存储到了会话中以便后续使用。然后,我们使用captchaProducer.createImage()方法根据验证码文本生成了一张验证码图片,并使用ImageIO.write()方法将其写入到响应的输出流中。
最后,我们在try-catch代码块中完成输出操作,并将输出流使用out.close()方法关闭,释放资源。
4.Common controller
本文介绍了一个用于文件上传和下载的通用控制器 CommonController。其中,使用了注解技术以及上传文件的 API 和操作下载文件的方法。
代码的核心功能是文件上传和下载。在代码中,实现了上传文件的功能。使用 File 类的对象将文件保存到给定的目录中。其次,提供了下载文件的方法,方法中,通过 FileInputStream 类和 ServletOutputStream 类,将指定目录下的文件发送到客户端,从而实现下载功能。
总体而言,CommonController 通过简洁的代码实现了文件上传和下载的功能,使用了注解、API 等技术手段使程序更加健壮,功能更加完善,很好地完成了上传和下载文件的任务。
5.File category controller
这份代码是一个文件分类控制器,其中定义了一些对文件分类的操作方法。
其中,第一个方法是listAll(),它通过LambdaQueryWrapper查询所有的文件分类,并通过R类进行封装并返回。
第二个方法是listSelf(),它通过LambdaQueryWrapper查询当前用户的所有文件分类,并通过R类进行封装并返回。
第三个方法是save(),它是一个POST请求,用于向数据库中新增一条文件分类信息。它首先会对新增的文件分类名称进行非空判断和是否已存在的校验,然后将当前用户ID设置到新增的文件分类中,并通过QueryWrapper进行查询,如果查询结果不为0,则返回错误信息,否则将新增的文件分类信息保存到数据库中,并通过R类进行封装并返回保存成功的信息。
整个代码实现了对文件分类的查询和新增操作,同时通过注解的方式实现了操作日志的记录。
6.File category list controller
该类中包含了两个主要的方法,一个是归档操作的方法,一个是按条件查询并分页显示列表的方法。
归档操作的方法将接收到的参数解析成文件和分类的id,然后构造一个文件分类对象,指定用户id,查询数据库中是否已有该文件分类的记录,如果有则更新记录,否则新增一条记录。最后返回一个成功的消息。
列表查询方法接收到分页和查询条件的参数,首先构造一个查询对象,在lambda表达式中指定查询条件,然后调用服务类的getVO方法获取指定页面的结果,并将结果封装成一个R对象返回给前端。在方法上加上了@LogAnno注解,用来记录用户浏览归档的行为。
7.Filesendcontroller
本文介绍了一个文件收发管理系统的Java代码,主要包含了文件收发的发送、接受、拒绝以及管理员和用户浏览文件信息的功能实现。对于发送文件,用户可以向指定接收者发送文件,发送成功后更新状态;对于接受文件,用户可以确认接受,管理员可以浏览所有文件信息;对于拒绝文件,用户可以拒绝该文件;对于浏览文件接收,用户和管理员可以根据条件进行筛选和浏览。
8.File type controller
以上代码是一个针对加密类别的控制器,在此控制器中,我们使用了MyBatis-Plus提供的LambdaQueryWrapper来构建查询条件,并使用baseService的list方法来查询所有的加密类别。在listAll方法中,我们将查询结果封装在R.success中,最终返回给前端。
9.Log controller
本文介绍了Java语言中的一个控制器类,该类可以对应用程序中的“日志”进行管理和操作。
这个控制器类实现了一个基础控制器类,方法包括浏览日志。控制器类还包括了一个list方法,可以对分页进行处理,并且可以对日志名称进行查询。在list方法中,使用了MyBatis-Plus的LambdaQueryWrapper,这是一个用于构造查询条件的工具类。
10.Org controller
本代码是一个组织控制器,主要包括删除组织和获取组织列表的功能。
其中,删除组织功能需要先检查组织中是否有用户存在,如果有则不能删除,否则可以删除,并返回删除结果。这里使用了一个注解 @LogAnno,记录了删除操作的类型。
获取组织列表功能直接返回了所有的组织列表。
代码中还注入了一个 UserService 和一个 OrgService,用于组织相关操作的服务。
此外,控制器还继承了一个 BaseController,该类封装了通用的控制器方法。
11.Usercontroller
本代码主要功能是实现用户登录验证。用户提交登录信息后,首先会判断角色是否为空,若为空则返回角色不可为空;然后判断验证码是否失效,若验证码失效,则返回验证码失效;接着判断用户输入的验证码是否正确,若不正确则返回验证码错误。当用户信息正确时,首先对用户密码进行MD5加密,然后通过查询数据库进行用户匹配,若用户不存在则返回用户不存在,若密码错误则返回密码错误。当用户存在且密码正确时,进一步查询用户状态,若用户已被禁用则返回账号已禁用。最终,若用户登录成功,则将用户ID存储在Session中,并返回登录成功信息。
三、安全性措施
加密算法的选择
为保证密码方案的安全性,我们组在UserController类中,我们增加角色时需要将口令进行加密处理。由于密码长度通常不会很长,因此我们采用了MD5算法,对用户输入的口令进行哈希运算并存入数据库中。