1d08b5235STom Joseph #include <openssl/evp.h> 2d08b5235STom Joseph #include <openssl/hmac.h> 3d08b5235STom Joseph #include <openssl/rand.h> 4*518ecceaSTom Joseph #include <algorithm> 5d08b5235STom Joseph #include <numeric> 6d08b5235STom Joseph #include "crypt_algo.hpp" 7d08b5235STom Joseph #include "message_parsers.hpp" 8d08b5235STom Joseph 9d08b5235STom Joseph namespace cipher 10d08b5235STom Joseph { 11d08b5235STom Joseph 12d08b5235STom Joseph namespace crypt 13d08b5235STom Joseph { 14d08b5235STom Joseph 15d08b5235STom Joseph Interface::Interface(const buffer& sik, const key& addKey) 16d08b5235STom Joseph { 17d08b5235STom Joseph unsigned int mdLen = 0; 18d08b5235STom Joseph 19d08b5235STom Joseph // Generated K2 for the confidentiality algorithm with the additional key 20d08b5235STom Joseph // keyed with SIK. 21d08b5235STom Joseph if (HMAC(EVP_sha1(), sik.data(), sik.size(), addKey.data(), 22d08b5235STom Joseph addKey.size(), k2.data(), &mdLen) == NULL) 23d08b5235STom Joseph { 24d08b5235STom Joseph throw std::runtime_error("Generating K2 for confidentiality algorithm" 25d08b5235STom Joseph "failed"); 26d08b5235STom Joseph } 27d08b5235STom Joseph } 28d08b5235STom Joseph 29*518ecceaSTom Joseph constexpr key AlgoAES128::const2; 30*518ecceaSTom Joseph 31*518ecceaSTom Joseph constexpr std::array<uint8_t, AlgoAES128::AESCBC128BlockSize - 1> 32*518ecceaSTom Joseph AlgoAES128::confPadBytes; 33*518ecceaSTom Joseph 34*518ecceaSTom Joseph buffer AlgoAES128::decryptPayload(const buffer& packet, 35*518ecceaSTom Joseph const size_t sessHeaderLen, 36*518ecceaSTom Joseph const size_t payloadLen) const 37*518ecceaSTom Joseph { 38*518ecceaSTom Joseph auto plainPayload = decryptData( 39*518ecceaSTom Joseph packet.data() + sessHeaderLen, 40*518ecceaSTom Joseph packet.data() + sessHeaderLen + AESCBC128ConfHeader, 41*518ecceaSTom Joseph payloadLen - AESCBC128ConfHeader); 42*518ecceaSTom Joseph 43*518ecceaSTom Joseph /* 44*518ecceaSTom Joseph * The confidentiality pad length is the last byte in the payload, it would 45*518ecceaSTom Joseph * tell the number of pad bytes in the payload. We added a condition, so 46*518ecceaSTom Joseph * that buffer overrun does't happen. 47*518ecceaSTom Joseph */ 48*518ecceaSTom Joseph size_t confPadLength = plainPayload.back(); 49*518ecceaSTom Joseph auto padLength = std::min(plainPayload.size() -1, confPadLength); 50*518ecceaSTom Joseph 51*518ecceaSTom Joseph auto plainPayloadLen = plainPayload.size() - padLength - 1; 52*518ecceaSTom Joseph 53*518ecceaSTom Joseph // Additional check if the confidentiality pad bytes are as expected 54*518ecceaSTom Joseph if(!std::equal(plainPayload.begin() + plainPayloadLen, 55*518ecceaSTom Joseph plainPayload.begin() + plainPayloadLen + padLength, 56*518ecceaSTom Joseph confPadBytes.begin())) 57*518ecceaSTom Joseph { 58*518ecceaSTom Joseph throw std::runtime_error("Confidentiality pad bytes check failed"); 59*518ecceaSTom Joseph } 60*518ecceaSTom Joseph 61*518ecceaSTom Joseph plainPayload.resize(plainPayloadLen); 62*518ecceaSTom Joseph 63*518ecceaSTom Joseph return plainPayload; 64*518ecceaSTom Joseph } 65*518ecceaSTom Joseph 66*518ecceaSTom Joseph buffer AlgoAES128::encryptPayload(buffer& payload) const 67*518ecceaSTom Joseph { 68*518ecceaSTom Joseph auto payloadLen = payload.size(); 69*518ecceaSTom Joseph 70*518ecceaSTom Joseph /* 71*518ecceaSTom Joseph * The following logic calculates the number of padding bytes to be added to 72*518ecceaSTom Joseph * the payload data. This would ensure that the length is a multiple of the 73*518ecceaSTom Joseph * block size of algorithm being used. For the AES algorithm, the block size 74*518ecceaSTom Joseph * is 16 bytes. 75*518ecceaSTom Joseph */ 76*518ecceaSTom Joseph auto paddingLen = AESCBC128BlockSize - ((payloadLen + 1) & 0xF); 77*518ecceaSTom Joseph 78*518ecceaSTom Joseph /* 79*518ecceaSTom Joseph * The additional field is for the Confidentiality Pad Length field. For the 80*518ecceaSTom Joseph * AES algorithm, this number will range from 0 to 15 bytes. This field is 81*518ecceaSTom Joseph * mandatory. 82*518ecceaSTom Joseph */ 83*518ecceaSTom Joseph payload.resize(payloadLen + paddingLen + 1); 84*518ecceaSTom Joseph 85*518ecceaSTom Joseph /* 86*518ecceaSTom Joseph * If no Confidentiality Pad bytes are required, the Confidentiality Pad 87*518ecceaSTom Joseph * Length field is set to 00h. If present, the value of the first byte of 88*518ecceaSTom Joseph * Confidentiality Pad shall be one (01h) and all subsequent bytes shall 89*518ecceaSTom Joseph * have a monotonically increasing value (e.g., 02h, 03h, 04h, etc). 90*518ecceaSTom Joseph */ 91*518ecceaSTom Joseph if (0 != paddingLen) 92*518ecceaSTom Joseph { 93*518ecceaSTom Joseph std::iota(payload.begin() + payloadLen, 94*518ecceaSTom Joseph payload.begin() + payloadLen + paddingLen, 95*518ecceaSTom Joseph 1); 96*518ecceaSTom Joseph } 97*518ecceaSTom Joseph 98*518ecceaSTom Joseph payload.back() = paddingLen; 99*518ecceaSTom Joseph 100*518ecceaSTom Joseph return encryptData(payload.data(), payload.size()); 101*518ecceaSTom Joseph } 102*518ecceaSTom Joseph 103*518ecceaSTom Joseph buffer AlgoAES128::decryptData(const uint8_t* iv, 104*518ecceaSTom Joseph const uint8_t* input, 105*518ecceaSTom Joseph const int inputLen) const 106*518ecceaSTom Joseph { 107*518ecceaSTom Joseph EVP_CIPHER_CTX ctx; 108*518ecceaSTom Joseph 109*518ecceaSTom Joseph // Initializes Cipher context 110*518ecceaSTom Joseph EVP_CIPHER_CTX_init(&ctx); 111*518ecceaSTom Joseph 112*518ecceaSTom Joseph /* 113*518ecceaSTom Joseph * EVP_DecryptInit_ex sets up cipher context ctx for encryption with type 114*518ecceaSTom Joseph * AES-CBC-128. ctx must be initialized before calling this function. K2 is 115*518ecceaSTom Joseph * the symmetric key used and iv is the initialization vector used. 116*518ecceaSTom Joseph */ 117*518ecceaSTom Joseph if (!EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, k2.data(), iv)) 118*518ecceaSTom Joseph { 119*518ecceaSTom Joseph EVP_CIPHER_CTX_cleanup(&ctx); 120*518ecceaSTom Joseph throw std::runtime_error("EVP_DecryptInit_ex failed for type " 121*518ecceaSTom Joseph "AES-CBC-128"); 122*518ecceaSTom Joseph } 123*518ecceaSTom Joseph 124*518ecceaSTom Joseph /* 125*518ecceaSTom Joseph * EVP_CIPHER_CTX_set_padding() enables or disables padding. If the pad 126*518ecceaSTom Joseph * parameter is zero then no padding is performed. This function always 127*518ecceaSTom Joseph * returns 1. 128*518ecceaSTom Joseph */ 129*518ecceaSTom Joseph EVP_CIPHER_CTX_set_padding(&ctx, 0); 130*518ecceaSTom Joseph 131*518ecceaSTom Joseph buffer output(inputLen + AESCBC128BlockSize); 132*518ecceaSTom Joseph 133*518ecceaSTom Joseph int outputLen = 0; 134*518ecceaSTom Joseph 135*518ecceaSTom Joseph /* 136*518ecceaSTom Joseph * If padding is disabled then EVP_DecryptFinal_ex() will not encrypt any 137*518ecceaSTom Joseph * more data and it will return an error if any data remains in a partial 138*518ecceaSTom Joseph * block: that is if the total data length is not a multiple of the block 139*518ecceaSTom Joseph * size. Since AES-CBC-128 encrypted payload format adds padding bytes and 140*518ecceaSTom Joseph * ensures that payload is a multiple of block size, we are not making the 141*518ecceaSTom Joseph * call to EVP_DecryptFinal_ex(). 142*518ecceaSTom Joseph */ 143*518ecceaSTom Joseph if (!EVP_DecryptUpdate(&ctx, output.data(), &outputLen, input, inputLen)) 144*518ecceaSTom Joseph { 145*518ecceaSTom Joseph EVP_CIPHER_CTX_cleanup(&ctx); 146*518ecceaSTom Joseph throw std::runtime_error("EVP_DecryptUpdate failed"); 147*518ecceaSTom Joseph } 148*518ecceaSTom Joseph 149*518ecceaSTom Joseph output.resize(outputLen); 150*518ecceaSTom Joseph EVP_CIPHER_CTX_cleanup(&ctx); 151*518ecceaSTom Joseph 152*518ecceaSTom Joseph return output; 153*518ecceaSTom Joseph } 154*518ecceaSTom Joseph 155*518ecceaSTom Joseph buffer AlgoAES128::encryptData(const uint8_t* input, const int inputLen) const 156*518ecceaSTom Joseph { 157*518ecceaSTom Joseph buffer output(inputLen + AESCBC128BlockSize); 158*518ecceaSTom Joseph 159*518ecceaSTom Joseph // Generate the initialization vector 160*518ecceaSTom Joseph if (!RAND_bytes(output.data(), AESCBC128ConfHeader)) 161*518ecceaSTom Joseph { 162*518ecceaSTom Joseph throw std::runtime_error("RAND_bytes failed"); 163*518ecceaSTom Joseph } 164*518ecceaSTom Joseph 165*518ecceaSTom Joseph EVP_CIPHER_CTX ctx; 166*518ecceaSTom Joseph 167*518ecceaSTom Joseph // Initializes Cipher context 168*518ecceaSTom Joseph EVP_CIPHER_CTX_init(&ctx); 169*518ecceaSTom Joseph 170*518ecceaSTom Joseph /* 171*518ecceaSTom Joseph * EVP_EncryptInit_ex sets up cipher context ctx for encryption with type 172*518ecceaSTom Joseph * AES-CBC-128. ctx must be initialized before calling this function. K2 is 173*518ecceaSTom Joseph * the symmetric key used and iv is the initialization vector used. 174*518ecceaSTom Joseph */ 175*518ecceaSTom Joseph if (!EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, k2.data(), 176*518ecceaSTom Joseph output.data())) 177*518ecceaSTom Joseph { 178*518ecceaSTom Joseph EVP_CIPHER_CTX_cleanup(&ctx); 179*518ecceaSTom Joseph throw std::runtime_error("EVP_EncryptInit_ex failed for type " 180*518ecceaSTom Joseph "AES-CBC-128"); 181*518ecceaSTom Joseph } 182*518ecceaSTom Joseph 183*518ecceaSTom Joseph /* 184*518ecceaSTom Joseph * EVP_CIPHER_CTX_set_padding() enables or disables padding. If the pad 185*518ecceaSTom Joseph * parameter is zero then no padding is performed. This function always 186*518ecceaSTom Joseph * returns 1. 187*518ecceaSTom Joseph */ 188*518ecceaSTom Joseph EVP_CIPHER_CTX_set_padding(&ctx, 0); 189*518ecceaSTom Joseph 190*518ecceaSTom Joseph int outputLen = 0; 191*518ecceaSTom Joseph 192*518ecceaSTom Joseph /* 193*518ecceaSTom Joseph * If padding is disabled then EVP_EncryptFinal_ex() will not encrypt any 194*518ecceaSTom Joseph * more data and it will return an error if any data remains in a partial 195*518ecceaSTom Joseph * block: that is if the total data length is not a multiple of the block 196*518ecceaSTom Joseph * size. Since we are adding padding bytes and ensures that payload is a 197*518ecceaSTom Joseph * multiple of block size, we are not making the call to 198*518ecceaSTom Joseph * EVP_DecryptFinal_ex() 199*518ecceaSTom Joseph */ 200*518ecceaSTom Joseph if (!EVP_EncryptUpdate(&ctx, 201*518ecceaSTom Joseph output.data() + AESCBC128ConfHeader, 202*518ecceaSTom Joseph &outputLen, 203*518ecceaSTom Joseph input, inputLen)) 204*518ecceaSTom Joseph { 205*518ecceaSTom Joseph EVP_CIPHER_CTX_cleanup(&ctx); 206*518ecceaSTom Joseph throw std::runtime_error("EVP_EncryptUpdate failed for type " 207*518ecceaSTom Joseph "AES-CBC-128"); 208*518ecceaSTom Joseph } 209*518ecceaSTom Joseph 210*518ecceaSTom Joseph output.resize(AESCBC128ConfHeader + outputLen); 211*518ecceaSTom Joseph EVP_CIPHER_CTX_cleanup(&ctx); 212*518ecceaSTom Joseph 213*518ecceaSTom Joseph return output; 214*518ecceaSTom Joseph } 215*518ecceaSTom Joseph 216d08b5235STom Joseph }// namespace crypt 217d08b5235STom Joseph 218d08b5235STom Joseph }// namespace cipher 219d08b5235STom Joseph 220d08b5235STom Joseph 221