508 lines
15 KiB
C++
508 lines
15 KiB
C++
|
|
#include <atomic>
|
|||
|
|
#include "Util/MD5.h"
|
|||
|
|
#include "Util/logger.h"
|
|||
|
|
|
|||
|
|
#include "Crypto.hpp"
|
|||
|
|
|
|||
|
|
#if defined(ENABLE_OPENSSL)
|
|||
|
|
#include "openssl/evp.h"
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
using namespace toolkit;
|
|||
|
|
using namespace std;
|
|||
|
|
using namespace SRT;
|
|||
|
|
|
|||
|
|
namespace SRT {
|
|||
|
|
|
|||
|
|
#if defined(ENABLE_OPENSSL)
|
|||
|
|
inline const EVP_CIPHER* aes_key_len_mapping_wrap_cipher(int key_len) {
|
|||
|
|
switch (key_len) {
|
|||
|
|
case 192/8: return EVP_aes_192_wrap();
|
|||
|
|
case 256/8: return EVP_aes_256_wrap();
|
|||
|
|
case 128/8:
|
|||
|
|
default:
|
|||
|
|
return EVP_aes_128_wrap();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
inline const EVP_CIPHER* aes_key_len_mapping_ctr_cipher(int key_len) {
|
|||
|
|
switch (key_len) {
|
|||
|
|
case 192/8: return EVP_aes_192_ctr();
|
|||
|
|
case 256/8: return EVP_aes_256_ctr();
|
|||
|
|
case 128/8:
|
|||
|
|
default:
|
|||
|
|
return EVP_aes_128_ctr();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief: aes_wrap
|
|||
|
|
* @param [in]: in 待warp的数据
|
|||
|
|
* @param [in]: in_len 待warp的数据长度
|
|||
|
|
* @param [out]: out warp后输出的数据
|
|||
|
|
* @param [out]: outLen 加密后输出的数据长度
|
|||
|
|
* @param [in]: key 密钥
|
|||
|
|
* @param [in]: key_len 密钥长度
|
|||
|
|
* @return : true: 成功,false: 失败
|
|||
|
|
**/
|
|||
|
|
static bool aes_wrap(const uint8_t* in, int in_len, uint8_t* out, int* outLen, uint8_t* key, int key_len) {
|
|||
|
|
|
|||
|
|
#if defined(ENABLE_OPENSSL)
|
|||
|
|
EVP_CIPHER_CTX* ctx = NULL;
|
|||
|
|
|
|||
|
|
*outLen = 0;
|
|||
|
|
|
|||
|
|
do {
|
|||
|
|
if (!(ctx = EVP_CIPHER_CTX_new())) {
|
|||
|
|
WarnL << "EVP_CIPHER_CTX_new fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
|
|||
|
|
|
|||
|
|
if (1 != EVP_EncryptInit_ex(ctx, aes_key_len_mapping_wrap_cipher(key_len), NULL, key, NULL)) {
|
|||
|
|
WarnL << "EVP_EncryptInit_ex fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int len1 = 0;
|
|||
|
|
if (1 != EVP_EncryptUpdate(ctx, (uint8_t*)out, &len1, (uint8_t*)in, in_len)) {
|
|||
|
|
WarnL << "EVP_EncryptUpdate fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int len2 = 0;
|
|||
|
|
if (1 != EVP_EncryptFinal_ex(ctx, (uint8_t*)out + len1, &len2)) {
|
|||
|
|
WarnL << "EVP_EncryptFinal_ex fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
*outLen = len1 + len2;
|
|||
|
|
} while (0);
|
|||
|
|
|
|||
|
|
if (ctx != NULL) {
|
|||
|
|
EVP_CIPHER_CTX_free(ctx);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return *outLen != 0;
|
|||
|
|
#else
|
|||
|
|
return false;
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief: aes_unwrap
|
|||
|
|
* @param [in]: in 待unwrap的数据
|
|||
|
|
* @param [in]: in_len 待unwrap的数据长度
|
|||
|
|
* @param [out]: out unwrap后输出的数据
|
|||
|
|
* @param [out]: outLen unwrap后输出的数据长度
|
|||
|
|
* @param [in]: key 密钥
|
|||
|
|
* @param [in]: key_len 密钥长度
|
|||
|
|
* @return : true: 成功,false: 失败
|
|||
|
|
**/
|
|||
|
|
static bool aes_unwrap(const uint8_t* in, int in_len, uint8_t* out, int* outLen, uint8_t* key, int key_len) {
|
|||
|
|
|
|||
|
|
#if defined(ENABLE_OPENSSL)
|
|||
|
|
EVP_CIPHER_CTX* ctx = NULL;
|
|||
|
|
|
|||
|
|
*outLen = 0;
|
|||
|
|
|
|||
|
|
do {
|
|||
|
|
|
|||
|
|
if (!(ctx = EVP_CIPHER_CTX_new())) {
|
|||
|
|
WarnL << "EVP_CIPHER_CTX_new fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
|
|||
|
|
|
|||
|
|
if (1 != EVP_DecryptInit_ex(ctx, aes_key_len_mapping_wrap_cipher(key_len), NULL, key, NULL)) {
|
|||
|
|
WarnL << "EVP_DecryptInit_ex fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//设置pkcs7padding
|
|||
|
|
if (1 != EVP_CIPHER_CTX_set_padding(ctx, 1)) {
|
|||
|
|
WarnL << "EVP_CIPHER_CTX_set_padding fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int len1 = 0;
|
|||
|
|
if (1 != EVP_DecryptUpdate(ctx, (uint8_t*)out, &len1, (uint8_t*)in, in_len)) {
|
|||
|
|
WarnL << "EVP_DecryptUpdate fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int len2 = 0;
|
|||
|
|
if (1 != EVP_DecryptFinal_ex(ctx, (uint8_t*)out + len1, &len2)) {
|
|||
|
|
WarnL << "EVP_DecryptFinal_ex fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
*outLen = len1 + len2;
|
|||
|
|
} while (0);
|
|||
|
|
|
|||
|
|
if (ctx != NULL) {
|
|||
|
|
EVP_CIPHER_CTX_free(ctx);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return *outLen != 0;
|
|||
|
|
|
|||
|
|
#else
|
|||
|
|
return false;
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief: aes ctr 加密
|
|||
|
|
* @param [in]: in 待加密的数据
|
|||
|
|
* @param [in]: in_len 待加密的数据长度
|
|||
|
|
* @param [out]: out 加密后输出的数据
|
|||
|
|
* @param [out]: outLen 加密后输出的数据长度
|
|||
|
|
* @param [in]: key 密钥
|
|||
|
|
* @param [in]: key_len 密钥长度
|
|||
|
|
* @param [in]: iv iv向量(16byte)
|
|||
|
|
* @return : true: 成功,false: 失败
|
|||
|
|
**/
|
|||
|
|
static bool aes_ctr_encrypt(const uint8_t* in, int in_len, uint8_t* out, int* outLen, uint8_t* key, int key_len, uint8_t* iv) {
|
|||
|
|
|
|||
|
|
#if defined(ENABLE_OPENSSL)
|
|||
|
|
EVP_CIPHER_CTX* ctx = NULL;
|
|||
|
|
|
|||
|
|
*outLen = 0;
|
|||
|
|
|
|||
|
|
do {
|
|||
|
|
if (!(ctx = EVP_CIPHER_CTX_new())) {
|
|||
|
|
WarnL << "EVP_CIPHER_CTX_new fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (1 != EVP_EncryptInit_ex(ctx, aes_key_len_mapping_ctr_cipher(key_len), NULL, key, iv)) {
|
|||
|
|
WarnL << "EVP_EncryptInit_ex fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int len1 = 0;
|
|||
|
|
if (1 != EVP_EncryptUpdate(ctx, (uint8_t*)out, &len1, (uint8_t*)in, in_len)) {
|
|||
|
|
WarnL << "EVP_EncryptUpdate fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int len2 = 0;
|
|||
|
|
if (1 != EVP_EncryptFinal_ex(ctx, (uint8_t*)out + len1, &len2)) {
|
|||
|
|
WarnL << "EVP_EncryptFinal_ex fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
*outLen = len1 + len2;
|
|||
|
|
} while (0);
|
|||
|
|
|
|||
|
|
if (ctx != NULL) {
|
|||
|
|
EVP_CIPHER_CTX_free(ctx);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return *outLen != 0;
|
|||
|
|
#else
|
|||
|
|
return false;
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief: aes ctr 解密
|
|||
|
|
* @param [in]: in 待解密的数据
|
|||
|
|
* @param [in]: in_len 待解密的数据长度
|
|||
|
|
* @param [out]: out 解密后输出的数据
|
|||
|
|
* @param [out]: outLen 解密后输出的数据长度
|
|||
|
|
* @param [in]: key 密钥
|
|||
|
|
* @param [in]: key_len 密钥长度
|
|||
|
|
* @param [in]: iv iv向量(16byte)
|
|||
|
|
* @return : true: 成功,false: 失败
|
|||
|
|
**/
|
|||
|
|
static bool aes_ctr_decrypt(const uint8_t* in, int in_len, uint8_t* out, int* outLen, uint8_t* key, int key_len, uint8_t* iv) {
|
|||
|
|
|
|||
|
|
#if defined(ENABLE_OPENSSL)
|
|||
|
|
EVP_CIPHER_CTX* ctx = NULL;
|
|||
|
|
|
|||
|
|
*outLen = 0;
|
|||
|
|
|
|||
|
|
do {
|
|||
|
|
|
|||
|
|
if (!(ctx = EVP_CIPHER_CTX_new())) {
|
|||
|
|
WarnL << "EVP_CIPHER_CTX_new fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (1 != EVP_DecryptInit_ex(ctx, aes_key_len_mapping_ctr_cipher(key_len), NULL, key, iv)) {
|
|||
|
|
WarnL << "EVP_DecryptInit_ex fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int len1 = 0;
|
|||
|
|
if (1 != EVP_DecryptUpdate(ctx, (uint8_t*)out, &len1, (uint8_t*)in, in_len)) {
|
|||
|
|
WarnL << "EVP_DecryptUpdate fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int len2 = 0;
|
|||
|
|
if (1 != EVP_DecryptFinal_ex(ctx, (uint8_t*)out + len1, &len2)) {
|
|||
|
|
WarnL << "EVP_DecryptFinal_ex fail";
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
*outLen = len1 + len2;
|
|||
|
|
} while (0);
|
|||
|
|
|
|||
|
|
if (ctx != NULL) {
|
|||
|
|
EVP_CIPHER_CTX_free(ctx);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return *outLen != 0;
|
|||
|
|
|
|||
|
|
#else
|
|||
|
|
return false;
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
///////////////////////////////////////////////////
|
|||
|
|
// CryptoContext
|
|||
|
|
CryptoContext::CryptoContext(const std::string& passparase, uint8_t kk, KeyMaterial::Ptr packet) :
|
|||
|
|
_passparase(passparase), _kk(kk) {
|
|||
|
|
if (packet) {
|
|||
|
|
loadFromKeyMaterial(packet);
|
|||
|
|
} else {
|
|||
|
|
refresh();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void CryptoContext::refresh() {
|
|||
|
|
if (_salt.empty()) {
|
|||
|
|
_salt = makeRandStr(_slen, false);
|
|||
|
|
generateKEK();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_sek = makeRandStr(_klen, false);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::string CryptoContext::generateWarppedKey() {
|
|||
|
|
string warpped_key;
|
|||
|
|
int size = (_sek.size() + 15) /16 * 16 + 8;
|
|||
|
|
warpped_key.resize(size);
|
|||
|
|
auto res = aes_wrap((uint8_t*)_sek.data(), _sek.size(), (uint8_t*)warpped_key.data(), &size, (uint8_t*)_kek.data(), _kek.size());
|
|||
|
|
if (!res) {
|
|||
|
|
return "";
|
|||
|
|
}
|
|||
|
|
warpped_key.resize(size);
|
|||
|
|
return warpped_key;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void CryptoContext::loadFromKeyMaterial(KeyMaterial::Ptr packet) {
|
|||
|
|
|
|||
|
|
_slen = packet->_slen;
|
|||
|
|
_klen = packet->_klen;
|
|||
|
|
_salt = packet->_salt;
|
|||
|
|
|
|||
|
|
generateKEK();
|
|||
|
|
|
|||
|
|
auto warpped_key = packet->_warpped_key;
|
|||
|
|
BufferLikeString sek;
|
|||
|
|
int size = warpped_key.size();
|
|||
|
|
sek.resize(size);
|
|||
|
|
auto ret = aes_unwrap((uint8_t*)warpped_key.data(), warpped_key.size(), (uint8_t*)sek.data(), &size, (uint8_t*)_kek.data(), _kek.size());
|
|||
|
|
if (!ret) {
|
|||
|
|
throw std::runtime_error(StrPrinter <<"warpped_key unwrap fail, password may mismatch");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
sek.resize(size);
|
|||
|
|
if (packet->_kk == KeyMaterial::KEY_BASED_ENCRYPTION_BOTH_SEK) {
|
|||
|
|
if (_kk == KeyMaterial::KEY_BASED_ENCRYPTION_EVEN_SEK) {
|
|||
|
|
_sek = sek.substr(0, _slen);
|
|||
|
|
} else {
|
|||
|
|
_sek = sek.substr(_slen, _slen);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
_sek = sek;
|
|||
|
|
}
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool CryptoContext::generateKEK() {
|
|||
|
|
/**
|
|||
|
|
SEK = PRNG(KLen)
|
|||
|
|
Salt = PRNG(128)
|
|||
|
|
KEK = PBKDF2(passphrase, LSB(64,Salt), Iter, KLen)
|
|||
|
|
**/
|
|||
|
|
_kek.resize(_klen);
|
|||
|
|
#if defined(ENABLE_OPENSSL)
|
|||
|
|
if (PKCS5_PBKDF2_HMAC(_passparase.data(), _passparase.length(), (uint8_t*)_salt.data() + _slen - 64/8, 64 /8, _iter, EVP_sha1(), _klen, (uint8_t*)_kek.data()) != 1) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
#else
|
|||
|
|
return false;
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
BufferLikeString::Ptr CryptoContext::generateIv(uint32_t pkt_seq_no) {
|
|||
|
|
auto iv = std::make_shared<BufferLikeString>();
|
|||
|
|
iv->resize(128 /8);
|
|||
|
|
|
|||
|
|
uint8_t* saltData = (uint8_t*)_salt.data();
|
|||
|
|
uint8_t* ivData = (uint8_t*)iv->data();
|
|||
|
|
memset((void*)ivData, 0, iv->size());
|
|||
|
|
memcpy((void*)(ivData + 10), (void*)&pkt_seq_no, 4);
|
|||
|
|
for (size_t i = 0; i < std::min<size_t>(_salt.size(), (size_t)112 /8); ++i) {
|
|||
|
|
ivData[i] ^= saltData[i];
|
|||
|
|
}
|
|||
|
|
return iv;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
///////////////////////////////////////////////////
|
|||
|
|
// AesCtrCryptoContext
|
|||
|
|
|
|||
|
|
AesCtrCryptoContext::AesCtrCryptoContext(const std::string& passparase, uint8_t kk, KeyMaterial::Ptr packet) :
|
|||
|
|
CryptoContext(passparase, kk, packet) {
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
BufferLikeString::Ptr AesCtrCryptoContext::encrypt(uint32_t pkt_seq_no, const char *buf, int len) {
|
|||
|
|
auto iv = generateIv(htonl(pkt_seq_no));
|
|||
|
|
auto payload = std::make_shared<BufferLikeString>();
|
|||
|
|
int size = (len + 15) /16 * 16 + 8;
|
|||
|
|
payload->resize(size);
|
|||
|
|
auto ret = aes_ctr_encrypt((const uint8_t*)buf, len, (uint8_t*)payload->data(), &size, (uint8_t*)_sek.data(), _sek.size(), (uint8_t*)iv->data());
|
|||
|
|
if (!ret) {
|
|||
|
|
return nullptr;
|
|||
|
|
}
|
|||
|
|
payload->resize(size);
|
|||
|
|
return payload;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
BufferLikeString::Ptr AesCtrCryptoContext::decrypt(uint32_t pkt_seq_no, const char *buf, int len) {
|
|||
|
|
auto iv = generateIv(htonl(pkt_seq_no));
|
|||
|
|
auto payload = std::make_shared<BufferLikeString>();
|
|||
|
|
int size = len;
|
|||
|
|
payload->resize(size);
|
|||
|
|
auto ret = aes_ctr_decrypt((const uint8_t*)buf, len, (uint8_t*)payload->data(), &size, (uint8_t*)_sek.data(), _sek.size(), (uint8_t*)iv->data());
|
|||
|
|
if (!ret) {
|
|||
|
|
return nullptr;
|
|||
|
|
}
|
|||
|
|
payload->resize(size);
|
|||
|
|
return payload;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
///////////////////////////////////////////////////
|
|||
|
|
// Crypto
|
|||
|
|
|
|||
|
|
Crypto::Crypto(const std::string& passparase) :
|
|||
|
|
_passparase(passparase) {
|
|||
|
|
|
|||
|
|
#ifndef ENABLE_OPENSSL
|
|||
|
|
throw std::invalid_argument("openssl disable, please set ENABLE_OPENSSL when compile");
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
_ctx_pair[0] = createCtx(KeyMaterial::CIPHER_AES_CTR, _passparase, KeyMaterial::KEY_BASED_ENCRYPTION_EVEN_SEK);
|
|||
|
|
_ctx_pair[1] = createCtx(KeyMaterial::CIPHER_AES_CTR, _passparase, KeyMaterial::KEY_BASED_ENCRYPTION_ODD_SEK);
|
|||
|
|
_ctx_idx = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
CryptoContext::Ptr Crypto::createCtx(int cipher, const std::string& passparase, uint8_t kk, KeyMaterial::Ptr packet) {
|
|||
|
|
switch (cipher){
|
|||
|
|
case KeyMaterial::CIPHER_AES_CTR:
|
|||
|
|
return std::make_shared<AesCtrCryptoContext>(passparase, kk, packet);
|
|||
|
|
case KeyMaterial::CIPHER_AES_ECB:
|
|||
|
|
case KeyMaterial::CIPHER_AES_CBC:
|
|||
|
|
case KeyMaterial::CIPHER_AES_GCM:
|
|||
|
|
default:
|
|||
|
|
throw std::runtime_error(StrPrinter <<"not support cipher " << cipher);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
HSExtKeyMaterial::Ptr Crypto::generateKeyMaterialExt(uint16_t extension_type) {
|
|||
|
|
HSExtKeyMaterial::Ptr ext = std::make_shared<HSExtKeyMaterial>();
|
|||
|
|
ext->extension_type = extension_type;
|
|||
|
|
ext->_kk = _ctx_pair[_ctx_idx]->_kk;
|
|||
|
|
ext->_cipher = _ctx_pair[_ctx_idx]->getCipher();
|
|||
|
|
ext->_slen = _ctx_pair[_ctx_idx]->_slen;
|
|||
|
|
ext->_klen = _ctx_pair[_ctx_idx]->_klen;
|
|||
|
|
ext->_salt = _ctx_pair[_ctx_idx]->_salt;
|
|||
|
|
ext->_warpped_key = _ctx_pair[_ctx_idx]->generateWarppedKey();
|
|||
|
|
return ext;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
KeyMaterialPacket::Ptr Crypto::generateAnnouncePacket(CryptoContext::Ptr ctx) {
|
|||
|
|
KeyMaterialPacket::Ptr pkt = std::make_shared<KeyMaterialPacket>();
|
|||
|
|
pkt->sub_type = HSExt::SRT_CMD_KMREQ;
|
|||
|
|
pkt->_kk = ctx->_kk;
|
|||
|
|
pkt->_cipher = ctx->getCipher();
|
|||
|
|
pkt->_slen = ctx->_slen;
|
|||
|
|
pkt->_klen = ctx->_klen;
|
|||
|
|
pkt->_salt = ctx->_salt;
|
|||
|
|
pkt->_warpped_key = ctx->generateWarppedKey();
|
|||
|
|
return pkt;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
KeyMaterialPacket::Ptr Crypto::takeAwayAnnouncePacket() {
|
|||
|
|
auto pkt = _re_announce_pkt;
|
|||
|
|
_re_announce_pkt = nullptr;
|
|||
|
|
return pkt;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool Crypto::loadFromKeyMaterial(KeyMaterial::Ptr packet) {
|
|||
|
|
try {
|
|||
|
|
if (packet->_kk == KeyMaterial::KEY_BASED_ENCRYPTION_EVEN_SEK) {
|
|||
|
|
_ctx_pair[0] = createCtx(packet->_cipher, _passparase, packet->_kk, packet);
|
|||
|
|
} else if (packet->_kk == KeyMaterial::KEY_BASED_ENCRYPTION_ODD_SEK) {
|
|||
|
|
_ctx_pair[1] = createCtx(packet->_cipher, _passparase, packet->_kk, packet);
|
|||
|
|
} else if (packet->_kk == KeyMaterial::KEY_BASED_ENCRYPTION_BOTH_SEK) {
|
|||
|
|
_ctx_pair[0] = createCtx(packet->_cipher, _passparase, KeyMaterial::KEY_BASED_ENCRYPTION_EVEN_SEK, packet);
|
|||
|
|
_ctx_pair[1] = createCtx(packet->_cipher, _passparase, KeyMaterial::KEY_BASED_ENCRYPTION_ODD_SEK, packet);
|
|||
|
|
}
|
|||
|
|
} catch (std::exception &ex) {
|
|||
|
|
WarnL << ex.what();
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
BufferLikeString::Ptr Crypto::encrypt(DataPacket::Ptr pkt, const char *buf, int len) {
|
|||
|
|
_pkt_count++;
|
|||
|
|
|
|||
|
|
//refresh
|
|||
|
|
if (_pkt_count == _re_announcement_period) {
|
|||
|
|
auto ctx = createCtx(KeyMaterial::CIPHER_AES_CTR, _passparase, _ctx_pair[!_ctx_idx]->_kk);
|
|||
|
|
_ctx_pair[!_ctx_idx] = ctx;
|
|||
|
|
_re_announce_pkt = generateAnnouncePacket(ctx);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (_pkt_count > _refresh_period) {
|
|||
|
|
_pkt_count = 0;
|
|||
|
|
_ctx_idx = !_ctx_idx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
pkt->KK = _ctx_pair[_ctx_idx]->_kk;
|
|||
|
|
return _ctx_pair[_ctx_idx]->encrypt(pkt->packet_seq_number, buf, len);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
BufferLikeString::Ptr Crypto::decrypt(DataPacket::Ptr pkt, const char *buf, int len) {
|
|||
|
|
CryptoContext::Ptr _ctx;
|
|||
|
|
if (pkt->KK == KeyMaterial::KEY_BASED_ENCRYPTION_NO_SEK) {
|
|||
|
|
auto payload = std::make_shared<BufferLikeString>();
|
|||
|
|
payload->assign(buf, len);
|
|||
|
|
return payload;
|
|||
|
|
} else if (pkt->KK == KeyMaterial::KEY_BASED_ENCRYPTION_EVEN_SEK) {
|
|||
|
|
_ctx = _ctx_pair[0];
|
|||
|
|
} else if (pkt->KK == KeyMaterial::KEY_BASED_ENCRYPTION_ODD_SEK) {
|
|||
|
|
_ctx = _ctx_pair[1];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!_ctx) {
|
|||
|
|
WarnL << "not has effective KeyMaterial with kk: " << pkt->KK;
|
|||
|
|
return nullptr;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return _ctx->decrypt(pkt->packet_seq_number, buf, len);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
} // namespace SRT
|