当前位置: 首页 > news >正文

【安全加密】通信加密算法介绍

加密常用于通信中,如战争中电台通讯有明码和密码,密码需要不断更换密码本;另外,商用软件也需要用到加密技术,如根据电脑的mac地址设置权限,防止软件被恶意传播。

文章目录

    • 一、介绍
      • 1. 单向散列/哈希算法
      • 2. 对称加密算法
      • 3. 非对称加密算法
    • 二、加密算法实现
      • 1. 造轮子
        • AES算法
        • SM4算法
        • RSA算法
        • MD5
        • SHA-1
        • sm3
      • 2. openssl
      • 3. crypto++
        • AES算法:
        • DES算法:
        • RSA算法:
        • SHA-256算法:
      • 4. botan
      • 5. cryptlib
    • 三、性能与方案选择

一、介绍

信息加密技术是利用数学或物理手段,对电子信息在传输过程中和存储介质内进行保护,以防止泄露的技术。通信加密技术是信息加密技术的重要分支,是网络安全的重要组成部分。

加密就是通过密码算法对数据进行转化,使之成为没有正确密钥任何人都无法读懂的报文。而这些以无法读懂的形式出现的数据一般被称为密文。为了读懂报文,密文必须重新转变为它的最初形式——明文,而含有以数学方式转换报文的双重密码就是密钥。

通信加密技术早期采用单向散列(hash)算法,即明文加密成密文后,不能再解密成明文。这种算法一般用来存储密码等信息,验证密码时,需要将密码转成的密文与数据库中密文进行对比。知名的单向散列算法有MD5、CRC32和SHA-256。

但如果我们只想在传输过程加密,收到数据后还想将其转换成明文怎么办呢?

为了解决上述问题,对称加密算法出现了。明文通过对称加密算法的密钥加密成密文,密文又可以通过对称加密算法的密钥解密成明文,由于加密和解密过程使用同一把密钥,所以称为对称加密。服务端和客户端之间的加密就常用到对称加密算法。知名的对称加密算法有DES和AES。

但是这个密钥放在哪里呢?如果定义一个变量,客户端和服务端各放一份,我们在发送前肯定要对明文加密,别人很容易通过OD调试器追踪到密钥;如果只放在服务端,第一次通信时发过去,那别人也可以通过对客户端抓包找到密钥;还有就是把密钥也加密发过去,那密钥的密钥总是明文吧,那就成了套娃。

为了解决以上问题,非对称加密算法出现了。非对称加密算法很神奇,它采用了一对密钥,即公钥和私钥。对一串明文,如果你用公钥加密,就只能用私钥解密,而用私钥加密,就只能用公钥解密。但非对称加密过程很复杂,所以处理很慢,比对称加密慢几百倍,用于网络传输不现实。知名的非对称加密算法有RSA和ECC。

对称加密不能确保安全,非对称加密不能保证效率,那怎么办呢?

为了解决这个问题,混合加密策略出现了,即用非对称加密来解决对称加密的密钥传输,密钥传输完成后,A和B间采用对称加密算法通信。对称加密算法的密钥由服务端A生成,A把对称加密算法的密钥用B的公钥加密,B收到后用自己的私钥解密,即“公钥加密,私钥解密”,得到对称加密算法的密钥,AB都有对称加密的密钥了,双方就可以正常进行对称加密通信了。混合加密策略解决了窃听的问题,此外,为了防止被逆向跟踪,最好再搭配反调试+异步回调+多线程+时钟扰乱,增大逆向难度。

除了窃听,常见的安全问题还有篡改和冒充。

要解决这个问题,就来到了下面的数字签名技术。数字签名技术使用了hash算法和非对称加密算法。利用私钥加密,公钥如果能成功解密得到摘要,可以证明发送方的身份,防止冒充;对消息内容进行hash,得到摘要,经过摘要对比,可以检测是否被篡改。

服务端A向客户端B发送数据:先对明文使用hash算法,生成摘要(digest),对这个摘要用A的私钥(唯一性,防止冒充)加密,生成数字签名(signature),将“明文+数字签名”发送给B。

客户端B接收数据:对数字签名用A的公钥解密,得到摘要1;再对明文用hash算法,得到摘要2;对比摘要1和摘要2,若两者一致,说明数据确实是A发过来的。

问题都解决了吗?还没有。非对称加密时要先将A和B的公钥发送给对方,在这个公钥分发的过程中,可能会出现“中间人劫持”现象,即中间人C截获A和B的公钥,并将自己伪装成B和A分别和A和B通信,这样中间人C获得了完整的数据。

那么如何安全地分发公钥呢?即证明A的公钥确实是A的,B的公钥确实是B的呢?

现实世界中有公证处,而网络世界中也有这样一种具有公信力的组织,叫CA,它可以给服务端A颁发一个数字证书,上面有A的信息,包含A的公钥,这样如果拿到了证书,也就拿到了可信任的A的公钥。

那么,证书要怎么安全传输呢? 如果证书被篡改了怎么办?
现在的情况是,需要一种既要能判断公钥是否冒充,还要能判断数据是否被篡改的手段, 这不就是刚刚介绍的数字签名技术。具体操作其实就是把数字签名中的"明文"部分替换为 “数字证书”。客户端B向服务端A发送请求时,服务端A会返回自己数字证书给客户端B。CA公钥是内置在客户电脑中的。

以上就是对通信加密技术的简单介绍。

为了信息安全,我国也开发了国产密码算法,简称国密算法,是由国家密码局认定的拥有自主知识产权的密码算法,在目前应用广泛的有SM2、SM3、SM4

目前为止,共计有近200多种加密算法,按国际惯例,将这近200种算法按照双方收发的密钥是否相同的标准划分为两大类:一种是常规算法(也叫私钥加密算法或对称加密算法),其特征是收信方和发信方使用相同的密钥,即加密密钥和解密密钥是相同或等价的。常规密码的优点是有很强的保密强度,且经受住时间的检验和攻击,但其密钥必须通过安全的途径传送。因此,其密钥管理成为系统安全的重要因素。知名的私钥加密算法有:DES、3DES和AES。

另一种是公钥加密算法(也叫非对称加密算法),其特征是收信方和发信方使用的密钥互不相同,而且几乎不可能从加密密钥推导解密密钥。比较著名的公钥密码算法有:RSA、DSA和ECC等。公钥密码的优点是可以适应网络的开放性要求,且密钥管理问题也较为简单,尤其可方便的实现数字签名和验证。但其算法复杂,加密数据的速率较低。

纵观这两种算法,一个从DES到3DES再到ADES,一个从RSA到ECC。其发展角度无不是从密钥的简单性,成本的低廉性,管理的简易性,算法的复杂性,保密的安全性以及计算的快速性这几个方面去考虑。因此,未来算法的发展也必定是从这几个角度出发的,而且在实际操作中往往把这两种算法结合起来,或许将来一种集两种算法有点于一身的新型算法将会出现,到那时,数据通信必将更加快捷与安全。

1. 单向散列/哈希算法

单向散列函数(也称Hash函数)指的是根据输入消息计算后,输出固定长度数值的算法,输出数值也称为“散列值”或“消息摘要”,其长度通常在128~256位之间。

常用的单向散列算法有MD5、SHA-x系列、CRC系列等

MD5算法是指输入任意长度的信息,经过处理,输出为128位的信息(数字指纹);不同的输入得到不同的结果(唯一性);根据128位的输出结果不可能反推出输入的信息(不可逆)。对安全性要求不高的软件常用MD5算法。

CRC也叫循环冗余校验码,是数据通信领域常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算。我们都知道,反码求和法用的是加法,而CRC算法用的是“除法”,这里不是十进制除法,而是二进制的异或取余。CRC8最终的余数是8位,如果不满8位需要在高位补0,CRC32最终的余数则是32位。车辆通信报文校验常用CRC算法。

SHA算法是在MD4算法的基础上演变而来,由美国国家安全局设计,有SHA-1和SHA-2两个系列。安全性要求一般时采用SHA-1,安全性要求较高时则至少采用SHA-256算法,SHA-256是指任意长度的消息文件,通过SHA-256算法加密,最终得到的密文都是256位(32字节),通常用一个长度为64的十六进制字符串来表示。https签名算法使用的是带RSA加密的SHA-256算法。

SM3算法:哈希算法,适用于商用密码应用中的数字签名和验证消息认证码的生成与验证以及随机数的生成,可满足多种密码应用的安全需求。用于替换MD5、SHA-1等国际算法。为了保证杂凑算法的安全性,其产生的杂凑值的长度不应太短,例如MD5输出128比特杂凑值,输出长度太短,影响其安全性。SHA-1算法的输出长度为160比特,SM3算法的输出长度为256比特,因此SM3算法的安全性要高于MD5算法和SHA-1算法。

2. 对称加密算法

对称加密算法是应用较早的加密算法。在对称加密算法中,数据发信方将明文和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。

DES是IBM公司1977年为美国政府研制的一种算法。DES是以56位密钥为基础的密码块加密技术。它的加密过程一般如下:

  1. 一次性把64位明文块打乱置换;
  2. 把64位明文块拆成两个32位块;
  3. 用机密DES密钥把每个32位块打乱位置16次;
  4. 使用初始置换的逆置换。

但后来,DES被容易地破解,因此,美国推出DES的改进版本——三重加密(triple Data Encryption Standard,3DES)即在使用过程中,收发双方都用三把密钥进行加解密,无疑这种3*56式的加密算法大大提升了密码的安全性,按现在计算机的运算速度,这种破解几乎是不可能的。但是我们在为数据提供强有力的安全保护的同时,也要花更多的时间来对信息进行三次加密和对每个密层进行解密。同时在这种前提下,使用这种密钥的双发都必须拥有3个密钥,如果丢失了其中任何一把,其余两把都成了无用的密钥。这样私钥的数量一下又提升了3倍,这显然不是我们想看到的。

于是美国国家标准与技术研究所推出了一个新的保密措施来保护金融交易。高级加密标准(Advanced Encryption Standard,AES)美国国家技术标准委员会(NIST)在2000年10月选定了比利时的研究成果“Rijndael”作为AES的基础。AES内部有更简洁精确的数学算法,而加密数据只需一次通过。AES被设计成高速,坚固的安全性能,而且能够支持各种小型设备。AES与3DES相比,不仅是安全性能有重大差别,使用性能和资源有效利用上也有很大差别。

SM4算法:对称加密算法。主要用于无线局域网标准,用于替换DES/AES等算法。要保证一个对称密码算法的安全性的基本条件是其具备足够的密钥长度,SM4算法与AES算法具有相同的密钥长度分组长度128比特,因此在安全性上高于3DES算法。

3. 非对称加密算法

非对称加密算法是一种密钥的保密方法。非对称加密算法需要两个密钥:公开密钥 (publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法称为非对称加密算法。

面对在执行过程中如何使用和分享密钥及保持其机密性等问题,1975年Whitefield Diffe和Marti Hellman提出了公开的密钥密码技术的概念,被称为Diffie-Hellman技术。从此公钥加密算法便产生了。

由于采取了公共密钥,密钥的管理和分发就变得简单多了,对于一个n个用户的网络来说,只需要2n个密钥便可达到密度。同时使得公钥加密法的保密性全部集中在及其复杂的数学问题上,它的安全性因而也得到了保证。但是在实际运用中,公共密钥加密算法并没有完全的取代私钥加密算法。其重要的原因是它的实现速度远远赶不上私钥加密算法。又因为它的安全性,所以常常用来加密一些重要的文件。

根据所基于的数学难题来分类,有以下三类系统目前被认为是安全和有效的:大整数因子分解系统(代表性的有RSA)、椭圆曲线离散对数系统(ECC)和离散对数系统(代表性的有DSA)。

RSA系统是公钥系统的最具有典型意义的算法,大多数使用公钥密码进行加密和数字签名的产品和标准使用的都是RSA算法。它的具体算法如下:

  1. 找两个非常大的质数,越大越安全。把这两个质数叫做P和Q;
  2. 找一个能满足下列条件得数字E:A.是一个奇数;B.小于P×Q;C.与(P-1)×(Q-1)互质,只是指E和该方程的计算结果没有相同的质数因子;
  3. 计算出数值D,满足下面性质:((D×E)-1)能被(P-1)×(Q-1)整除。

公开密钥对是(P×Q,E);私人密钥是D;公开密钥是E。
解密函数是:
假设T是明文,C是密文。
加密函数用公开密钥E和模P×Q;
加密信息=(TE)模P×Q。
解密函数用私人密钥D和模P×Q;
解密信息=(CD)模P×Q。
椭圆曲线加密技术(ECC)是建立在单向函数(椭圆曲线离散对数)的基础上,由于它比RAS使用得离散对数要复杂得多,而且该单向函数比RSA得要难,所以与RSA相比,它有安全性高、计算量小、存储空间占用小、占用带宽低等优点。

在实现非对称加密RSA算法前,服务端A和客户端B都要先用openssl(开源密码库)生成自己的公钥和私钥。命令如下:

genrsa -out private_key.pem 2048 # 制作私钥
rsa -in private_key.pem -pubout -out public_key.pem # 制作公钥

注意,公钥是公开的,因此程序开始A和B会传输各自的公钥给对方。

通过RSA算法传输数据的流程如下:

A发送数据给B:A先把明文用B的公钥进行加密,这样除了B的私钥,其他都解不了密,B收到后,用自己的私钥解密,得到明文。

B发送数据给A:B把明文用A的公钥进行加密,A收到后,用自己的私钥解密得到明文。

规则就是:你要发给谁,就用谁的公钥加密,这样他收到后,只有他自己的私钥能解密。

远程ssh连接git账户时,生成密钥的算法就是RSA算法。

SM2算法:非对称加密算法。基于椭圆曲线密码(ECC)的公钥密码算法标准,提供数字签名、密钥交换和公钥加密。用于替换RSA等国际算法。SM2算法与RSA算法不同的是,SM2算法是基于椭圆曲线上点群离散对数难题,相对于RSA算法,256位的SM2密码强度已经比2048位的RSA密码强度要高。

二、加密算法实现

1. 造轮子

自己编写相关加密算法。

AES算法

一个基于C++的AES实现:https://github.com/Urban82/Aes256
aes.h

#ifndef AES_H
#define AES_H/*** 参数 p: 明文的字符串数组。* 参数 plen: 明文的长度,长度必须为16的倍数。* 参数 key: 密钥的字符串数组。*/
void aes(char *p, int plen, char *key);/*** 参数 c: 密文的字符串数组。* 参数 clen: 密文的长度,长度必须为16的倍数。* 参数 key: 密钥的字符串数组。*/
void deAes(char *c, int clen, char *key);#endif

aes.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "aes.h"void aes(char *p, int plen, char *key);
void deAes(char *c, int clen, char *key);
/*** S盒*/
static const int S[16][16] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };/*** 逆S盒*/
static const int S2[16][16] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };/*** 获取int数据的低8位的左4个位*/
static int getLeft4Bit(int num) {int left = num & 0x000000f0;return left >> 4;
}/*** 获取int数据的低8位的右4个位*/
static int getRight4Bit(int num) {return num & 0x0000000f;
}
/*** 根据索引,从S盒中获得元素*/
static int getNumFromSBox(int index) {int row = getLeft4Bit(index);int col = getRight4Bit(index);return S[row][col];
}/*** 把一个字符转变成整型*/
static int getIntFromChar(char c) {int result = (int) c;return result & 0x000000ff;
}/*** 把16个字符转变成4X4的数组,* 该矩阵中字节的排列顺序为从上到下,* 从左到右依次排列。*/
static void convertToIntArray(char *str, int pa[4][4]) {int k = 0;for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++) {pa[j][i] = getIntFromChar(str[k]);k++;}
}/*** 打印4X4的数组*/
static void printArray(int a[4][4]) {for(int i = 0; i < 4; i++){for(int j = 0; j < 4; j++)printf("a[%d][%d] = 0x%x ", i, j, a[i][j]);printf("\n");}printf("\n");
}/*** 打印字符串的ASSCI,* 以十六进制显示。*/
static void printASSCI(char *str, int len) {for(int i = 0; i < len; i++)printf("0x%x ", getIntFromChar(str[i]));printf("\n");
}/*** 把连续的4个字符合并成一个4字节的整型*/
static int getWordFromStr(char *str) {int one = getIntFromChar(str[0]);one = one << 24;int two = getIntFromChar(str[1]);two = two << 16;int three = getIntFromChar(str[2]);three = three << 8;int four = getIntFromChar(str[3]);return one | two | three | four;
}/*** 把一个4字节的数的第一、二、三、四个字节取出,* 入进一个4个元素的整型数组里面。*/
static void splitIntToArray(int num, int array[4]) {int one = num >> 24;array[0] = one & 0x000000ff;int two = num >> 16;array[1] = two & 0x000000ff;int three = num >> 8;array[2] = three & 0x000000ff;array[3] = num & 0x000000ff;
}/*** 将数组中的元素循环左移step位*/
static void leftLoop4int(int array[4], int step) {int temp[4];for(int i = 0; i < 4; i++)temp[i] = array[i];int index = step % 4 == 0 ? 0 : step % 4;for(int i = 0; i < 4; i++){array[i] = temp[index];index++;index = index % 4;}
}/*** 把数组中的第一、二、三和四元素分别作为* 4字节整型的第一、二、三和四字节,合并成一个4字节整型*/
static int mergeArrayToInt(int array[4]) {int one = array[0] << 24;int two = array[1] << 16;int three = array[2] << 8;int four = array[3];return one | two | three | four;
}/*** 常量轮值表*/
static const unsigned int Rcon[10] = { 0x01000000, 0x02000000,0x04000000, 0x08000000,0x10000000, 0x20000000,0x40000000, 0x80000000,0x1b000000, 0x36000000 };
/*** 密钥扩展中的T函数*/
static int T(int num, int round) {int numArray[4];splitIntToArray(num, numArray);leftLoop4int(numArray, 1);//字循环//字节代换for(int i = 0; i < 4; i++)numArray[i] = getNumFromSBox(numArray[i]);int result = mergeArrayToInt(numArray);return result ^ Rcon[round];
}//密钥对应的扩展数组
static int w[44];/*** 扩展密钥,结果是把w[44]中的每个元素初始化*/
static void extendKey(char *key) {for(int i = 0; i < 4; i++)w[i] = getWordFromStr(key + i * 4);for(int i = 4, j = 0; i < 44; i++) {if( i % 4 == 0) {w[i] = w[i - 4] ^ T(w[i - 1], j);j++;//下一轮}else {w[i] = w[i - 4] ^ w[i - 1];}}}/*** 轮密钥加*/
static void addRoundKey(int array[4][4], int round) {int warray[4];for(int i = 0; i < 4; i++) {splitIntToArray(w[ round * 4 + i], warray);for(int j = 0; j < 4; j++) {array[j][i] = array[j][i] ^ warray[j];}}
}/*** 字节代换*/
static void subBytes(int array[4][4]){for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++)array[i][j] = getNumFromSBox(array[i][j]);
}/*** 行移位*/
static void shiftRows(int array[4][4]) {int rowTwo[4], rowThree[4], rowFour[4];//复制状态矩阵的第2,3,4行for(int i = 0; i < 4; i++) {rowTwo[i] = array[1][i];rowThree[i] = array[2][i];rowFour[i] = array[3][i];}//循环左移相应的位数leftLoop4int(rowTwo, 1);leftLoop4int(rowThree, 2);leftLoop4int(rowFour, 3);//把左移后的行复制回状态矩阵中for(int i = 0; i < 4; i++) {array[1][i] = rowTwo[i];array[2][i] = rowThree[i];array[3][i] = rowFour[i];}
}/*** 列混合要用到的矩阵*/
static const int colM[4][4] = { 2, 3, 1, 1,1, 2, 3, 1,1, 1, 2, 3,3, 1, 1, 2 };static int GFMul2(int s) {int result = s << 1;int a7 = result & 0x00000100;if(a7 != 0) {result = result & 0x000000ff;result = result ^ 0x1b;}return result;
}static int GFMul3(int s) {return GFMul2(s) ^ s;
}static int GFMul4(int s) {return GFMul2(GFMul2(s));
}static int GFMul8(int s) {return GFMul2(GFMul4(s));
}static int GFMul9(int s) {return GFMul8(s) ^ s;
}static int GFMul11(int s) {return GFMul9(s) ^ GFMul2(s);
}static int GFMul12(int s) {return GFMul8(s) ^ GFMul4(s);
}static int GFMul13(int s) {return GFMul12(s) ^ s;
}static int GFMul14(int s) {return GFMul12(s) ^ GFMul2(s);
}/*** GF上的二元运算*/
static int GFMul(int n, int s) {int result;if(n == 1)result = s;else if(n == 2)result = GFMul2(s);else if(n == 3)result = GFMul3(s);else if(n == 0x9)result = GFMul9(s);else if(n == 0xb)//11result = GFMul11(s);else if(n == 0xd)//13result = GFMul13(s);else if(n == 0xe)//14result = GFMul14(s);return result;
}
/*** 列混合*/
static void mixColumns(int array[4][4]) {int tempArray[4][4];for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++)tempArray[i][j] = array[i][j];for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++){array[i][j] = GFMul(colM[i][0],tempArray[0][j]) ^ GFMul(colM[i][1],tempArray[1][j]) ^ GFMul(colM[i][2],tempArray[2][j]) ^ GFMul(colM[i][3], tempArray[3][j]);}
}
/*** 把4X4数组转回字符串*/
static void convertArrayToStr(int array[4][4], char *str) {for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++)*str++ = (char)array[j][i];	
}
/*** 检查密钥长度*/
static int checkKeyLen(int len) {if(len == 4)return 1;elsereturn 0;
}/*** 参数 p: 明文的字符串数组。* 参数 plen: 明文的长度。* 参数 key: 密钥的字符串数组。*/
void aes(char *p, int plen, char *key){int keylen = strlen(key);if(plen == 0 || plen % 4 != 0) {printf("明文字符长度必须为4的倍数!\n");exit(0);}if(!checkKeyLen(keylen)) {printf("密钥字符长度错误!长度必须为16、24和32。当前长度为%d\n",keylen);exit(0);}extendKey(key);//扩展密钥int pArray[4][4];for(int k = 0; k < plen; k += 16) {	convertToIntArray(p + k, pArray);addRoundKey(pArray, 0);//一开始的轮密钥加for(int i = 1; i < 10; i++){//前9轮subBytes(pArray);//字节代换shiftRows(pArray);//行移位mixColumns(pArray);//列混合addRoundKey(pArray, i);}//第10轮subBytes(pArray);//字节代换shiftRows(pArray);//行移位addRoundKey(pArray, 10);convertArrayToStr(pArray, p + k);}
}
/*** 根据索引从逆S盒中获取值*/
static int getNumFromS1Box(int index) {int row = getLeft4Bit(index);int col = getRight4Bit(index);return S2[row][col];
}
/*** 逆字节变换*/
static void deSubBytes(int array[4][4]) {for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++)array[i][j] = getNumFromS1Box(array[i][j]);
}
/*** 把4个元素的数组循环右移step位*/
static void rightLoop4int(int array[4], int step) {int temp[4];for(int i = 0; i < 4; i++)temp[i] = array[i];int index = step % 4 == 0 ? 0 : step % 4;index = 3 - index;for(int i = 3; i >= 0; i--) {array[i] = temp[index];index--;index = index == -1 ? 3 : index;}
}/*** 逆行移位*/
static void deShiftRows(int array[4][4]) {int rowTwo[4], rowThree[4], rowFour[4];for(int i = 0; i < 4; i++) {rowTwo[i] = array[1][i];rowThree[i] = array[2][i];rowFour[i] = array[3][i];}rightLoop4int(rowTwo, 1);rightLoop4int(rowThree, 2);rightLoop4int(rowFour, 3);for(int i = 0; i < 4; i++) {array[1][i] = rowTwo[i];array[2][i] = rowThree[i];array[3][i] = rowFour[i];}
}
/*** 逆列混合用到的矩阵*/
static const int deColM[4][4] = { 0xe, 0xb, 0xd, 0x9,0x9, 0xe, 0xb, 0xd,0xd, 0x9, 0xe, 0xb,0xb, 0xd, 0x9, 0xe };/*** 逆列混合*/
static void deMixColumns(int array[4][4]) {int tempArray[4][4];for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++)tempArray[i][j] = array[i][j];for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++){array[i][j] = GFMul(deColM[i][0],tempArray[0][j]) ^ GFMul(deColM[i][1],tempArray[1][j]) ^ GFMul(deColM[i][2],tempArray[2][j]) ^ GFMul(deColM[i][3], tempArray[3][j]);}
}
/*** 把两个4X4数组进行异或*/
static void addRoundTowArray(int aArray[4][4],int bArray[4][4]) {for(int i = 0; i < 4; i++)for(int j = 0; j < 4; j++)aArray[i][j] = aArray[i][j] ^ bArray[i][j];
}
/*** 从4个32位的密钥字中获得4X4数组,* 用于进行逆列混合*/
static void getArrayFrom4W(int i, int array[4][4]) {int index = i * 4;int colOne[4], colTwo[4], colThree[4], colFour[4];splitIntToArray(w[index], colOne);splitIntToArray(w[index + 1], colTwo);splitIntToArray(w[index + 2], colThree);splitIntToArray(w[index + 3], colFour);for(int i = 0; i < 4; i++) {array[i][0] = colOne[i];array[i][1] = colTwo[i];array[i][2] = colThree[i];array[i][3] = colFour[i];}}/*** 参数 c: 密文的字符串数组。* 参数 clen: 密文的长度。* 参数 key: 密钥的字符串数组。*/
void deAes(char *c, int clen, char *key) {int keylen = strlen(key);if(clen == 0 || clen % 4 != 0) {printf("密文字符长度必须为4的倍数!现在的长度为%d\n",clen);exit(0);}if(!checkKeyLen(keylen)) {printf("密钥字符长度错误!长度必须为16、24和32。当前长度为%d\n",keylen);exit(0);}extendKey(key);//扩展密钥int cArray[4][4];for(int k = 0; k < clen; k += 16) {convertToIntArray(c + k, cArray);addRoundKey(cArray, 10);int wArray[4][4];for(int i = 9; i >= 1; i--) {deSubBytes(cArray);deShiftRows(cArray);deMixColumns(cArray);getArrayFrom4W(i, wArray);deMixColumns(wArray);addRoundTowArray(cArray, wArray);}deSubBytes(cArray);deShiftRows(cArray);addRoundKey(cArray, 0);convertArrayToStr(cArray, c + k);}
}

参考main.cpp实现:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>#include "aes.h"#define MAXLEN 1024//获取字符串
void getString(char *str, int len){int slen = read(0, str, len);for(int i = 0; i < slen; i++,str++){if(*str == '\n'){*str = '\0';break;}}
}//输出ASCII
void printASCII(char *str, int len) {int c;for(int i = 0; i < len; i++) {c = (int)*str++;c = c & 0x000000ff;//保留低8位printf("0x%x ", c);}printf("\n");
}/*** 从标准输入中读取用户输入的字符串*/
void readPlainText(char *str, int *len) {int plen;while(1) {getString(str, MAXLEN);plen = strlen(str);if(plen != 0 && plen % 4 == 0) {printf("你输入的明文为:%s\n", str);break;}else{printf("明文字符长度必须为4的倍数,现在的长度为%d\n", plen);}}*len = plen;
}
/*** 把字符串写进文件*/
void writeStrToFile(char *str, int len, char *fileName) {FILE *fp;fp = fopen(fileName, "wb");for(int i = 0; i < len; i++)putc(str[i], fp);fclose(fp);
}//字符串写进文件
void aesStrToFile(char *key) {char p[MAXLEN];int plen;printf("请输入你的明文,明文字符长度必须为4的倍数\n");readPlainText(p,&plen);printf("进行AES加密..................\n");aes(p, plen, key);//AES加密printf("加密完后的明文的ASCII为:\n");printASCII(p, plen);char fileName[64];printf("请输入你想要写进的文件名,比如'test.txt':\n");if(scanf("%s", fileName) == 1) {	writeStrToFile(p, plen, fileName);printf("已经将密文写进%s中了,可以在运行该程序的当前目录中找到它。\n", fileName);}
}
/*** 从文件中读取字符串*/
int readStrFromFile(char *fileName, char *str) {FILE *fp = fopen(fileName, "rb");if(fp == NULL) {printf("打开文件出错,请确认文件存在当前目录下!\n");exit(0);}int i;for(i = 0; i < MAXLEN && (str[i] = getc(fp)) != EOF; i++);if(i >= MAXLEN) {printf("解密文件过大!\n");exit(0);}str[i] = '\0';fclose(fp);return i;
}//解密文件
void deAesFile(char *key) {char fileName[64];char c[MAXLEN];//密文字符串printf("请输入要解密的文件名,该文件必须和本程序在同一个目录\n");if(scanf("%s", fileName) == 1) {int clen = readStrFromFile(fileName, c);printf("开始解密.........\n");deAes(c, clen, key);printf("解密后的明文ASCII为:\n");printASCII(c, clen);printf("明文为:%s\n", c);writeStrToFile(c,clen,fileName);printf("现在可以打开%s来查看解密后的密文了!\n",fileName);}
}//加密文件
void aesFile(char *key) {char fileName[64];char fileP[MAXLEN];printf("请输入要加密的文件名,该文件必须和本程序在同一个目录\n");if(scanf("%s", fileName) == 1) {readStrFromFile(fileName, fileP);int plen = strlen(fileP);printf("开始加密.........\n");printf("加密前文件中字符的ASCII为:\n");printASCII(fileP, plen);aes(fileP, plen, key);//开始加密printf("加密后的密文ASCII为:\n");printASCII(fileP, plen);writeStrToFile(fileP,plen,fileName);printf("已经将加密后的密文写进%s中了\n",fileName);}
}int main(int argc, char const *argv[]) {clock_t start,finish;start = clock();char key[17];printf("请输入4个字符的密钥:\n");int klen;while(1){getString(key,17);klen = strlen(key);if(klen != 4){printf("请输入4个字符的密钥,当前密钥的长度为%d\n",klen);}else{printf("你输入的密钥为:%s\n",key);break;}}printf("输入's'表示要加密输入的字符串,并将加密后的内容写入到文件\n");printf("请输入要功能选项并按回车,输入'f'表示要加密文件\n");printf("输入'p'表示要解密文件\n");char c;if(scanf("%s",&c) == 1) {if(c == 's')aesStrToFile(key);//用AES加密字符串,并将字符串写进文件中else if(c == 'p')deAesFile(key);//把文件中的密文解密,并写回文件中else if(c == 'f')//用AES加密文件aesFile(key);}finish = clock();std::cout << std::endl<<"the time cost is:" << double(finish - start) / CLOCKS_PER_SEC << std::endl;return 0;
}

编译:
Windows可在VS2017下不依赖其他库实现;
Linux编译g++ -o aes -static aes.cpp main.cpp

SM4算法

一个SM的算法:https://github.com/tonyonce2017/SM4

#ifndef _SM4_H
#define _SM4_H
#include<stdio.h>
#include<time.h>
#include<iomanip>
#include<stdlib.h>typedef unsigned int word;// 密钥扩展
// param:   
//		mk[4]: 加密密钥
// return: 轮密钥
word* keyExpansion(word mk[4]);// 迭代
// param¿
//		x[4]: 加密结果
//		mk[4]:密钥 128 bits
//		flag: true:加密  flase:解密
void encryption(word x[4], word mk[4], bool flag);// sm4加密,CBC模式
// param¿
//		result:加密结果
// 		arr	  :待加密数据
//		bits  :待加密数据的bit数
// 		mk[4] :密钥,128 bits
// return: 加密结果result的bit数
unsigned int sm4_encryption(word*& result, word*& arr, unsigned int bits, word mk[4]);// sm4解密,CBC模式
// param¿ 
//		result: 解密结果
//		arr   : 待解密数据
//		bits  : 待解密数据的bit数
//      mk[4] : 密钥,128 bits
// return: 解密结果result的bit数
unsigned int sm4_decryption(word*& result, word*& arr, unsigned int bits, word mk[4]);const word S[] = {0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05, //00x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, //10x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62, //20xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6, //30x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8, //40x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35, //50x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0x78, 0x87, //60xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52, 0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E, //70xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5, 0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1, //80xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55, 0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3, //90x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60, 0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F, //A0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F, 0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 0x51, //B0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F, 0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8, //C0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD, 0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0, //D0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96, 0x77, 0x7E, 0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84, //E0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20, 0x79, 0xEE, 0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48  //F
};#define ShiftLeft(x,k) (x>>(32-k)|(x<<k))
#define L(x) (x^ShiftLeft(x,2)^ShiftLeft(x,10)^ShiftLeft(x,18)^ShiftLeft(x,24))//¿¿¿¿L
#define LL(x) (x^ShiftLeft(x,13)^ShiftLeft(x,23))//¿¿¿¿¿¿¿¿¿
#define F(x) (T(x))
#define lamda(x) ((S[x >> 24 & 0xff] << 24) | (S[x >> 16 & 0xff] << 16) | (S[x >> 8 & 0xff] << 8) | S[x & 0xff])//¿¿¿¿¿//密钥扩展函数
word* keyExpansion(word mk[4]) {word* rk = new word[32];word Fk[4] = { 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc };word CK[32], k[4];for (int i = 0; i < 32; i++) {CK[i] = 0;for (int j = 0; j < 4; j++)CK[i] = CK[i] * 256 + ((4 * i + j) * 7) % 256;}for (int i = 0; i < 4; i++) {k[i] = mk[i] ^ Fk[i];}word temp;for (int i = 0; i < 32; i++) {temp = k[1] ^ k[2] ^ k[3] ^ CK[i];temp = lamda(temp);temp = k[0] ^ LL(temp);k[0] = k[1]; k[1] = k[2]; k[2] = k[3]; k[3] = temp;rk[i] = temp;}return rk;
}//迭代
void encryption(word x[4], word mk[4], bool flag) {word temp;word* rk = keyExpansion(mk);for (int i = 0; i < 32; i++) {temp = x[1] ^ x[2] ^ x[3];if (flag == false) temp ^= rk[31 - i];else temp ^= rk[i];temp = lamda(temp);temp = L(temp) ^ x[0];x[0] = x[1]; x[1] = x[2]; x[2] = x[3]; x[3] = temp;}temp = x[0]; x[0] = x[3]; x[3] = temp;temp = x[1]; x[1] = x[2]; x[2] = temp;delete[] rk;
}//sm4加密函数,CBC模式
unsigned int sm4_encryption(word*& result, word*& arr, unsigned int bits, word mk[4]) {//return bitsword* temp;unsigned int temp_size;unsigned int s = 128 - bits % 128;//s:填充的比特数if (s == 0)s = 128;else if (s == 1)s += 128;temp_size = 4 + ((bits + s) >> 5);temp = new unsigned int[temp_size];int i;for (i = 4; i < 4 + ((bits + 31) >> 5); i++)temp[i] = arr[i - 4];for (; i < temp_size; i++)temp[i] = 0;temp[i - 1] |= s;//用零填充,最后8比特用s填充srand((int)time(0));for (i = 0; i < 4; i++)temp[i] = rand();//前128比特为初始向量result = new unsigned int[temp_size];for (i = 0; i < 4; i++)result[i] = temp[i];for (i = 4; i < temp_size; i += 4) {result[i] = temp[i] ^ result[i - 4];result[i + 1] = temp[i + 1] ^ result[i - 3];result[i + 2] = temp[i + 2] ^ result[i - 2];result[i + 3] = temp[i + 3] ^ result[i - 1];encryption(&result[i], mk, true);}return temp_size * 32;
}//sm4解密,CBC模式
unsigned int sm4_decryption(word*& result, word*& arr, unsigned int bits, word mk[4]) {unsigned int size = bits / 32 - 4;result = new unsigned int[size];unsigned int i;for (i = 0; i < size; i += 4) {result[i] = arr[i + 4];result[i + 1] = arr[i + 5];result[i + 2] = arr[i + 6];result[i + 3] = arr[i + 7];encryption(&result[i], mk, false);result[i] ^= arr[i];result[i + 1] ^= arr[i + 1];result[i + 2] ^= arr[i + 2];result[i + 3] ^= arr[i + 3];}i = result[size - 1] & 0xff;return size * 32 - i;
}#endif

RSA算法

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include<string.h>
#include <math.h>
#include<algorithm>
#include <time.h>using namespace std;
typedef long long ll;// e是公钥
// d是私钥ll e, d, n;ll gcd(ll a, ll b)  //求最大公约数
{ll c = 0;if(a<b) swap(a,b);c = b;do{b = c;c = a%b;a = b;}while (c != 0);return b;
}// 0不是 1是 
ll isPrime(ll i) //判断i是否是素数
{ll flag=0;for(ll a=2; a<i; a++){if(i%a==0){flag=1;break;}}if(flag==1) return 0;else return 1;}ll myPow(ll a, ll b, ll n)  //求a^b mod n
{ll y;/*使用二进制平方乘法计算 pow(a,b) % n*/y=1;while(b != 0){/*对于b中的每个1,累加y*/if(b & 1)y = (y*a) % n;/*对于b中的每一位,计算a的平方*/a = (a*a) % n;/*准备b中的下一位*/b = b>>1;}return y;
}void extgcd(ll a,ll b,ll& d,ll& x,ll& y) 
{if(!b){d=a;x=1;y=0;}else{extgcd(b,a%b,d,y,x);y-=x*(a/b);}
}ll ModularInverse(ll a,ll b)  //获取(1/a)mod b的结果
{ll d,x,y;extgcd(a,b,d,x,y);return d==1?(x+b)%b:-1;}void KeyGeneration()  //获取公钥密钥
{ll p, q;ll phi_n;do{dop = rand();while (p % 2 == 0);}while (!isPrime(p)); 	// 得到素数 p do{doq = rand();while (q % 2 == 0);}while (!isPrime(q)); 	// 得到素数q n = p * q;phi_n = (p - 1) * (q - 1);doe = rand() % (phi_n - 2) + 2; // 1 < e < phi_nwhile (gcd(e, phi_n) != 1);d = ModularInverse(e,phi_n);
}// 一位一位地输出加密的结果 
ll Encryption(ll value)  //加密
{ll cipher;cipher = myPow(value, e, n);cout<<cipher;return cipher;
}// 一位一位地输出解 密的结果 
void Decryption(ll value)  //解密
{ll decipher;decipher = myPow(value, d, n);cout<<decipher;
}
int main()
{clock_t start,finish;start = clock();// 对6位的数字进行稳定加密 ll num;cout<<"请输入要加密的明文数字,enter结束"<<endl;//while(cin>>num){cin >> num;ll de;cout<<"输入的明文为"<<num<<endl; KeyGeneration();  //获取公钥密钥cout<<"加密密钥:"<<e<<endl; cout<<"加密结果为:";de = Encryption( num );cout<<"\n私钥为:"<<d;
//		cout<<"de="<<de<<endl;cout<<"\n解密结果"; Decryption(de);	cout<<"\n-------------"<<endl;//}finish = clock();cout <<endl<<"the time cost is:" << double(finish - start) / CLOCKS_PER_SEC<<endl;return 0;
}

MD5

#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <time.h>using namespace std;#define A 0x67452301
#define B 0xefcdab89
#define C 0x98badcfe
#define D 0x10325476const char str16[] = "0123456789abcdef";const unsigned int T[] = {0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244,0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391 };//行*列16*4const unsigned int s[] = { 7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21};//行*列4*16class MD5 {
private:unsigned int tempA, tempB, tempC, tempD, strlength;
public:MD5() {tempA = A;tempB = B;tempC = C;tempD = D;strlength = 0;}// F函数unsigned int F(unsigned int b, unsigned int c, unsigned int d) {return (b & c) | ((~b) & d);}// G函数unsigned int G(unsigned int b, unsigned int c, unsigned int d) {return (b & d) | (c & (~d));}// H函数unsigned int H(unsigned int b, unsigned int c, unsigned int d) {return b ^ c ^ d;}// I函数unsigned int I(unsigned int b, unsigned int c, unsigned int d) {return c ^ (b | (~d));}// 移位操作函数unsigned int shift(unsigned int a, unsigned int n) {return (a << n) | (a >> (32 - n));}// 编码函数(重要)string encode(string src) {vector<unsigned int> rec = padding(src);//填充字符串for(unsigned int i = 0; i < strlength/16; i++) {unsigned int num[16];for(int j = 0; j < 16; j++) {num[j] = rec[i*16+j];}iterateFunc(num, 16);//循环压缩}return format(tempA) + format(tempB) + format(tempC) + format(tempD);//整理输出}// 循环压缩void iterateFunc(unsigned int* X, int size = 16) {unsigned int a = tempA,b = tempB,c = tempC,d = tempD,rec = 0,g, k;for(int i = 0; i < 64; i++) {if(i < 16) {// F迭代g = F(b, c, d);k = i;}else if(i < 32) {// G迭代g = G(b, c, d);k = (1 + 5*i) % 16;}else if(i < 48) {// H迭代g = H(b, c, d);k = (5 + 3*i) % 16;}else {// I迭代g = I(b, c, d);k = (7*i) % 16;}rec = d;d = c;c = b;b = b + shift(a + g + X[k] + T[i], s[i]);a = rec;}tempA += a;tempB += b;tempC += c;tempD += d;}// 填充字符串vector<unsigned int> padding(string src) {// 以512位,64个字节为一组unsigned int num = ((src.length() + 8) / 64) + 1;vector<unsigned int> rec(num*16);strlength = num*16;for(unsigned int i = 0; i < src.length(); i++){// 一个unsigned int对应4个字节,保存4个字符信息rec[i>>2] |= (int)(src[i]) << ((i % 4) * 8);}// 补充1000...000rec[src.length() >> 2] |= (0x80 << ((src.length() % 4)*8));// 填充原文长度rec[rec.size()-2] = (src.length() << 3);return rec;}// 整理输出string format(unsigned int num) {string res = "";unsigned int base = 1 << 8;for(int i = 0; i < 4; i++) {string tmp = "";unsigned int b = (num >> (i * 8)) % base & 0xff;for(int j = 0; j < 2; j++) {tmp = str16[b%16] + tmp;b /= 16;}res += tmp;}return res;}
};int main() {clock_t start,finish;start = clock();MD5 test;string a = "";cout << "请输入密码: ";getline(cin,a);cout << "MD5单向加密result: " << test.encode(a) << endl;finish = clock();cout <<endl<<"the time cost is:" << double(finish - start) / CLOCKS_PER_SEC<<endl;
}//解密网站:https://www.cmd5.com/

SHA-1

#include <iostream>
#include <string>
#include <bitset>
#include <math.h>
#include <time.h>using namespace std;long long pad[75] = { 0 };
int lenth_pad = 0;bitset<32> Kt[4] = { 0x5A827999,0x6ED9EBA1,0x8F1BBCDC,0xCA62C1D6 };
bitset<32> Ht[5] = { 0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0 };//Ft函数
bitset<32> Ft(int t, bitset<32> B, bitset<32> C, bitset<32> D)
{if (0 <= t && t <= 19){return ((B&C) | ((~B)&D));}else if (20 <= t && t <= 39){return (B^C^D);}else if (40 <= t && t <= 59){return ((B&C) | (B&D) | (C&D));}else if (60 <= t && t <= 79){return (B^C^D);}
}//字符串的拓展函数
void SHA_PAD(string x)
{long long l = x.length();long long i = 0;pad[i] = 128;i++;l += 1;if ((l * 8) % 512 != 448){for (; (l * 8) % 512 != 448; l++){i++;}}l = x.length();l = l * 8;int a = 1;pad[i + 7] = l % 256;while (l / 256 > 0){l = l / 256;pad[i + 7 - a] = l % 256;a++;}for (; a < 8; a++){pad[i + 7 - a] = 0;}lenth_pad = i + 7;
}//循环左移函数
bitset<32> ROTL(int s, bitset<32> W)
{bitset<32>m = W << s;for (int i = 0; i < s; i++){m[i] = W[32 - s + i];}return m;
}//模2^32加函数
bitset<32> ADD(bitset<32>a, bitset<32>b)
{bitset<32> c;int d = 0;for (int i = 0; i < 32; i++){c[i] = (a[i] + b[i] + d) % 2;if (a[i] + b[i] + d >= 2){d = 1;}else if (a[i] + b[i] + d < 2){d = 0;}}return c;
}//循环体
void DO(bitset<512> M)
{bitset<32> Wt[80] = { 0 };for (int i = 0; i < 16; i++){for (int n = 0; n < 32; n++){Wt[i][n] = M[(15 - i) * 32 + n];}}for (int t = 16; t <= 79; t++){Wt[t] = ROTL(1, Wt[t - 3] ^ Wt[t - 8] ^ Wt[t - 14] ^ Wt[t - 16]);}bitset<32> A = Ht[0];bitset<32> B = Ht[1];bitset<32> C = Ht[2];bitset<32> D = Ht[3];bitset<32> E = Ht[4];for (int t = 0; t <= 79; t++){bitset<32> temp = ADD(ADD(ADD(ROTL(5, A), Ft(t, B, C, D)), ADD(E, Wt[t])), Kt[t/20]);E = D;D = C;C = ROTL(30, B);B = A;A = temp;}Ht[0] = ADD(Ht[0], A);Ht[1] = ADD(Ht[1], B);Ht[2] = ADD(Ht[2], C);Ht[3] = ADD(Ht[3], D);Ht[4] = ADD(Ht[4], E);
}int main()
{clock_t start,finish;start = clock();string x;cout << "please enter the text:";getline(cin, x);SHA_PAD(x);long long l = 0;//循环体while (l < x.length()){long long i = l;string Sx;for (; (i < 64 + l) && (i < x.length()); i++){bitset<8> mark = int(x[i]);Sx += mark.to_string();}l += 64;if (i == x.length()){if(lenth_pad<=63)for (int n = 0; n <= lenth_pad; n++){bitset<8> mark = pad[n];Sx += mark.to_string();}else{int n = 0;for (; i < l; i++){bitset<8> mark = pad[n];n++;Sx += mark.to_string();}bitset<512>Mx(Sx);DO(Mx);string last_Sx;for (; n <= lenth_pad; n++){bitset<8> mark = pad[n];last_Sx += mark.to_string();}bitset<512>last_Mx(last_Sx);DO(last_Mx);break;}}bitset<512> Mx(Sx);DO(Mx);}//输出cout << "The hash of text is:";for (int i = 0; i < 5; i++){string s = Ht[i].to_string();for (int n = 0; n < 32;){int result = 0;for (int m = 0; m < 4; m++){result += (s[n + m] - '0')*pow(2, 3 - m);}cout << hex << result;n += 4;}}cout << "\n";//getchar();finish = clock();cout << "the time cost is: " << double(finish-start) / CLOCKS_PER_SEC << endl;return 0;
}

sm3

#include <iostream>
#include <string>
#include <cmath>
#include <time.h>
using namespace std;//二进制转换为十六进制函数实现
string BinToHex(string str) {string hex = "";//用来存储最后生成的十六进制数int temp = 0;//用来存储每次四位二进制数的十进制值while (str.size() % 4 != 0) {//因为每四位二进制数就能够成为一个十六进制数,所以将二进制数长度转换为4的倍数str = "0" + str;//最高位添0直到长度为4的倍数即可}for (int i = 0; i < str.size(); i += 4) {temp = (str[i] - '0') * 8 + (str[i + 1] - '0') * 4 + (str[i + 2] - '0') * 2 + (str[i + 3] - '0') * 1;//判断出4位二进制数的十进制大小为多少if (temp < 10) {//当得到的值小于10时,可以直接用0-9来代替hex += to_string(temp);}else {//当得到的值大于10时,需要进行A-F的转换hex += 'A' + (temp - 10);}}return hex;
}//十六进制转换为二进制函数实现
string HexToBin(string str) {string bin = "";string table[16] = { "0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111" };for (int i = 0; i < str.size(); i++) {if (str[i] >= 'A'&&str[i] <= 'F') {bin += table[str[i] - 'A' + 10];}else {bin += table[str[i] - '0'];}}return bin;
}//二进制转换为十进制的函数实现
int BinToDec(string str) {int dec = 0;for (int i = 0; i < str.size(); i++) {dec += (str[i] - '0')*pow(2, str.size() - i - 1);}return dec;
}//十进制转换为二进制的函数实现
string DecToBin(int str) {string bin = "";while (str >= 1) {bin = to_string(str % 2) + bin;str = str / 2;}return bin;
}//十六进制转换为十进制的函数实现
int HexToDec(string str) {int dec = 0;for (int i = 0; i < str.size(); i++) {if (str[i] >= 'A'&&str[i] <= 'F') {dec += (str[i] - 'A' + 10)*pow(16, str.size() - i - 1);}else {dec += (str[i] - '0')*pow(16, str.size() - i - 1);}}return dec;
}//十进制转换为十六进制的函数实现
string DecToHex(int str) {string hex = "";int temp = 0;while (str >= 1) {temp = str % 16;if (temp < 10 && temp >= 0) {hex = to_string(temp) + hex;}else {hex += ('A' + (temp - 10));}str = str / 16;}return hex;
}string padding(string str) {//对数据进行填充 string res = "";for (int i = 0; i < str.size(); i++) {//首先将输入值转换为16进制字符串res += DecToHex((int)str[i]);}cout << "输入字符串的ASCII码表示为:" << endl;for (int i = 0; i < res.size(); i++) {cout << res[i];if ((i + 1) % 8 == 0) {cout << "  ";}if ((i + 1) % 64 == 0 || (i + 1) == res.size()) {cout << endl;}}cout << endl;int res_length = res.size() * 4;//记录的长度为2进制下的长度res += "8";//在获得的数据后面添1,在16进制下相当于是添加8while (res.size() % 128 != 112) {res += "0";//“0”数据填充}string res_len = DecToHex(res_length);//用于记录数据长度的字符串while (res_len.size() != 16) {res_len = "0" + res_len;}res += res_len;return res;
}string LeftShift(string str, int len) {//实现循环左移len位功能string res = HexToBin(str);res = res.substr(len) + res.substr(0, len);return BinToHex(res);
}string XOR(string str1, string str2) {//实现异或操作string res1 = HexToBin(str1);string res2 = HexToBin(str2);string res = "";for (int i = 0; i < res1.size(); i++) {if (res1[i] == res2[i]) {res += "0";}else {res += "1";}}return BinToHex(res);
}string AND(string str1, string str2) {//实现与操作string res1 = HexToBin(str1);string res2 = HexToBin(str2);string res = "";for (int i = 0; i < res1.size(); i++) {if (res1[i] == '1' && res2[i] == '1') {res += "1";}else {res += "0";}}return BinToHex(res);
}string OR(string str1, string str2) {//实现或操作string res1 = HexToBin(str1);string res2 = HexToBin(str2);string res = "";for (int i = 0; i < res1.size(); i++) {if (res1[i] == '0' && res2[i] == '0') {res += "0";}else {res += "1";}}return BinToHex(res);
}string NOT(string str) {//实现非操作string res1 = HexToBin(str);string res = "";for (int i = 0; i < res1.size(); i++) {if (res1[i] == '0') {res += "1";}else {res += "0";}}return BinToHex(res);
}char binXor (char str1, char str2) {//实现单比特的异或操作return str1 == str2 ? '0' : '1';
}char binAnd(char str1, char str2) {//实现单比特的与操作return (str1 == '1'&&str2 == '1') ? '1' : '0';
}string ModAdd(string str1, string str2) {//mod 2^32运算的函数实现string res1 = HexToBin(str1);string res2 = HexToBin(str2);char temp = '0';string res = "";for (int i = res1.size() - 1; i >= 0; i--) {res = binXor(binXor(res1[i], res2[i]), temp) + res;if (binAnd(res1[i], res2[i]) == '1') {temp = '1';}else {if (binXor(res1[i], res2[i]) == '1') {temp = binAnd('1', temp);}else {temp = '0';}}}return BinToHex(res);
}string P1(string str) {//实现置换功能P1(X)return XOR(XOR(str, LeftShift(str, 15)), LeftShift(str, 23));
}string P0(string str) {//实现置换功能P0(X)return XOR(XOR(str, LeftShift(str, 9)), LeftShift(str, 17));
}string T(int j) {//返回Tj常量值的函数实现if (0 <= j && j <= 15) {return "79CC4519";}else {return "7A879D8A";}
}string FF(string str1, string str2, string str3, int j) {//实现布尔函数FF功能if (0 <= j && j <= 15) {return XOR(XOR(str1, str2), str3);}else {return OR(OR(AND(str1, str2), AND(str1, str3)), AND(str2, str3));}
}string GG(string str1, string str2, string str3, int j) {//实现布尔函数GG功能if (0 <= j && j <= 15) {return XOR(XOR(str1, str2), str3);}else {return OR(AND(str1, str2), AND(NOT(str1), str3));}
}
string extension(string str) {//消息扩展函数string res = str;//字符串类型存储前68位存储扩展字W值for (int i = 16; i < 68; i++) {//根据公式生成第17位到第68位的W值res += XOR(XOR(P1(XOR(XOR(res.substr((i-16)*8,8), res.substr((i - 9) * 8, 8)), LeftShift(res.substr((i - 3) * 8, 8), 15))), LeftShift(res.substr((i - 13) * 8, 8), 7)), res.substr((i - 6) * 8, 8));}cout << "扩展后的消息:" << endl;cout << "W0,W1,……,W67的消息:" << endl;for (int i = 0; i < 8; i++) {for (int j = 0; j < 8; j++) {cout << res.substr(i * 64 + j * 8, 8) << "  ";}cout << endl;}cout << res.substr(512, 8) << "  " << res.substr(520, 8) << "  " << res.substr(528, 8) << "  " << res.substr(536, 8) << endl;cout << endl;for (int i = 0; i < 64; i++) {//根据公式生成64位W'值res += XOR(res.substr(i * 8, 8), res.substr((i + 4) * 8, 8));}cout << "W0',W1',……,W63'的消息:" << endl;for (int i = 0; i < 8; i++) {for (int j = 0; j < 8; j++) {cout << res.substr(544+i * 64 + j * 8, 8) << "  ";}cout << endl;}cout << endl;return res;
}string compress(string str1, string str2) {//消息压缩函数string IV = str2;string A = IV.substr(0, 8), B = IV.substr(8, 8), C = IV.substr(16, 8), D = IV.substr(24, 8), E = IV.substr(32, 8), F = IV.substr(40, 8), G = IV.substr(48, 8), H = IV.substr(56, 8);string SS1 = "", SS2 = "", TT1 = "", TT2 = "";cout << "迭代压缩中间值: " << endl;cout << "    A         B         C         D         E         F        G         H " << endl;cout << A << "  " << B << "  " << C << "  " << D << "  " << E << "  " << F << "  " << G << "  " << H << endl;for (int j = 0; j < 64; j++) {SS1 = LeftShift(ModAdd(ModAdd(LeftShift(A, 12), E), LeftShift(T(j), (j%32))), 7);SS2 = XOR(SS1, LeftShift(A, 12));TT1 = ModAdd(ModAdd(ModAdd(FF(A, B, C, j), D), SS2), str1.substr((j + 68) * 8, 8));TT2 = ModAdd(ModAdd(ModAdd(GG(E, F, G, j), H), SS1), str1.substr(j * 8, 8));D = C;C = LeftShift(B, 9);B = A;A = TT1;H = G;G = LeftShift(F, 19);F = E;E = P0(TT2);cout << A << "  " << B << "  " << C << "  " << D << "  " << E << "  " << F << "  " << G << "  " << H << endl;}string res = (A + B + C + D + E + F + G + H);cout << endl;return res;
}string iteration(string str) {//迭代压缩函数实现int num = str.size() / 128;cout << "消息经过填充之后共有 " + to_string(num) + " 个消息分组。" << endl;cout << endl;string V = "7380166F4914B2B9172442D7DA8A0600A96F30BC163138AAE38DEE4DB0FB0E4E";string B = "", extensionB = "", compressB = "";for (int i = 0; i < num; i++) {cout << "第 " << to_string(i+1) << " 个消息分组:" << endl;cout << endl;B = str.substr(i * 128, 128);extensionB = extension(B);compressB = compress(extensionB, V);V = XOR(V, compressB);}return V;
}int main() {//主函数clock_t start, finish;//clock_t为CPU时钟计时单元数start = clock();//clock()函数返回此时CPU时钟计时单元数string str[2];str[0] = "abcdabcdabcdabcd";str[1] = "1234567812345678";for (int num = 0; num < 2; num++) {cout << "示例 " + to_string(num + 1) + " :输入消息为字符串: " + str[num] << endl;cout << endl;string paddingValue = padding(str[num]);cout << "填充后的消息为:" << endl;for (int i = 0; i < paddingValue.size() / 64; i++) {for (int j = 0; j < 8; j++) {cout << paddingValue.substr(i * 64 + j * 8, 8) << "  ";}cout << endl;}cout << endl;string result = iteration(paddingValue);cout << "杂凑值:" << endl;for (int i = 0; i < 8; i++) {cout << result.substr(i * 8, 8) << "  ";}cout << endl;cout << endl;}finish = clock();//clock()函数返回此时CPU时钟计时单元数cout <<endl<<"the time cost is:" << double(finish - start) / CLOCKS_PER_SEC<<endl;//finish与start的差值即为程序运行花费的CPU时钟单元数量,再除每秒CPU有多少个时钟单元,即为程序耗时return 0;
}

2. openssl

OpenSSL is written in C, and has an Apache style license. It is distinguished by its support for the SSL and TLS protocols, as well as a family of command line applications.

openssl现在的状态不佳,自从心脏出血事件之后,可谓是墙倒众人推,网上也有好多人说它的代码写的很差,没有良好的代码规范,基于这些理由,又是项目中使用的,所以,还是不去冒这个险了。

地址:http://www.openssl.org/

OpenSSL是一个安全套接字层密码库,其包括常用的密码算法、常用的密钥生成和证书封装管理功能及SSL协议,并提供了丰富的应用程序以供测试。

OpenSSL 是一个开源项目,其组成主要包括一下三个组件:

  • openssl:多用途的命令行工具
  • libcrypto:加密算法库
  • libssl:加密模块应用库,实现了ssl及tls

安装参考:https://blog.csdn.net/weixin_39274753/article/details/107958283

应用如下:

1.单向散列加密应用
OpenSSL单向加密的子命令为dgst,其语法如下:
openssl dgst [-md5|-md4|-md2|-sha1|-sha|-mdc2|-ripemd160|-dss1] [-c] [-d] [-hex] [-binary] [-out filename] [-sign filename] [-keyform arg] [-passin arg] [-verify filename] [-prverify filename] [-signature filename] [-hmac key] [file…]
其常用的选项为:
[-md5|-md4|-md2|-sha1|-sha|-mdc2|-ripemd160|-dss1]:指定一种单向加密算法;
-out FILENAME:将加密的内容保存到指定的文件中;
单向加密除了 openssl dgst 工具还有: md5sum,sha1sum,sha224sum,sha256sum ,sha384sum,sha512sum
生成指定文件的特征码案例:openssl dgst -md5 /tmp/fstab
md5sum /tmp/fstab
echo hello,world | md5sum
echo hello,world | openssl dgst -md5
2.对称加密算法应用
OpenSSL一共提供了8种对称加密算法,其中7种是分组加密算法,仅有的一种流加密算法是RC4。这7种分组加密算法分别是AES、DES、Blowfish、CAST、IDEA、RC2、RC5。利用OpenSSL作对称加密需要使用其子命令enc,其用法为:
openssl enc -ciphername [-in filename] [-out filename] [-pass arg] [-e] [-d] [-a/-base64] [-A] [-k password] [-kfile filename] [-K key] [-iv IV] [-S salt] [-salt] [-nosalt] [-z] [-md] [-p] [-P] [-bufsize number] [-nopad] [-debug] [-none] [-engine id]
其中常用的选项为:
-e:加密;
-d:解密;
-ciphername:ciphername为相应的对称加密算法名字,如-des3、-ase128、-cast、-blowfish等等。
-a/-base64:使用base-64位编码格式;
-salt:自动插入一个随机数作为文件内容加密,默认选项;
-in FILENAME:指定要加密的文件的存放路径;
-out FILENAME:指定加密后的文件的存放路径;
加密字符串案例:echo "hello,world" | openssl enc -aes128 -e -a –salt -in
加解密文件案例:openssl enc -des3 -e -a -in /etc/fstab -out /tmp/fstab
openssl enc -d -des3 -a -salt -in /tmp/fstab
3.非对称加密算法应用
OpenSSL一共实现了4种非对称加密算法,包括DH算法、RSA算法、DSA算法和椭圆曲线算法(EC)。DH算法一般用户密钥交换。RSA算法既可以用于密钥交换,也可以用于数字签名。
利用openssl命令的子命令genrsa生成私钥,然后再使用子命令rsa私钥中提取公钥。
genrsa的语法如下:
openssl genrsa [-out filename] [-passout arg] [-des] [-des3] [-idea] [-f4] [-3] [-rand file(s)] [-engine id] [numbits]
常用选项:
-out FILENAME:将生成的私钥保存至指定的文件中;
[-des] [-des3] [-idea]:指定加密算法;
numbits:指明生成的私钥大小,默认是512;
通常来说秘钥文件的权限一般只能由管理员访问,因此可以结合umask命令来设置生成的密钥文件的权限,如:
(umask 077;openssl genrsa -out CA.key 4096)
随后可利用rsa子命令生成的私钥文件中提取公钥,rsa子命令的语法为:
openssl rsa [-inform PEM|NET|DER] [-outform PEM|NET|DER] [-in filename] [-passin arg] [-out filename] [-passout arg] [-sgckey] [-des] [-des3] [-idea] [-text] [-noout] [-modulus] [-check] [-pubin] [-pubout] [-engine id]
常用选项为:
-in FILENAME:指明私钥文件的存放路径;
-out FILENAME:指明将公钥的保存路径;
-pubout:根据提供的私钥,从中提取出公钥;
使用案例:openssl rsa -pubout -in CA.key
利用公钥加密、私钥解密数据:
使用rsautl进行加密和解密操作,语法如下:
openssl rsautl [-in file] [-out file] [-inkey file] [-pubin] [-certin] [-sign] [-verify] [-encrypt] [-decrypt] [-pkcs] [-ssl] [-raw] [-hexdump] [-asn1parse]     
openssl rsautl -h
Usage: rsautl [options]
-in file        input file 输入文件
-out file       output file 输出文件
-inkey file     input key 指定私有密钥文件,格式是RSA私有密钥文件
-keyform arg    private key format - default PEM 指定私钥格式
-pubin          input is an RSA public 指定输入的是RSA公钥
-certin         input is a certificate carrying an RSA public key 指定输入的是证书文件
-ssl            使用SSLv2的填充方式
-raw            不进行填充
-pkcs           使用V1.5的填充方式(默认)
-oaep           使用OAEP的填充方式
-sign           使用私钥做签名
-verify         使用公钥认证签名
-encrypt        使用公钥加密
-decrypt        使用私钥解密
-hexdump        以16进制打印
-engine e       指定三方库或者硬件设备
-passin arg    pass phrase source 传递密码来源
操作示例:
/*创建需要加密的文件*/
echo "123456789 hello world!" > plain.txt
/*生成RSA密钥,采用des3对称加密私钥*/
openssl genrsa -des3 -passout pass:123456 -out RSA.pem
/*提取公钥*/
openssl rsa -in RSA.pem -passin pass:123456 -pubout -out pub.pem
/*使用RSA作为密钥进行加密,实际上使用其中的公钥进行加密*/
openssl rsautl -encrypt -in plain.txt -inkey RSA.pem -passin pass:123456 -out enc.txt
/*使用RSA作为密钥进行解密,实际上使用其中的私钥进行解密*/
openssl rsautl -decrypt -in enc.txt -inkey RSA.pem -passin pass:123456 -out replain.txt
4.生成随机数
openssl命令也支持生成随机数,其子命令为rand,对应的语法为:
openssl rand [-out file] [-rand file(s)] [-base64] [-hex] num
常用选项有:
-base64:以base64编码格式输出;
-hex:使用十六进制编码格式;
-out FILE:将生成的内容保存在指定的文件中;
使用案例:openssl rand  -base64  10
5.加密密码
OpenSSL还支持生成密码的hash离散值,其子命令为passwd,语法如下:
openssl passwd [-crypt] [-1] [-apr1] [-salt string] [-in file] [-stdin] [-noverify] [-quiet] [-table] {password}
常用选项为:
-salt STRING:添加随机数;
-in FILE:对输入的文件内容进行加密;
-stdin:对标准输入的内容进行加密;
生成密码的hash值案例:openssl passwd -1 -salt 123456 PASSWORD
6. 数字签名
和非对称加密相反,如果是用私钥进行加密,公钥解密叫做数字签名,因为私钥只有一份,用公钥解密出来验证确认是你用这个私钥做的签名,这就是签名和验证。
先用pkcs8子命令提取出pkcs8格式的私钥,rsa默认生成pkcs1格式的私钥,当然也可以直接使用默认的来做签名和验证,在用java等一些开发中需要要求私钥是pkcs8格式,pkcs8子命令格式以及参数如下:
openssl pkcs8 
[-inform PEM|DER] [-outform PEM|DER] [-in filename] [-passin arg] [-out filename]   
[-passout arg] [-topk8] [-noiter] [-nocrypt] [-nooct] [-embed] [-nsdb] [-v2 alg] 
[-v1 alg] [-engine id]  
参数说明:
-inform PEM|DER :输入文件格式,DER或者PEM格式。DER格式采用ASN1的DER标准格式。一般用的多的都是PEM格式,就是base64编码格式。
-outform DER|PEM :输出文件格式,DER或者PEM格式。
-in filename :输入的密钥文件,默认为标准输入。如果密钥被加密,会提示输入一个密钥口令。
-passin arg :输入文件口令保护来源。
-out filename :输出文件,默认为标准输出。如果任何加密操作已经执行,会提示输入一个密钥值。输出的文件名字不能和输入的文件名一样。
-passout arg :输出文件口令保护来源。
-topk8 :通常的是输入一个pkcs8文件和传统的格式私钥文件将会被写出。设置了此选项后,位置转换过来:输入一个传统格式的私钥文件,输出一个PKCS#8格式的文件。
-noiter :MAC保护计算次数为1。
-nocrypt :PKCS#8密钥产生或输入一般用一个适当地密钥来加密PKCS#8 EncryptedPrivateKeyInfo结构。设置了此选项后,一个不加密的PrivateKeyInfo结构将会被输出。这个选项一直不加密私钥文件,在绝对必要的时候才能够使用。某些软件例如一些JAVA代码签名软件使用不加密的私钥文件。
-nooct :这个选项产生的RSA私钥文件是一个坏的格式,一些软件将会使用。特别的是,私钥文件必须附上一个八位组字符串,但是一些软件仅仅包含本身的结构体没有使八位组字符串所环绕。不采用八位组表示私钥。
-embed :这个选项产生的RSA私钥文件是一个坏的格式。在私钥结构体中采用嵌入式DSA参数格式。在这个表单中,八位组字符串包含了ASN1 SEQUENCE中的两种结构:一个SEQUENCE包含了密钥参数,一个ASN1 INTEGER包含私钥值。
-nsdb :这个选项产生的RSA私钥文件是一个坏的格式并兼容了Netscape私钥文件数据库。采用NetscapeDB的DSA格式。
-v2 alg :采用PKCS#5 v2.0,并指定加密算法,默认的是PKCS#8私钥文件被叫做B<pbeWithMD5AndDES-CBC>(该算法用56字节的DES加密但是在PKCS#5 v1.5中有更加强壮的加密算法)的加密算法用口令进行加密。用B<-v2>选项,PKCS#5 v2.0相关的算法将会被使用,可以是des3(168字节)和rc2(128字节),推荐des3。
-v1 alg :采用PKCS#5 v1.5或pkcs12,并指定加密算法。-engine id :指定硬件引擎。
然后用rsautl子命令-sign生成签名,-verify验证,示例如下:
/*提取PCKS8格式的私钥*/
openssl pkcs8 -topk8 -in RSA.pem -passin pass:123456 -out pri.pem –nocrypt
/*使用私钥生成签名*/
openssl rsautl -sign -in plain.txt -inkey pri.pem  -out sign.txt
/*使用公钥对签名进行验证*/
openssl rsautl -verify -in sign.txt -inkey pub.pem -pubin -out replain.txt
/*用默认的rsa生成的pkcs1格式私钥生成签名*/
openssl rsautl -sign -in plain.txt -inkey RSA.pem -passin pass:123456  -out sign1.txt
/*用公钥验证签名*/
openssl rsautl -verify -in sign1.txt -inkey pub.pem  -pubin -out replain1.txt
/*查看解密内容*/
xxd replain1.txt

3. crypto++

Crypto++ is written in C++, and is mostly public domain files, although there are a few restrictions on the use of the collection. Crypto++ includes a set of ECC functions.

基于c++的cryptlib,这个库在网上的评价还算不错的,支持多种加密算法。

这里暂时选择Cryto++这个库,选择这个库主要是因为现在手头找到的关于它的资料文档最多,容易快速上手。

地址:http://www.cryptopp.com/

AES算法:

#include <iostream>
#include <aes.h>#pragma comment( lib, "cryptlib.lib" )
using namespace std; 
using namespace CryptoPP;
int main()
{
//AES中的固定参数是以类AES中定义的enum数据类型,而不是成员函数或变量
cout << "AES Parameters: " << endl;
cout << "Algorithm name : " << AES::StaticAlgorithmName() << endl; //Crypto++库中一般用字节数来表示长度
cout << "Block size : " << AES::BLOCKSIZE * 8 << endl;
cout << "Min key length : " << AES::MIN_KEYLENGTH * 8 << endl;
cout << "Max key length : " << AES::MAX_KEYLENGTH * 8 << endl;//AES中只包含一些固定的数据,而加密解密的功能由AESEncryption和AESDecryption来完成
//加密过程
AESEncryption aesEncryptor; //加密器 unsigned char aesKey[AES::DEFAULT_KEYLENGTH]; //密钥
unsigned char inBlock[AES::BLOCKSIZE] = "123456789"; //要加密的数据块
unsigned char outBlock[AES::BLOCKSIZE]; //加密后的密文块
unsigned char xorBlock[AES::BLOCKSIZE]; //必须设定为全零memset( xorBlock, 0, AES::BLOCKSIZE ); //置零aesEncryptor.SetKey( aesKey, AES::DEFAULT_KEYLENGTH ); //设定加密密钥
aesEncryptor.ProcessAndXorBlock( inBlock, xorBlock, outBlock ); //加密//以16进制显示加密后的数据
for( int i=0; i<16; i++ ) {
cout << hex << (int)outBlock[i] << " ";
}
cout << endl;//解密
AESDecryption aesDecryptor;
unsigned char plainText[AES::BLOCKSIZE];aesDecryptor.SetKey( aesKey, AES::DEFAULT_KEYLENGTH );
aesDecryptor.ProcessAndXorBlock( outBlock, xorBlock, plainText );for( int i=0; i<16; i++ ) 
{ 
cout << plainText[i]; 
}
cout << endl;return 0;}

DES算法:

#include <iostream>
#include <des.h>#pragma comment( lib, "cryptlib.lib" )using namespace std;
using namespace CryptoPP;int main( void )
{cout << "DES Parameters: " << endl;cout << "Algorithm name : " << DES::StaticAlgorithmName() << endl;unsigned char key[ DES::DEFAULT_KEYLENGTH ];unsigned char input[ DES::BLOCKSIZE ] = "12345";unsigned char output[ DES::BLOCKSIZE ];unsigned char txt[ DES::BLOCKSIZE ];cout << "input is: " << input << endl;//首先构造一个加密器DESEncryption encryption_DES;//设置密匙。encryption_DES.SetKey( key, DES::KEYLENGTH );//进行加密encryption_DES.ProcessBlock( input, output );//显示结果//for和for之后的cout可有可无,主要为了运行的时候看加密结果//把字符串的长度写成一个常量其实并不被推荐。//这里主要是把output也就是加密后的内容,以十六进制的整数形式输出。for( int i = 0; i < 5; i++ ){cout << hex << (int)output[ i ] << ends;}cout << endl;//构造一个解密器DESDecryption decryption_DES;//加密和解密都是同一个密匙,decryption_DES.SetKey( key, DES::KEYLENGTH );//进行解密,把结果写到txt中//decryption_DES.ProcessAndXorBlock( output, xorBlock, txt );decryption_DES.ProcessBlock( output, txt );//验证加密前的明文和解密后的译文是否相等。if ( memcmp( input, txt, 5 ) != 0 ){cerr << "DES Encryption/decryption failed.\n";abort();}cout << "DES Encryption/decryption succeeded.\n";return 0;
}

RSA算法:

#include "randpool.h"
#include "rsa.h"
#include "hex.h"
#include "files.h"
#include <iostream>using namespace std;
using namespace CryptoPP;#pragma comment(lib, "cryptlib.lib")void GenerateRSAKey( unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed  );
string RSAEncryptString( const char *pubFilename, const char *seed, const char *message );
string RSADecryptString( const char *privFilename, const char *ciphertext );
RandomPool & GlobalRNG();void main( void ){char priKey[ 128 ] = { 0 };char pubKey[ 128 ] = { 0 };char seed[ 1024 ]  = { 0 };// 生成 RSA 密钥对strcpy( priKey, "pri" );  // 生成的私钥文件strcpy( pubKey, "pub" );  // 生成的公钥文件strcpy( seed, "seed" );GenerateRSAKey( 1024, priKey, pubKey, seed );// RSA 加解密char message[ 1024 ] = { 0 };cout<< "Origin Text:\t" << "Hello World!" << endl << endl;strcpy( message, "Hello World!" );string encryptedText = RSAEncryptString( pubKey, seed, message );  // RSA 公匙加密cout<<"Encrypted Text:\t"<< encryptedText << endl << endl;string decryptedText = RSADecryptString( priKey, encryptedText.c_str() );  // RSA 私匙解密
}// 生成密钥对
void GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed)
{RandomPool randPool;randPool.Put((byte *)seed, strlen(seed));RSAES_OAEP_SHA_Decryptor priv(randPool, keyLength);HexEncoder privFile(new FileSink(privFilename));priv.DEREncode(privFile);privFile.MessageEnd();RSAES_OAEP_SHA_Encryptor pub(priv);HexEncoder pubFile(new FileSink(pubFilename));pub.DEREncode(pubFile);pubFile.MessageEnd();return}// RSA加密
string RSAEncryptString( const char *pubFilename, const char *seed, const char *message )
{FileSource pubFile( pubFilename, true, new HexDecoder );RSAES_OAEP_SHA_Encryptor pub( pubFile );RandomPool randPool;randPool.Put( (byte *)seed, strlen(seed) );string result;StringSource( message, true, new PK_EncryptorFilter(randPool, pub, new HexEncoder(new StringSink(result))) );return result;
}// RSA解密
string RSADecryptString( const char *privFilename, const char *ciphertext )
{FileSource privFile( privFilename, true, new HexDecoder );RSAES_OAEP_SHA_Decryptor priv(privFile);string result;StringSource( ciphertext, true, new HexDecoder(new PK_DecryptorFilter(GlobalRNG(), priv, new StringSink(result))) );return result;
}// 定义全局的随机数池
RandomPool & GlobalRNG()
{static RandomPool randomPool;return randomPool;
}

SHA-256算法:

//参考 http://hi.baidu.com/magic475/blog/item/19b37a8c1fa15a14b21bbaeb.html
#include <iostream>
#include <string.h>#include "sha.h"
#include "secblock.h"
#include "modes.h"
#include "hex.h"#pragma comment( lib, "cryptlib.lib")using namespace std;
using namespace CryptoPP;void CalculateDigest(string &Digest, const string &Message);
bool VerifyDigest(const string &Digest, const string &Message);int main( void )
{string strMessage( "Hello world" );string strDigest;	// 摘要//string strMessage2( "hello world" ); //只是第一个字母不同//string strDigest2;CalculateDigest( strDigest, strMessage );  //计算Hash值并打印一些debug信息cout << "the size of Digest is: " << strDigest.size() << endl;cout << "Digest is: " << strDigest << endl;bool bIsSuccess = false;bIsSuccess = VerifyDigest( strDigest, strMessage );//通过校验,看看strDigest是否对应原来的messageif( bIsSuccess ){cout << "sussessive verify" << endl;cout << "origin string is: " << strMessage << endl << endl;}else{cout << "fail!" << endl;}//通过strDigest2与strMessage进行校验,要是相等,//就证明strDigest2是对应的strMessage2跟strMessage1相等。/*CalculateDigest( strDigest2, strMessage2 );bIsSuccess = VerifyDigest( strDigest2, strMessage );if( !bIsSuccess ){cout << "success! the tiny modification is discovered~" << endl;cout << "the origin message is: \n" << strMessage << endl;cout << "after modify is: \n" << strMessage2 << endl;}*/return 0;
}void CalculateDigest(string &Digest, const string &Message)
{SHA256 sha256;int DigestSize = sha256.DigestSize();char* byDigest;char* strDigest;byDigest = new char[ DigestSize ];strDigest = new char[ DigestSize * 2 + 1 ];sha256.CalculateDigest((byte*)byDigest, (const byte *)Message.c_str(), Message.size());memset(strDigest, 0, sizeof(strDigest));//uCharToHex(strDigest, byDigest, DigestSize);Digest = byDigest;delete []byDigest;byDigest = NULL;delete []strDigest;strDigest = NULL;return;
}bool VerifyDigest(const string &Digest, const string &Message)
{bool Result;SHA256 sha256;char* byDigest;byDigest = new char[ sha256.DigestSize() ];strcpy( byDigest, Digest.c_str() );//HexTouChar(byDigest, Digest.c_str(), Digest.size());Result = sha256.VerifyDigest( (byte*)byDigest, (const byte *)Message.c_str(), Message.size() );delete []byDigest;byDigest = NULL;return Result;
}

获取设备mac物理地址程序:

#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif // !_CRT_SECURE_NO_WARNINGS//#include "stdafx.h"
#include <windows.h>
#include <wincon.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <Nb30.h>#include <fstream>
#include <iostream>
#include <string>
#pragma comment(lib,"netapi32.lib")int GetMac(char * mac)
{NCB ncb;typedef struct _ASTAT_{ADAPTER_STATUS   adapt;NAME_BUFFER   NameBuff[30];}ASTAT, *PASTAT;ASTAT Adapter;typedef struct _LANA_ENUM{UCHAR   length;UCHAR   lana[MAX_LANA];}LANA_ENUM;LANA_ENUM lana_enum;UCHAR uRetCode;memset(&ncb, 0, sizeof(ncb));memset(&lana_enum, 0, sizeof(lana_enum));ncb.ncb_command = NCBENUM;ncb.ncb_buffer = (unsigned char *)&lana_enum;ncb.ncb_length = sizeof(LANA_ENUM);uRetCode = Netbios(&ncb);if (uRetCode != NRC_GOODRET)return uRetCode;for (int lana = 0; lana < lana_enum.length; lana++){ncb.ncb_command = NCBRESET;ncb.ncb_lana_num = lana_enum.lana[lana];uRetCode = Netbios(&ncb);if (uRetCode == NRC_GOODRET)break;}if (uRetCode != NRC_GOODRET)return uRetCode;memset(&ncb, 0, sizeof(ncb));ncb.ncb_command = NCBASTAT;ncb.ncb_lana_num = lana_enum.lana[0];strcpy((char*)ncb.ncb_callname, "*");ncb.ncb_buffer = (unsigned char *)&Adapter;ncb.ncb_length = sizeof(Adapter);uRetCode = Netbios(&ncb);if (uRetCode != NRC_GOODRET)return uRetCode;sprintf(mac, "%02X-%02X-%02X-%02X-%02X-%02X",Adapter.adapt.adapter_address[0],Adapter.adapt.adapter_address[1],Adapter.adapt.adapter_address[2],Adapter.adapt.adapter_address[3],Adapter.adapt.adapter_address[4],Adapter.adapt.adapter_address[5]);return 0;
}int main(int argc, char* argv[])
{//1.未授权的钥匙int is_authorized = 0;char   mac_empty[200] = "asghjkkklll";//电脑mac地std::string key_file_name = "key.txt";std::ofstream outfile(key_file_name);std::ifstream infile(key_file_name);//写入文件夹std::fstream file(key_file_name, std::ios::out);//文件夹清空outfile << std::to_string(is_authorized) << std::endl;outfile << mac_empty << std::endl;char   mac_empty1[200] = "000000000";//电脑mac地int is_authorized1 = 0;if (!infile.is_open()){std::cout << "文件夹已经打开!" << std::endl;return -1;}//2.读取密钥信息std::string mac_name;std::string is_authorized2_str;if (!infile.is_open()){std::cout << "文件夹已经打开!" << std::endl;return -1;}std::getline(infile, is_authorized2_str);std::getline(infile, mac_name);const std::string  is_authorized11 = is_authorized2_str;int  is_authorized3 = std::stoi(is_authorized11);//3.判定如果软件还未授权,则授权if (is_authorized3 == 0){GetMac(mac_empty);is_authorized = 1;std::fstream file(key_file_name, std::ios::out);//文件夹清空outfile << is_authorized << std::endl;outfile << mac_empty << std::endl;printf("授权成功!/n");}//4.再次读取授权状态if (!infile.is_open()){std::cout << "文件夹已经打开!" << std::endl;return -1;}std::getline(infile, is_authorized2_str);std::getline(infile, mac_name);const std::string  is_authorized12 = is_authorized2_str;is_authorized3 = std::stoi(is_authorized12);if (is_authorized3 == 1){	char   mac_real[200] = "1111111";//电脑mac地GetMac(mac_real);if (strcmp(mac_real, mac_name.c_str()) == 0){std::cout << "mac 地址正确!" << std::endl;}else{std::cout << "mac 地址错误,软件未授权!" << std::endl;}}printf("The Mac Address is : %s   \n", mac_empty);system("pause");return 0;
}

4. botan

这个库没有太多的了解,也仅仅是刚知道,也是支持多种加密算法的。

地址:http://botan.randombit.net/

5. cryptlib

基于c的加密库。

地址:http://www.cryptlib.com/

如果应用涉及到 SSL 等 PKI 协议,应该使用 openssl,如果只是应用一些加密算法,则建议使用 Cryptlib。

三、性能与方案选择

加密技术包括两个元素:算法和密钥。密钥是用来对数据进行编码和解码的一种方法;而算法是将明文与密钥结合,产生不可理解的密文的步骤。

单向散列算法诞生较早,技术成熟,运行速度最快,但只能单向加密;对称加密算法是指客户端和服务端共用一套密钥,用相同的密钥去加密和解密,运行速度较快,安全性也较高;非对称加密算法有公钥和私钥,较难破解,安全等级最高,但运行速度较慢。

常用加密算法性能和安全性对比:

在这里插入图片描述

通过了解各种算法的实现方式、优缺点及相关应用,得出以下结论:校验时,可以使用单向散列算法(如MD5、CRC32),一般加密需求时,可以使用对称加密算法(如AES、DES);但加密要求较高时,建议选用混合加密策略,即用非对称加密算法(如RSA)来解决对称加密的密钥传输,密钥传输完成后,A和B之间采用对称加密算法(如AES)进行通信。这样做既可以保证密钥的安全性,也能保证数据正常传输过程中的运行效率。

以上。

相关文章:

【安全加密】通信加密算法介绍

加密常用于通信中&#xff0c;如战争中电台通讯有明码和密码&#xff0c;密码需要不断更换密码本&#xff1b;另外&#xff0c;商用软件也需要用到加密技术&#xff0c;如根据电脑的mac地址设置权限&#xff0c;防止软件被恶意传播。 文章目录一、介绍1. 单向散列/哈希算法2. 对…...

kubernetes教程 --组件详细介绍

组件详细介绍 NameSpace 在 Kubernetes 中&#xff0c;名字空间&#xff08;Namespace&#xff09; 提供一种机制&#xff0c;将同一集群中的资源划分为相互隔离的组。 同一名字空间内的资源名称要唯一&#xff0c;但跨名字空间时没有这个要求。 名字空间作用域仅针对带有名字…...

数字化系统使用率低的原因剖析

当“数字化变革”成为热门话题&#xff0c;当“数字化转型”作为主题频频出现在一个个大型会议中&#xff0c;我们知道数字化时代的确到来了。但是&#xff0c;根据Gartner的报告我们看到一个矛盾的现象——85%的企业数字化建设与应用并不理想、但对数字化系统的需求多年来持续…...

<<Java开发环境配置>>7-Apache Tomcat安装教程环境变量配置IDEA配置

一.Apache Tomcat简介: Apache是普通服务器&#xff0c;本身只支持html即普通网页。不仅可以通过插件支持php,还可以与Tomcat连通(单向Apache连接Tomcat,就是说通过Apache可以访问Tomcat资源。反之不然)。Apache只支持静态网页&#xff0c;但像php,cgi,jsp等动态网页就需要Tomc…...

互联网大厂测开面试记,二面被按地上血虐,所幸Offer已到手

在互联网做了几年之后&#xff0c;去大厂“镀镀金”是大部分人的首选。大厂不仅待遇高、福利好&#xff0c;更重要的是&#xff0c;它是对你专业能力的背书&#xff0c;大厂工作背景多少会给你的简历增加几分竞争力。 如何备战面试的&#xff1f; 第一步&#xff1a;准备简历…...

网络管理之设备上线技术的发展现状和趋势

网络和网络设备无处不在 随着社会的发展和技术的进步&#xff0c;人类文明开始向信息时代演进&#xff0c;网络逐渐变成现代社会不可或缺的一部分&#xff0c;极大程度影响了人类的认知形式、思维方式与生活模式。从家庭网&#xff0c;到企业网&#xff1b;从无线网&#xff0…...

SQL67 返回固定价格的产品

描述有表Productsprod_idprod_nameprod_pricea0018sockets9.49a0019iphone13600b0018gucci t-shirts1000【问题】从 Products 表中检索产品 ID&#xff08;prod_id&#xff09;和产品名称&#xff08;prod_name&#xff09;&#xff0c;只返回价格为 9.49 美元的产品。【示例结…...

webpack 开发环境的基本配置(webpack打包样式资源、html、图片、devserver、开发环境配置、以及其他资源)

A.打包样式资源 1. 创建文件 2. 下载安装 loader 包 npm i css-loader style-loader less-loader less -D 3. 修改配置文件 /*webpack.config.js webpack的配置文件作用: 指示 webpack 干哪些活&#xff08;当你运行 webpack 指令时&#xff0c;会加载里面的配置&#xff…...

刷题记录:牛客NC14402求最大值

传送门:牛客 题目描述: 给出一个序列&#xff0c;你的任务是求每次操作之后序列中 &#xff08;a[j]-a[i]&#xff09;/&#xff08;j-i&#xff09;【1<i<j<n】的最大值。 操作次数有Q次&#xff0c;每次操作需要将位子p处的数字变成y. 输入: 5 2 4 6 8 10 2 2 5 4…...

javaEE 初阶 — 传输层 TCP 协议 中的延迟应答与捎带应答

文章目录1. 延迟应答2. 捎带应答TCP 工作机制&#xff1a;确认应答机制 超时重传机制 连接管理机制 滑动窗口 流量控制与拥塞控制 1. 延迟应答 延时应答 也是提升效率的机制&#xff0c;也是在滑动窗口基础上搞点事情。 滑动窗口的关键是让窗口大小大一点&#xff0c;传输…...

STM32单片机初学8-SPI flash(W25Q128)数据读写

当使用单片机进行项目开发&#xff0c;涉及大量数据需要储存时&#xff08;例如使用了屏幕作为显示设备&#xff0c;常常需要存储图片、动画等数据&#xff09;&#xff0c;单靠单片机内部的Flash往往是不够用的。 如STM32F103系列&#xff0c;内部Flash最多只能达到512KByte&a…...

MS-SQL创建查询排序语句总结

重新捡起枪杆子&#xff0c;学习N年没用过的MS-SQL&#xff0c;整理一些学习笔记记录。 一、创建、修改和删除表 在SQL中&#xff0c;表有如下规则&#xff1a; 每张表都有一个名字&#xff0c;通常称为表名或关系名。表名必须以字母开头&#xff0c;最大长度为 30 个字符。一…...

subprocess—Python多进程模块

subprocess—Python多进程模块 1.概述 这篇文章介绍并行运算中的subprocess模块&#xff0c;subprocess 模块允许我们启动一个新进程&#xff0c;并连接到它们的输入/输出/错误管道&#xff0c;从而获取返回值。 subprocess 它可以用来调用第三方工具&#xff08;例如&#x…...

【APP渗透测试】 Android APP渗透测试技术实施以及工具使用(客户端服务端)

文章目录前言一、安全威胁分析二、主要风险项三、Android测试思维导图四、反编译工具五、Android客户端漏洞一、Jnaus漏洞漏洞二、数据备份配置风险漏洞漏洞三、Activity组件泄露漏洞漏洞四、BroadcastReceiver组件泄露漏洞漏洞五、允许模拟器Root环境登录漏洞漏洞六、未识别代…...

字符串匹配 - Overview

字符串匹配(String Matchiing)也称字符串搜索(String Searching)是字符串算法中重要的一种&#xff0c;是指从一个大字符串或文本中找到模式串出现的位置。字符串匹配概念字符串匹配问题的形式定义&#xff1a;文本&#xff08;Text&#xff09;是一个长度为 n 的数组 T[1..n]&…...

【IP课堂】Ip地址如何进行精准定位?

通过Ip地址定位&#xff0c;是目前网络上最常见的定位方式。当然&#xff0c;也是最简单的定位方式。其实方法大多都是雷同的&#xff0c;通过Ip定位&#xff0c;就目前网上公开的技术。如通过搜索关键词“定位&#xff0c;定位查询&#xff0c;Ip定位”等&#xff0c;只能查询…...

MySQL 临时表相关参数说明区别

MySQL 临时表参数innodb_temp_tablespaces_dir、innodb_temp_data_file_path、innodb_tmpdir、tmpdir 区分 解决方案 innodb_tmpdir&#xff1a; alter table生成中间表文件&#xff0c;innodb_tmpdir有指定效路径&#xff0c;优选选择innodb_tmpdir&#xff0c;没有则选择tm…...

第二章 变量和基本类型

1.string类型数据的另一种初始化方式 语法&#xff1a; string 变量名 (" 初始化内容 "); 2.C中的列表初始化 语法&#xff1a; 数据类型 变量名 { 变量初始化的值 } ; 数据类型 变量名 { 变量初始化的值 } ; 例&#xff1a; 3.引用常量 常量引…...

【Python】循环语句(while,for)、运算符、字符串格式化

一、while循环Python 编程中 while 语句用于循环执行程序&#xff0c;即在某条件下&#xff0c;循环执行某段程序&#xff0c;以处理需要重复处理的相同任务。其基本形式为&#xff1a;while 判断条件(condition)&#xff1a;执行语句(statements)执行语句可以是单个语句或语句…...

利用设计模式、反射写代码

软件工程师和码农最大的区别就是平时写代码时习惯问题&#xff0c;码农很喜欢写重复代码而软件工程师会利用各种技巧去干掉重复的冗余代码。 业务同学抱怨业务开发没有技术含量&#xff0c;用不到设计模式、Java 高级特性、OOP&#xff0c;平时写代码都在堆 CRUD&#xff0c;个…...

Spring Cloud Alibaba--seata微服务详解之分布式事务(三)

上篇讲述gateway的部署和使用&#xff0c;gateway统一管理和转发了HTTP请求&#xff0c;在互联网中大型项目一定存在复杂的业务关系&#xff0c;尤其在商城类软件中如淘宝、PDD等商城&#xff0c;尤其在秒杀场景中&#xff0c;并发量可以到达千万级别&#xff0c;此时数据库就会…...

[USACO2023-JAN-Bronze] T3 Moo Operations 题解

一、题目描述因为Bessie觉得玩平时经常玩的只包含C O和W的字符串无聊了&#xff0c;Farmer John 给了她Q个新的字符串(1≤Q≤100)&#xff0c;这Q个字符串只包含M和O。很明显&#xff0c;只包含M和O的单词里Bessie最喜欢的是”MOO”&#xff0c;所以她希望按照下面两个规则&…...

OKCC呼叫中心支持哪些接入方式?

使用OKCC系统开展呼叫中心业务&#xff0c;要将电话打通&#xff0c;需要什么样的设备接入到OKCC系统呢&#xff1f; 目前实际广泛使用的接入方式&#xff0c;既有硬件网关接入方式&#xff0c;也有软件接入方式&#xff0c;在生产实践中&#xff0c;我们须根据实际的需求及使…...

如何让手机共享电脑代理网络的WIFI热点

参考&#xff1a; 手机共享电脑的proxy网络 把电脑的网络代理给安卓设备如何将电脑的代理网络以WIFI热点的方式共享 电脑端设置代理&#xff1a; 打开电脑上的 proxy软件并设置其端口号&#xff08;例如&#xff1a;7890&#xff09;&#xff0c;且允许局域网&#xff08;例如…...

渲染有问题?怎么办?6种方法让你渲染无忧

简单点&#xff0c;解决问题的方式简单点。 日常工作中我们总会遇到各种各样的问题&#xff0c;比如渲不出图&#xff0c;速度太慢或效率太低&#xff0c;各种噪点和黑图等等&#xff0c;烦不胜烦&#xff0c;今天我就针对6个常见的问题给大家说下方法&#xff0c;一家之言仅供…...

中国人寿业务稳定性保障:“1+1+N” 落地生产全链路压测

引言 保险业务的数字化转型正如火如荼地进行&#xff0c;产品线上化、投保线上化、承保线上化、核保线上化等业务转型&#xff0c;导致系统的应用范围不断扩大&#xff0c;用户的高频访问也正在成为常态。同时&#xff0c;系统复杂性也呈指数上升&#xff0c;这些因素都增加了…...

2/17考试总结

时间安排 7:40–7:50 读题&#xff0c;T1 貌似是签到&#xff0c;T2,T4 DP,T3看起来很不可做。 7:50–8:00 T1,差分一下然后模拟就行了。 8:00–10:20 T2,注意到值域很小&#xff0c;可以考虑状压&#xff0c;想到一个状压状态数较少的 dp &#xff0c;然后挂得彻底。发现有一…...

零信任-360连接云介绍(9)

​360零信任介绍 360零信任又称360连接云安全访问平台(下文简称为&#xff1a;360连接云)&#xff0c;360连接云&#xff0c;是360基于零信任安全理念&#xff0c;以身份为基础、动态访问控制为核心打造的安全访问平台。 通过收缩业务暴露面、自适应增强身份认证、终端持续检…...

使用dlib进行人脸检测和对齐

最近在配置人脸属性识别的服务&#xff0c;用过faceboxes_detector&#xff08;faster rcnn的包&#xff09;&#xff0c;也用过face_recognition的&#xff0c;但是她们都没有做人脸对齐&#xff0c;而且检测人脸的范围也不太一样。没有做人脸对齐的时候&#xff0c;使用属性识…...

将python代码封装成c版本的dll动态链接库

前言 将python程序打包成DLL文件&#xff0c;然后用C调用生成的DLL文件&#xff0c;这是一种用C调用python的方法&#xff0c;这一块比较容易遇到坑。网上关于这一块的教程不是很多&#xff0c;而且大部分都不能完全解决问题。我在傻傻挣扎了几天之后&#xff0c;终于试出了一个…...

信用渭南网站建设/企业网站seo优化

#include <stdio.h> #define T 10int main() {int i, j, a[T];printf("请输入%d个数字&#xff0c;空格分隔&#xff1a;\n", T - 1);for (i 1; i < T; i) //a[0] 存放交换时的临时数据scanf("%d", &a[i]);for (i 1; i < T; i) …...

上海html5网站建设/苏州网络推广seo服务

作者&#xff1a;范军 &#xff08;Frank Fan&#xff09; 新浪微博&#xff1a;frankfan7核心竞争力&#xff0c;说白了就是一种掌握稀缺资源的能力。你拥有的资源&#xff0c;别人不能很轻易的获得。对于IT技术人而言&#xff0c;我们需要对自己所希望获取的稀缺资源有很清楚…...

osx wordpress/优化关键词技巧

2019独角兽企业重金招聘Python工程师标准>>> 一年一度的秋招已经打响了发令枪&#xff0c;从去年的薪酬排行来看&#xff0c;算法工程师和数据分析等工作排在前列&#xff0c;很多相关专业的学生一直在自学一些网络上的公开课并阅读一些专业书籍&#xff0c;比如“西…...

单位做网站备案用身份证有啥用/百度云登录入口官网

创建一个新的项目IPHONE 的。 项目名&#xff1a;prog3 点击到 main.storyboard 中&#xff0c;再点击 view ,就可以看到手机界面了。 从对象库 object library 中拖控件到界面中即可。 上图指的就是对象库。...

遵义市建设厅网站/网站推广如何引流

python更新1.官网下载安装包&#xff0c;编译安装./configure --prefix/usr/local/pythonmake && make install2.修改旧的python2.7命令 mv /usr/bin/python /usr/bin/python2.7.5链接python3.4的命令 ln -s /usr/local/python/bin/python3.4 /usr/bin/python3.yum 指向…...

好的网站建设网/西安专业seo

关于线性与条带化下LVM增加磁盘数据分布的讨论一、环境介绍二、线性模式逻辑卷创建逻辑卷删除三、条带化逻辑卷创建逻辑卷删除LVM有两种模式&#xff1a;线性模式&#xff1a;先写满组成线性逻辑卷的第一个物理卷&#xff0c;再向第2个物理卷中写入数据&#xff0c;以此类推&am…...