实验一

常用密码学原语的C++代码使用


1. Crypto++部署与测试

Crypto++部署

本文采用Windows子系统wsl2进行部署测试

  • 从官网下载Crypto++ (https://www.cryptopp.com/)
  • make -j4
  • make install PREFIX=./path 使用path指定安装路径
  • g++ hw1.cpp -I /usr/local/bin/include/cryptopp -o hw1.exe /usr/local/bin/lib/libcryptopp.a 使用g++进行编译

Crypto++测试

  • 使用SHA384进行测试
  • 这里利用StringSource的方法进行函数调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 使用SHA384进行加密
void encryptSHA384(string& plain){
std::string cipher, encoded;
SHA384 hash;
StringSource ss1(plain, true,
new HashFilter(hash,
new HexEncoder(
new StringSink( cipher ) ) ) ); // HashFilter
std::cout << "(SHA384) The cipher text is: " << cipher << std::endl;
}

int main(int argc, char* argv[]){
// 测试代码
string in_string = "Hello World";
CryptoPP::byte key[AES::DEFAULT_KEYLENGTH] = "abcd1234";

cout << "Original text is: " << in_string << endl;
cout << "Key is: " << key << endl;
// 使用SHA384进行加密
encryptSHA384(in_string);
...
}

img

Crypto++使用

字符串、二进制、十六进制相互转换

  • 任务比较简单,两两转换共需要6个函数,这里我们采用环形转换的方式,即字符串转二进制、二进制转十六进制、十六进制转字符串,这样即可说明可以互相转化,我们实现3个函数即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 字符串转2进制
string string_to_bit(string& plain){
std::string encoded = "";
for(auto c: plain){
bitset<8> bs(c);
encoded += bs.to_string();
}
std::cout << "Binary Encoder text is: " << encoded << std::endl;
return encoded;
}

// 2进制转16进制
string bit_to_hex(string& plain){
std::string encoded;
for(int i = 0; i < plain.length(); i += 8){
stringstream ss;
string ts;
ss << std::hex << stoi(plain.substr(i, 8), nullptr, 2);
ss >> ts;
transform(ts.begin(), ts.end(), ts.begin(), ::toupper);
encoded += ts;
}
cout << "Hex Encoder text is: " << encoded << endl;
return encoded;
}

// 16进制转字符串
string hex_to_string(string& plain){
std::string encoded;
StringSource ss2( plain, true,
new HexDecoder(
new StringSink( encoded )
) // HexDecoder
); // StringSource
std::cout << "String text is: " << encoded << std::endl;
return encoded;
}

int main(){
...
// 进制转换
string bits,hexs,strs;
bits = string_to_bit(in_string);
hexs = bit_to_hex(bits);
strs = hex_to_string(hexs);
}

img

  • 通过转换我们可以发现,最后结果和初始输入相同

哈希:Sha1哈希、MD5哈希、Sha256哈希

  • 使用Crypto中的哈希类实现
  • 几类哈希方法使用方法类似,这里使用StringSource的方法,以十六进制输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// Sha1哈希加密
string encryptSHA1(string& plain){
std::string cipher, encoded;
SHA1 hash;
StringSource ss1(plain, true,
new HashFilter(hash,
new HexEncoder(
new StringSink( cipher ) ) ) ); // HashFilter
std::cout << "(SHA1) The cipher text is: " << cipher << std::endl;
return cipher;
}

// MD5哈希
string encryptMD5(string& plain){
std::string cipher, encoded;
MD5 hash;
StringSource ss1(plain, true,
new HashFilter(hash,
new HexEncoder(
new StringSink( cipher ) ) ) ); // HashFilter
std::cout << "(MD5) The cipher text is: " << cipher << std::endl;
return cipher;
}

// SHA256哈希
string encryptSHA256(string& plain){
std::string cipher, encoded;
SHA256 hash;
StringSource ss1(plain, true,
new HashFilter(hash,
new HexEncoder(
new StringSink( cipher ) ) ) ); // HashFilter
std::cout << "(SHA256) The cipher text is: " << cipher << std::endl;
return cipher;
}

int main(int argc, char* argv[]){
...
// Sha1哈希
encryptSHA1(in_string);
// MD5哈希
encryptMD5(in_string);
// Sha256哈希
encryptSHA256(in_string);
}

img

对称加密、解密:AES、DES

  • 采用ECB的模式构造AES、DES
  • 密钥为“abcd1234”,长度分别为16、8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// AES加密
string encryptAES(string& plain, CryptoPP::byte* key){
std::string cipher, encoded;
ECB_Mode<AES>::Encryption e;
e.SetKey(key, 16);
// The StreamTransformationFilter removes
// padding as required.
StringSource ss1(plain, true,
new StreamTransformationFilter(e,
new StringSink(cipher)) // StreamTransformationFilter
);
std::cout << "(AES) The cipher text is: " << cipher << std::endl;

StringSource ss2( cipher, true,
new HexEncoder(
new StringSink( encoded )
) // HexDecoder
);
std::cout << "(AES) The hex text is: " << encoded << std::endl;
return cipher;
}

string decryptAES(string& cipher, CryptoPP::byte* key){
std::string recovered;
ECB_Mode<AES>::Decryption d;
d.SetKey(key, 16);
// The StreamTransformationFilter removes
// padding as required.
StringSource ss1(cipher, true,
new StreamTransformationFilter(d,
new StringSink(recovered)) // StreamTransformationFilter
);
std::cout << "(AES) The recovered text is: " << recovered << std::endl;
return recovered;
}

// DES加密
string encryptDES(string& plain, CryptoPP::byte* key){
string cipher, encoded;
ECB_Mode<DES>::Encryption e;
e.SetKey(key, 8);
// The StreamTransformationFilter removes
// padding as required.
StringSource ss1(plain, true,
new StreamTransformationFilter(e,
new StringSink(cipher)) // StreamTransformationFilter
);
std::cout << "(DES) The cipher text is: " << cipher << std::endl;

StringSource ss2( cipher, true,
new HexEncoder(
new StringSink( encoded )
) // HexDecoder
);
std::cout << "(DES) The hex text is: " << encoded << std::endl;
return cipher;
}

string decryptDES(string& cipher, CryptoPP::byte* key){
std::string recovered;
ECB_Mode<DES>::Decryption d;
d.SetKey(key, 8);
// The StreamTransformationFilter removes
// padding as required.
StringSource ss1(cipher, true,
new StreamTransformationFilter(d,
new StringSink(recovered)) // StreamTransformationFilter
);
std::cout << "(DES) The recovered text is: " << recovered << std::endl;
return recovered;
}

img

RSA非对称加密:秘钥对生成、加密、解密、签名

  • 秘钥对生成
  • key_size为2048位
1
2
3
4
5
6
7
8
9
10
11
// 生成密钥
void generate_key(const unsigned int key_size, RSA::PrivateKey& private_key, RSA::PublicKey& public_key) //钥匙的长度,通常是2048以上,越大相对越安全,但相对的运算越久
{
AutoSeededRandomPool rng; //伪随机数
InvertibleRSAFunction params;
params.GenerateRandomWithKeySize(rng, key_size);
RSA::PrivateKey privateKey(params);
RSA::PublicKey publicKey(params);
private_key = privateKey;
public_key = publicKey;
}
  • 加密
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// RSA加密
string encryptRSA(string& plain, RSA::PublicKey& public_key){
string cipher,encoded;
AutoSeededRandomPool rng;
const RSAES_OAEP_SHA_Encryptor encrypt(public_key);
StringSource ss_1(plain, true, new
PK_EncryptorFilter(rng, encrypt, new StringSink(cipher)));
cout << "(RSA) The cipher text is: " << cipher << endl;

StringSource ss_2(cipher, true,
new HexEncoder(new StringSink(encoded)));
cout << "(RSA) The encoded text is: " << encoded << endl;
return cipher;
}
  • 解密
1
2
3
4
5
6
7
8
9
10
// RSA解密
string decryptRSA(string& cipher, RSA::PrivateKey& private_key){
string recovered;
AutoSeededRandomPool rng;
RSAES_OAEP_SHA_Decryptor d(private_key);
StringSource ss2(cipher, true, new
PK_DecryptorFilter(rng, d, new StringSink(recovered)));
cout << "(RSA) The recovered text is: " << recovered << endl;
return recovered;
}
  • 签名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// RSA签名
string signatureRSA(string& plain, RSA::PrivateKey& private_key){
string signature, encoded;
AutoSeededRandomPool rng;
const RSASS<PSS, SHA256>::Signer signer(private_key);
StringSource ss(plain, true,
new SignerFilter(rng, signer, new StringSink(signature)));
cout << "(RSA) The signature is: " << signature << endl;

StringSource ss2(signature, true,
new HexEncoder(new StringSink(encoded)));
cout << "(RSA) The encoded signature is: " << encoded << endl;
return signature;
}
  • 验证
  • 验证同时需要明文和签名
1
2
3
4
5
6
7
8
9
10
// RSA验证
string verifyRSA(string& signature, RSA::PublicKey& public_key){
string recovered;
const RSASS<PSS, SHA256>::Verifier verifier(public_key);
StringSource ss(signature, true,
new SignatureVerificationFilter(verifier, new StringSink(recovered),
SignatureVerificationFilter::THROW_EXCEPTION));
cout << "(RSA) Verified signature on message" << endl;
return recovered;
}
  • 测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main(int argc, char* argv[]){
...
// RSA
RSA::PrivateKey private_key;
RSA::PublicKey public_key;
string cipher,sign,recovered,plain_cipher;
generate_key(2048, private_key, public_key);
cipher = encryptRSA(in_string, public_key);
decryptRSA(cipher, private_key);
sign = signatureRSA(in_string, private_key);
plain_cipher = in_string + sign;
verifyRSA(plain_cipher, public_key);
return 0;
}

img

总结

  • 利用Crypto++方法库,学习使用了主要的加解密算法
  • 代码和实验结果另附文件