实现SM4-ECB、CBC、CFB、OFB算法(大数据版)
作者:互联网
base_sm4类参考:
sm4.h
#pragma once #include <algorithm> #include <iostream> #include "D:\C++\实现SM4算法(16字节版)\base_sm4.h" constexpr bool SM4_ENCRYPT = 1; //进行加密运算 constexpr bool SM4_DECRYPT = 0; //进行解密运算 constexpr unsigned SM4_BLOCK_SIZE = 16; //每个分组的大小为16字节,32位 class sm4 : public base_sm4 { public: /* ECB模式的SM4算法 ECB模式是最早采用的简单模式,它将加密的数据分成若干组,每组的大小跟加密密钥长度相同,然后每组都用相同的密钥进行加密。相同的明文会产生相同的密文。 每个分组的运算(加密或解密)都是独立的,每个分组加密只需要密钥和明文分组即可,每个分组解密也只需要密钥和密文分组即可。 in:明文或者密文 out:存储明文或者密文,要求out有足够的空间,且长度不低于in的长度 lenght:in的长度 key:16字节长度的秘钥 type:指定为加密或者解密 */ void sm4Ecb(std::vector<unsigned char>& in, std::vector<unsigned char>& out, const size_t lenght, std::vector<unsigned char>& key, const bool type); /* CBC模式的SM4算法 初始向量(或称初向量)是一个固定长度的比特串。一般使用时会要求它是随机数或伪随机数。使用随机数产生的初始向量,使得同一个密钥加密的结果每次都不同,这样攻击者难以对同一把密钥的密文进行破解。 加密时,第一个明文块和初始向量进行异或后,再用key进行加密,以后每个明文块与前一个分组结果(密文)块进行异或后,再用key进行加密。 解密时,第一个密文块先用key解密,得到的中间结果再与初始向量进行异或后得到第一个明文分组(第一个分组的最终明文结果),后面每个密文块也是先用key解密,得到的中间结果再与前一个密文分组(注意是解密之前的密文分组)进行异或后得到本次明文分组。 in:明文或者密文 out:存储明文或者密文,要求out有足够的空间,且长度不低于in的长度 lenght:in的长度 key:16字节长度的秘钥 ivec:初始向量,16字节 type:指定为加密或者解密 */ void sm4Cbc(std::vector<unsigned char>& in, std::vector<unsigned char>& out, const size_t lenght, std::vector<unsigned char>& key, std::vector<unsigned char>&ivec, const bool type); /* CFB模式的SM4算法 也需要初始向量。 加密第一个分组时,先对初始向量进行加密,得到的中间结果再与第一个明文分组进行异或得到第一个密文分组;加密后面的分组时,把前一个密文分组作为向量先加密,得到的中间结果再与当前明文分组进行异或得到密文分组。 解密第一个分组时,先对初始向量进行加密运算(注意,用的是加密算法),得到的中间结果再与第一个密文分组进行异或得到明文分组;解密后面的分组时,把上一个密文分组当作向量进行加密运算(注意,用的还是加密算法),得到的中间结果再与本次的密文分组进行异或得到本次的明文分组。 in:明文或者密文 out:存储明文或者密文,要求out有足够的空间,且长度不低于in的长度 lenght:in的长度 key:16字节长度的秘钥 ivec:初始向量,16字节 type:指定为加密或者解密 */ void sm4Cfb(std::vector<unsigned char>& in, std::vector<unsigned char>& out, const size_t lenght, std::vector<unsigned char>& key, std::vector<unsigned char>& ivec, const bool type); /* OFB模式的SM4算法 也需要初始向量。 加密第一个分组时,先对初始向量进行加密,得到的中间结果再与第一个明文分组进行异或得到第一个密文分组;加密后面的分组时,把前一个中间结果(前一个分组的向量的密文)作为向量先加密,得到的中间结果再与当前明文分组进行异或得到密文分组。 解密第一个分组时,先对初始向量进行加密运算(注意用的是加密算法),得到的中间结果再与第一个密文分组进行异或得到明文分组;解密后面的分组时,把上一个中间结果(前一个分组的向量的密文,因为用的依然是加密算法)当作向量进行加密运算(注意用的是加密算法),得到的中间结果再与本次的密文分组进行异或得到本次的明文分组。 in:明文或者密文 out:存储明文或者密文,要求out有足够的空间,且长度不低于in的长度 lenght:in的长度 key:16字节长度的秘钥 ivec:初始向量,16字节 */ void sm4Ofb(std::vector<unsigned char>& in, std::vector<unsigned char>& out, const size_t lenght, std::vector<unsigned char>& key, std::vector<unsigned char>& ivec); //ecb加解密检查 int sm4ecbcheck(); //cbc加解密检查 int sm4cbccheck(); //cfb加解密检查 int sm4cfbcheck(); //ofb加解密检查 int sm4ofbcheck(); };View Code
sm4.cpp
#include "sm4.h" void sm4::sm4Ecb(std::vector<unsigned char> &in, std::vector<unsigned char> &out, const size_t lenght, std::vector<unsigned char> &key, const bool type){ size_t len = lenght; //判断参数是否为空,以及判断长度是否为16的倍数 if (in.size() == 0 || out.size() == 0 || key.size() == 0 || lenght % SM4_BLOCK_SIZE != 0) { return; } std::vector<unsigned char>::iterator in_iterator = in.begin(); std::vector<unsigned char>::iterator out_iterator = out.begin(); while (len >= SM4_BLOCK_SIZE) { //SM4加解密的分组大小为128Bit,故对消息进行加解密时,若消息长度过长,则需要进行循环分组加解密。 if (type== SM4_ENCRYPT) { //加密 this->SM4_Encrypt(key.begin(), in_iterator, out_iterator); } else { this->SM4_Decrypt(key.begin(), in_iterator, out_iterator); } len -= SM4_BLOCK_SIZE; //没处理完一个分组,长度就要减去16 in_iterator += SM4_BLOCK_SIZE; //原文数据迭代器偏移16字节,即16个char,指向新的未处理的数据 out_iterator += SM4_BLOCK_SIZE; //结果迭代器也要偏移16字节,即16个char,指向新的未占用的空间 } } void sm4::sm4Cbc(std::vector<unsigned char>& in, std::vector<unsigned char>& out, const size_t lenght, std::vector<unsigned char>& key, std::vector<unsigned char>& ivec, const bool type) { /* * 这个算法支持in和out指向同一个缓冲区(称为原地加解密),根据CBC模式的原理,加密时不必区分in和out是否相同,而解密时需要区分。 */ size_t len = lenght; std::vector<unsigned char> temp(SM4_BLOCK_SIZE, 0); std::vector<unsigned char>::iterator iv_iterator = ivec.begin(); std::vector<unsigned char> iv_temp(SM4_BLOCK_SIZE, 0); //判断参数是否为空,以及判断长度是否为16的倍数 if (in.size() == 0 || out.size() == 0 || key.size() == 0 || ivec.size() == 0 || lenght % SM4_BLOCK_SIZE != 0) { return; } if (type == SM4_ENCRYPT) { //加密 std::vector<unsigned char>::iterator in_iterator = in.begin(); std::vector<unsigned char>::iterator out_iterator = out.begin(); while (len >= SM4_BLOCK_SIZE) { /* * 加密时,第一个明文块和初始向量iv进行异或后,再用key进行加密; * 以后每个明文块与前一个分组结果(密文)块进行异或后,再用key进行加密 * 前一个分组结果(密文)块当做本次iv */ for (int i{}; i < SM4_BLOCK_SIZE; ++i) { out_iterator[i] = in_iterator[i] ^ iv_iterator[i]; } //用key进行加密 this->SM4_Encrypt(key.begin(), out_iterator, out_iterator); iv_iterator = out_iterator; //保存当前结果,以便下一次循环中和明文进行异或运算 len -= SM4_BLOCK_SIZE; //减去已完成的字节数 in_iterator += SM4_BLOCK_SIZE; //偏移明文数据的迭代器,指向未加密的数据开头 out_iterator += SM4_BLOCK_SIZE; //偏移密文数据的迭代器,指向未放置数据的内存 } } else { //解密 std::vector<unsigned char>::iterator in_iterator = in.begin(); std::vector<unsigned char>::iterator out_iterator = out.begin(); //不同的vector的迭代器不能相互比较,哪怕vector的类型、大小等一样,只要迭代器的来源不属于同一个vector,那么就不能比较。 //if (in_iterator != out_iterator) { if (in.data() != out.data()) { //in和out属于不同的缓冲区 while (len >= SM4_BLOCK_SIZE) { //循环分组处理 this->SM4_Decrypt(key.begin(), in_iterator, out_iterator); for (int i{}; i < SM4_BLOCK_SIZE; ++i) { out_iterator[i] = out_iterator[i] ^ iv_iterator[i]; } iv_iterator = in_iterator; len -= SM4_BLOCK_SIZE; //减去已完成的字节数 in_iterator+= SM4_BLOCK_SIZE; //偏移密文数据迭代器,指向还没解密的数据开头 out_iterator += SM4_BLOCK_SIZE;; //偏移结果数据指针,指向未放置数据的内存 } } else { //in和out属于相同的缓冲区 iv_temp.insert(iv_temp.end(), ivec.begin(), ivec.begin() + SM4_BLOCK_SIZE); while (len >= SM4_BLOCK_SIZE) { //暂存本次分组密文,因为in要存放结果明文 temp.insert(temp.end(), in.begin(), in.begin() + SM4_BLOCK_SIZE); this->SM4_Encrypt(key.begin(), in_iterator, out_iterator); for (int i{}; i < SM4_BLOCK_SIZE; ++i) { out_iterator[i] = out_iterator[i] ^ iv_temp[i]; } iv_temp.clear(); iv_temp.insert(iv_temp.end(), temp.begin(), temp.begin() + SM4_BLOCK_SIZE); len -= SM4_BLOCK_SIZE; //减去已完成的字节数 in_iterator += SM4_BLOCK_SIZE; //偏移密文数据迭代器,指向还没解密的数据开头 out_iterator += SM4_BLOCK_SIZE;; //偏移结果数据指针,指向未放置数据的内存 } } } } void sm4::sm4Cfb(std::vector<unsigned char>& in, std::vector<unsigned char>& out, const size_t lenght, std::vector<unsigned char>& key, std::vector<unsigned char>& ivec, const bool type) { //CFB模式和CBC类似,也需要IV rsize_t len = lenght; unsigned char ch{}; std::vector<unsigned char> iv; //判断参数是否为空,以及判断长度是否为16的倍数 if (in.size() == 0 || out.size() == 0 || key.size() == 0 || ivec.size() == 0 || lenght % SM4_BLOCK_SIZE != 0) { return; } iv.insert(iv.begin(), ivec.begin(), ivec.begin() + SM4_BLOCK_SIZE); std::vector<unsigned char>::iterator in_iterator = in.begin(); std::vector<unsigned char>::iterator out_iterator = out.begin(); if (type == SM4_ENCRYPT) { //加密 std::vector<unsigned char>::iterator iv_iterator = iv.begin(); int i{}; while (len--) { if (!i) { //第一次循环才进入这里 this->SM4_Encrypt(key.begin(), iv_iterator, iv_iterator); } iv[i] = *(out_iterator++) = *(in_iterator++) ^ iv[i]; i = (i + 1) % SM4_BLOCK_SIZE; //上面两行代码就很精妙,实现了iv始终在0~SM4_BLOCK_SIZE之间 } } else { //解密 //解密也是使用的SM4_Encrypt std::vector<unsigned char>::iterator iv_iterator = iv.begin(); int i{}; while (len--) { if (!i) { this->SM4_Encrypt(key.begin(), iv_iterator, iv_iterator); } ch = *in_iterator; *(out_iterator++) = *(in_iterator++) ^ iv[i]; //上面这句代码应该可以换成*(++out_iterator) = *(++in_iterator) ^ iv[i]; iv[i]=ch; i = (i + 1) % SM4_BLOCK_SIZE; //上面两行代码就很精妙,实现了iv始终在0~SM4_BLOCK_SIZE之间 } } } void sm4::sm4Ofb(std::vector<unsigned char>& in, std::vector<unsigned char>& out, const size_t lenght, std::vector<unsigned char>& key, std::vector<unsigned char>& ivec) { size_t len = lenght; std::vector<unsigned char> iv; //判断参数是否为空,以及判断长度是否为16的倍数 if (in.size() == 0 || out.size() == 0 || key.size() == 0 || ivec.size() == 0 || lenght % SM4_BLOCK_SIZE != 0) { return; } iv.insert(iv.begin(), ivec.begin(), ivec.begin() + SM4_BLOCK_SIZE); std::vector<unsigned char>::iterator in_iterator = in.begin(); std::vector<unsigned char>::iterator out_iterator = out.begin(); std::vector<unsigned char>::iterator iv_iterator = iv.begin(); //OFB模式的加密和解密是一致的 int i{}; while (--len) { if (!i) { this->SM4_Encrypt(key.begin(), iv_iterator, iv_iterator); } *(++out_iterator) = *(++in_iterator) ^ iv[i]; i = (i + 1) % SM4_BLOCK_SIZE; } } int sm4::sm4ecbcheck(){ int i, len, ret = 0; std::vector<unsigned char> key{ 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 }; std::vector<unsigned char> plain{ 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 }; std::vector<unsigned char> cipher{ 0x68,0x1e,0xdf,0x34,0xd2,0x06,0x96,0x5e,0x86,0xb3,0xe9,0x4f,0x53,0x6e,0x42,0x46 }; std::vector<unsigned char> En_output; std::vector<unsigned char> De_output; std::vector<unsigned char> in; std::vector<unsigned char> out; std::vector<unsigned char> chk; En_output.resize(16); //需要提前准备好充足的空间 this->sm4Ecb(plain, En_output, 16, key, SM4_ENCRYPT); //比较两个缓冲区的值是否一致 if (std::equal(cipher.begin(), cipher.end(), En_output.begin())) { std::cout << "ecb enc(len=16) memcmp ok\n"; } else { std::cout << "ecb enc(len=16) memcmp failed\n"; std::cout << "En_output:\n"; std::copy(En_output.begin(), En_output.end(), std::ostream_iterator<unsigned>(std::cout, ",")); std::cout << "cipher:\n"; std::copy(cipher.begin(), cipher.end(), std::ostream_iterator<unsigned>(std::cout, ",")); std::cout << "\n"; } ////比较两个缓冲区的值是否一致 //if (memcmp(En_output.data(), cipher.data(), cipher.size())) { // puts("ecb enc(len=16) memcmp failed"); //} //else puts("ecb enc(len=16) memcmp ok"); De_output.resize(SM4_BLOCK_SIZE); ////需要提前准备好充足的空间 this->sm4Ecb(cipher, De_output, SM4_BLOCK_SIZE, key, SM4_DECRYPT); //比较两个缓冲区的值是否一致 if (std::equal(plain.begin(), plain.end(), De_output.begin())) { std::cout << "ecb dec(len=16) memcmp ok\n"; } else { std::cout << "ecb dec(len=16) memcmp failed\n"; std::cout << "En_output:\n"; std::copy(De_output.begin(), De_output.end(), std::ostream_iterator<unsigned>(std::cout, ",")); std::cout << "cipher:\n"; std::copy(cipher.begin(), cipher.end(), std::ostream_iterator<unsigned>(std::cout, ",")); std::cout << "\n"; } //if (memcmp(De_output.data(), plain.data(), SM4_BLOCK_SIZE)) puts("ecb dec(len=16) memcmp failed"); //else puts("ecb dec(len=16) memcmp ok"); len = 32; for (i = 0; i < 8; i++) { //memset(in, i, len); in.insert(in.end(), len, i); out.resize(in.size()); //这里是默认了为16的倍数 this->sm4Ecb(in, out, len, key, SM4_ENCRYPT); //加密 chk.resize(in.size()); //这里是默认了为16的倍数 this->sm4Ecb(out, chk, len, key, SM4_DECRYPT); //解密 if (std::equal(in.begin(), in.end(), chk.begin())) { std::cout << "ecb enc(len=" << len << ") memcmp ok\n"; } else { std::cout << "ecb enc(len=" << len << ") memcmp failed\n"; } //if (memcmp(in.data(), chk.data(), len)) printf("ecb enc/dec(len=%d) memcmp failed\n", len); //else printf("ecb enc/dec(len=%d) memcmp ok\n", len); len = 2 * len; in.clear(); } return 0; } int sm4::sm4cbccheck() { int i, len, ret = 0; std::vector<unsigned char> key { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };//密钥 std::vector<unsigned char> iv { 0xeb,0xee,0xc5,0x68,0x58,0xe6,0x04,0xd8,0x32,0x7b,0x9b,0x3c,0x10,0xc9,0x0c,0xa7 }; //初始化向量 std::vector<unsigned char> plain { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,0x29,0xbe,0xe1,0xd6,0x52,0x49,0xf1,0xe9,0xb3,0xdb,0x87,0x3e,0x24,0x0d,0x06,0x47 }; //明文 std::vector<unsigned char> cipher { 0x3f,0x1e,0x73,0xc3,0xdf,0xd5,0xa1,0x32,0x88,0x2f,0xe6,0x9d,0x99,0x6c,0xde,0x93,0x54,0x99,0x09,0x5d,0xde,0x68,0x99,0x5b,0x4d,0x70,0xf2,0x30,0x9f,0x2e,0xf1,0xb7 }; //密文 std::vector<unsigned char> En_output; std::vector<unsigned char> De_output; std::vector<unsigned char> in; std::vector<unsigned char> out; std::vector<unsigned char> chk; En_output.resize(plain.size()); //sizeof是输出的字节数,对于这里其实就是长度 this->sm4Cbc(plain, En_output, plain.size(), key, iv, SM4_ENCRYPT); //加密 //比较是否相等 if (std::equal(cipher.begin(), cipher.end(), En_output.begin())) { std::cout << "cbc enc(len=16) memcmp ok\n"; } else { std::cout << "cbc enc(len=16) memcmp failed\n"; std::cout << "En_output:\n"; std::copy(En_output.begin(), En_output.end(), std::ostream_iterator<unsigned>(std::cout, ",")); std::cout << "cipher:\n"; std::copy(cipher.begin(), cipher.end(), std::ostream_iterator<unsigned>(std::cout, ",")); std::cout << "\n"; } //if (memcmp(En_output, cipher, 16)) puts("cbc enc(len=32) memcmp failed"); //else puts("cbc enc(len=32) memcmp ok"); De_output.resize(cipher.size()); this->sm4Cbc(cipher, De_output, cipher.size(), key, iv, SM4_DECRYPT); //比较是否相等 if (std::equal(plain.begin(), plain.end(), De_output.begin())) { std::cout << "cbc dec(len=16) memcmp ok\n"; } else { std::cout << "cbc dec(len=16) memcmp failed\n"; std::cout << "En_output:\n"; std::copy(De_output.begin(), De_output.end(), std::ostream_iterator<unsigned>(std::cout, ",")); std::cout << "cipher:\n"; std::copy(plain.begin(), plain.end(), std::ostream_iterator<unsigned>(std::cout, ",")); std::cout << "\n"; } /*if (memcmp(De_output, plain, SM4_BLOCK_SIZE)) puts("cbc dec(len=32) memcmp failed"); else puts("cbc dec(len=32) memcmp ok");*/ len = 32; for (i = 0; i < 8; i++) { //memset(in, i, len); in.resize(len, i); out.resize(len); this->sm4Cbc(in, out, len, key, iv, SM4_ENCRYPT); chk.resize(len); this->sm4Cbc(out, chk, len, key, iv, SM4_DECRYPT); //比较是否相等 if (std::equal(in.begin(), in.end(), chk.begin())) { std::cout << "cbc enc/dec(len=" << len << ") memcmp ok\n"; } else { std::cout << "cbc enc/dec(len=" << len << ") memcmp failed\n"; std::cout << "En_output:\n"; std::copy(in.begin(), in.end(), std::ostream_iterator<unsigned>(std::cout, ",")); std::cout << "cipher:\n"; std::copy(chk.begin(), chk.end(), std::ostream_iterator<unsigned>(std::cout, ",")); } //if (memcmp(in, chk, len)) printf("cbc enc/dec(len=%d) memcmp failed\n", len); //else printf("cbc enc/dec(len=%d) memcmp ok\n", len); len = 2 * len; } return 0; } int sm4::sm4cfbcheck() { int i, len, ret = 0; std::vector<unsigned char> key{ 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };//密钥 std::vector<unsigned char> iv{ 0xeb,0xee,0xc5,0x68,0x58,0xe6,0x04,0xd8,0x32,0x7b,0x9b,0x3c,0x10,0xc9,0x0c,0xa7 }; //初始化向量 std::vector<unsigned char> in; std::vector<unsigned char> out; std::vector<unsigned char> chk; len = 16; for (i = 0; i < 9; i++) { in.resize(len, i); out.resize(len); chk.resize(len); this->sm4Cfb(in, out, len, key, iv, SM4_ENCRYPT); this->sm4Cfb(out, chk, len, key, iv, SM4_DECRYPT); //比较是否相等 if (std::equal(in.begin(), in.end(), chk.begin())) { std::cout << "cfb enc/dec(len=" << len << ") memcmp ok\n"; } else { std::cout << "\ncfb enc/dec(len=" << len << ") memcmp failed"; std::cout << "\nin:"; std::copy(in.begin(), in.end(), std::ostream_iterator<unsigned>(std::cout, ",")); std::cout << "\nout:"; std::copy(out.begin(), out.end(), std::ostream_iterator<unsigned>(std::cout, ",")); std::cout << "\nchk:"; std::copy(chk.begin(), chk.end(), std::ostream_iterator<unsigned>(std::cout, ",")); break; } /*if (memcmp(in, chk, len)) printf("cfb enc/dec(len=%d) memcmp failed\n", len); else printf("cfb enc/dec(len=%d) memcmp ok\n", len);*/ len = 2 * len; } return 0; } int sm4::sm4ofbcheck() { int i, len, ret = 0; std::vector<unsigned char> key{ 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 };//密钥 std::vector<unsigned char> iv{ 0xeb,0xee,0xc5,0x68,0x58,0xe6,0x04,0xd8,0x32,0x7b,0x9b,0x3c,0x10,0xc9,0x0c,0xa7 }; //初始化向量 std::vector<unsigned char> in; std::vector<unsigned char> out; std::vector<unsigned char> chk; len = 16; for (i = 0; i < 9; i++) { out.resize(len); chk.resize(len); in.resize(len, i); this->sm4Ofb(in, out, len, key, iv); this->sm4Ofb(out, chk, len, key, iv); //比较是否相等 if (std::equal(in.begin(), in.end(), chk.begin())) { std::cout << "ofb enc/dec(len=" << len << ") memcmp ok\n"; } else { std::cout << "\nofb enc/dec(len=" << len << ") memcmp failed"; std::cout << "\nin:"; std::copy(in.begin(), in.end(), std::ostream_iterator<unsigned>(std::cout, ",")); std::cout << "\nout:"; std::copy(out.begin(), out.end(), std::ostream_iterator<unsigned>(std::cout, ",")); std::cout << "\nchk:"; std::copy(chk.begin(), chk.end(), std::ostream_iterator<unsigned>(std::cout, ",")); break; } /*if (memcmp(in, chk, len)) printf("ofb enc/dec(len=%d) memcmp failed\n", len); else printf("ofb enc/dec(len=%d) memcmp ok\n", len);*/ len = 2 * len; } return 0; }View Code
实现SM4-ECB、CBC、CFB、OFB算法(大数据版).cpp
// 实现SM4-ECB、CBC、CFB、OFB算法(大数据版).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <iostream> #include "sm4.h" int main() { sm4 s; s.sm4ofbcheck(); } // 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单 // 调试程序: F5 或调试 >“开始调试”菜单 // 入门使用技巧: // 1. 使用解决方案资源管理器窗口添加/管理文件 // 2. 使用团队资源管理器窗口连接到源代码管理 // 3. 使用输出窗口查看生成输出和其他消息 // 4. 使用错误列表窗口查看错误 // 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目 // 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件View Code
标签:OFB,CBC,ECB,iterator,SM4,len,std,vector,out 来源: https://www.cnblogs.com/love-DanDan/p/16691875.html