자작소스/C++/MFC/API

AES128 CBC PKCS5 HMAC(SHA256) 암/복호화(C++)

와이즈번 2016. 5. 10. 15:03

1. 헤더파일

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef UTILS_CRYPTO_H
#define UTILS_CRYPTO_H
 
#include <string>
#include <stdio.h>
#include "os/Compat.h"
#include "cryptopp/config.h"
 
 
class UtilsCrypto
{
public:
    UtilsCrypto(void);
    ~UtilsCrypto(void);
 
    static void hex2byte(const char *in, _UInt32 len, byte *out);
    static std::string MD5HASH(std::string);
    static std::string SHA256HASH(std::string);
    
    static std::string encrypt(std::string);
    static std::string decrypt(std::string);
};
 
#endif



2. cpp파일

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
 
#include "UtilsCrypto.h"
#include "cryptopp/cryptlib.h"
#include "cryptopp/modes.h"
#include "cryptopp/aes.h"
#include "cryptopp/filters.h"
#include "cryptopp/base64.h"
#include "cryptopp/md5.h"
#include "cryptopp/hex.h"
#include "cryptopp/sha.h"
#include "cryptopp/hmac.h"
 
UtilsCrypto::UtilsCrypto(void)
{
}
 
 
UtilsCrypto::~UtilsCrypto(void)
{
}
 
void UtilsCrypto::hex2byte(const char *in, _UInt32 len, byte *out)
{
    for(_UInt32 i = 0; i < len; i+=2)
    {
        char c0 = in[i+0];
        char c1 = in[i+1];
        byte c = (
            ((c0 & 0x40 ? (c0 & 0x20 ? c0 - 0x57 : c0 - 0x37) : c0 - 0x30<< 4|
            ((c1 & 0x40 ? (c1 & 0x20 ? c1 - 0x57 : c1 - 0x37) : c1 - 0x30))
        );
        out[i/2= c;
    }
}
 
std::string UtilsCrypto::MD5HASH(std::string str)
{
    CryptoPP::Weak::MD5 hash;
    byte digest[CryptoPP::Weak::MD5::DIGESTSIZE];
    
    hash.CalculateDigest(digest, (byte*)str.c_str(), str.length());
 
    CryptoPP::HexEncoder encoder;
    std::string output;
    encoder.Attach(new CryptoPP::StringSink(output));
    encoder.Put(digest, sizeof(digest));
    encoder.MessageEnd();
 
    return output;
}
 
std::string UtilsCrypto::SHA256HASH(std::string str)
{
    byte const* pbData = (byte*)str.data();
    _UInt32 nDataLen = str.size();
    byte abDigest[CryptoPP::SHA256::DIGESTSIZE];
 
    CryptoPP::SHA256().CalculateDigest(abDigest, pbData, nDataLen);
 
    return std::string((char*)abDigest, 32);
}
 
std::string UtilsCrypto::encrypt(std::string str)
{
    if (str.empty())
        return std::string();
 
    std::string enc_key = MD5HASH("비밀키");
    std::string enc_iv = MD5HASH("IV키");
    std::string enc_hash = MD5HASH("HMAC키");
 
    //키할당
    byte key[CryptoPP::AES::DEFAULT_KEYLENGTH];
    memset(key, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH);
    const char* rawKey = enc_key.c_str();
    hex2byte(rawKey, strlen(rawKey), key);
 
    //iv할당
    byte iv[CryptoPP::AES::BLOCKSIZE];
    memset(iv, 0x00, CryptoPP::AES::BLOCKSIZE);
    const char* rawIv = enc_iv.c_str();
    hex2byte(rawIv, strlen(rawIv), iv);
 
    //hash키할당
    byte hashKey[CryptoPP::AES::DEFAULT_KEYLENGTH];
    memset(hashKey, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH);
    const char* rawHashKey = enc_hash.c_str();
    hex2byte(rawHashKey, strlen(rawHashKey), hashKey);
 
    std::string cipher, hmac, encoded;
    try {
        CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption e;
        e.SetKeyWithIV(key, sizeof(key), iv);
 
        CryptoPP::StringSource ss(str, truenew CryptoPP::StreamTransformationFilter(e, new CryptoPP::StringSink(cipher), CryptoPP::BlockPaddingSchemeDef::PKCS_PADDING));
        CryptoPP::HMAC<CryptoPP::SHA256> hmac_hash(hashKey, sizeof(hashKey));
        CryptoPP::StringSource(cipher, truenew CryptoPP::HashFilter(hmac_hash, new CryptoPP::StringSink(hmac)));
        CryptoPP::StringSource(cipher + hmac, truenew CryptoPP::Base64Encoder(new CryptoPP::StringSink(encoded), false));
 
        return encoded;
    } catch (const CryptoPP::Exception &e) {
        std::cerr << e.what() << std::endl;
        return std::string();
    }
}
 
std::string UtilsCrypto::decrypt(std::string str)
{
    if (str.empty())
        return std::string();
 
    std::string enc_key = MD5HASH("비밀키");
    std::string enc_iv = MD5HASH("IV키");
    std::string enc_hash = MD5HASH("HMAC키");
 
    //키할당
    byte key[CryptoPP::AES::DEFAULT_KEYLENGTH];
    memset(key, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH);
    const char* rawKey = enc_key.c_str();
    hex2byte(rawKey, strlen(rawKey), key);
 
    //iv할당
    byte iv[CryptoPP::AES::BLOCKSIZE];
    memset(iv, 0x00, CryptoPP::AES::BLOCKSIZE);
    const char* rawIv = enc_iv.c_str();
    hex2byte(rawIv, strlen(rawIv), iv);
 
    //hash키할당
    byte hashKey[CryptoPP::AES::DEFAULT_KEYLENGTH];
    memset(hashKey, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH);
    const char* rawHashKey = enc_hash.c_str();
    hex2byte(rawHashKey, strlen(rawHashKey), hashKey);
 
    std::string tmp, cipher, hmac, hmac2, decoded;
    try
    {
        CryptoPP::StringSource(str, truenew CryptoPP::Base64Decoder(new CryptoPP::StringSink(tmp)));
 
        if (tmp.size() < 48)
            return std::string();
 
        cipher = tmp.substr(0, tmp.size() - 32);
        hmac = tmp.substr(tmp.size() - 3232);
 
        CryptoPP::HMAC<CryptoPP::SHA256> hmac_hash(hashKey, sizeof(hashKey));
        CryptoPP::StringSource(cipher, truenew CryptoPP::HashFilter(hmac_hash, new CryptoPP::StringSink(hmac2)));
 
        if (hmac.compare(hmac2) != 0)
            return std::string();
 
        CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption d;
        d.SetKeyWithIV(key, sizeof(key), iv);
 
        CryptoPP::StringSource ss(cipher, truenew CryptoPP::StreamTransformationFilter(d, new CryptoPP::StringSink(decoded), CryptoPP::BlockPaddingSchemeDef::PKCS_PADDING));
 
        return decoded;
    } 
    catch(const CryptoPP::Exception &e)
    {
        std::cerr << e.what() << std::endl;
        return std::string();
    }
}