C++ C++;在OpenSSL中读取和使用RSA私钥

C++ C++;在OpenSSL中读取和使用RSA私钥,c++,encryption,cryptography,openssl,rsa,C++,Encryption,Cryptography,Openssl,Rsa,假设有一个程序使用OpenSSL RSA进行安全保护,我有它用来解密/加密数据的私钥。 这是一段谁写的程序协议是如何工作的引用: 对于会话打开,客户端生成256位AES会话密钥和 128位AES会话IV(初始化向量) 客户端向服务器发送一条GSP会话初始化消息,并使用 客户端的RSA私钥(即,使用私钥加密)。 RSA私钥对于所有Garena客户端都是相同的,已被窃取 从windows EXE,并在此文件末尾给出:) 因此,加密是毫无价值的:如果有人能够嗅探 GSP会话,他可以得到加密的GSP会话

假设有一个程序使用OpenSSL RSA进行安全保护,我有它用来解密/加密数据的私钥。

这是一段谁写的程序协议是如何工作的引用:

对于会话打开,客户端生成256位AES会话密钥和 128位AES会话IV(初始化向量)

客户端向服务器发送一条GSP会话初始化消息,并使用 客户端的RSA私钥(即,使用私钥加密)。 RSA私钥对于所有Garena客户端都是相同的,已被窃取 从windows EXE,并在此文件末尾给出:) 因此,加密是毫无价值的:如果有人能够嗅探 GSP会话,他可以得到加密的GSP会话初始化消息,解密 它使用RSA公钥(可以从RSA私钥派生)进行加密 使用OpenSSL非常容易),因此获得AES会话密钥和IV

在GSP会话初始化消息之后,所有其他GSP消息都被加密 在AES CBC中,使用会话密钥和IV。会话期间密钥和IV保持不变 所有会话,在两个方向上(即,用于加密的IV 接下来的每一条信息实际上都是开始的第四条,而不是最后一条 密文块(就像它应该的那样)

正如他提到的,我只需要一次RSA(加密GSP会话初始化),然后我们就可以与AES CBC通信了。

这是我使用的SSL类:(这只是RSA的东西)

CGarenaEncrypt::CGarenaEncrypt() {
localKeypair = NULL;
remotePubKey = NULL;

#ifdef PSUEDO_CLIENT
    genTestClientKey();
#endif

init();
}

int CGarenaEncrypt::rsaEncrypt(const unsigned char *msg, size_t msgLen, unsigned char **encMsg, unsigned char **ek, size_t *ekl, unsigned char **iv, size_t *ivl) {
size_t encMsgLen = 0;
size_t blockLen = 0;

*ek = (unsigned char*)malloc(EVP_PKEY_size(localKeypair));
*iv = (unsigned char*)malloc(EVP_MAX_IV_LENGTH);
if(*ek == NULL || *iv == NULL) return FAILURE;
*ivl = EVP_MAX_IV_LENGTH;

*encMsg = (unsigned char*)malloc(msgLen + EVP_MAX_IV_LENGTH);
if(encMsg == NULL) return FAILURE;

if(!EVP_SealInit(rsaEncryptCtx, EVP_aes_256_cbc(), ek, (int*)ekl, *iv, &localKeypair, 1)) {
    return FAILURE;
}

if(!EVP_SealUpdate(rsaEncryptCtx, *encMsg + encMsgLen, (int*)&blockLen, (const unsigned char*)msg, (int)msgLen)) {
    return FAILURE;
}
encMsgLen += blockLen;

if(!EVP_SealFinal(rsaEncryptCtx, *encMsg + encMsgLen, (int*)&blockLen)) {
    return FAILURE;
}
encMsgLen += blockLen;

EVP_CIPHER_CTX_cleanup(rsaEncryptCtx);

return (int)encMsgLen;
}

int CGarenaEncrypt::rsaDecrypt(unsigned char *encMsg, size_t encMsgLen, unsigned char *ek, size_t ekl, unsigned char *iv, size_t ivl, unsigned char **decMsg) {
size_t decLen = 0;
size_t blockLen = 0;
EVP_PKEY *key;

*decMsg = (unsigned char*)malloc(encMsgLen + ivl);
if(decMsg == NULL) return FAILURE;

#ifdef PSUEDO_CLIENT
    key = remotePubKey;
#else
    key = localKeypair;
#endif

if(!EVP_OpenInit(rsaDecryptCtx, EVP_aes_256_cbc(), ek, ekl, iv, key)) {
    return FAILURE;
}

if(!EVP_OpenUpdate(rsaDecryptCtx, (unsigned char*)*decMsg + decLen, (int*)&blockLen, encMsg, (int)encMsgLen)) {
    return FAILURE;
}
decLen += blockLen;

if(!EVP_OpenFinal(rsaDecryptCtx, (unsigned char*)*decMsg + decLen, (int*)&blockLen)) {
    return FAILURE;
}
decLen += blockLen;

EVP_CIPHER_CTX_cleanup(rsaDecryptCtx);

return (int)decLen;
}

int CGarenaEncrypt::readPrivateKey(FILE *fd) {
if(!PEM_read_PrivateKey(fd, &localKeypair, NULL, NULL))
    return FAILURE;

return SUCCESS;
}

int CGarenaEncrypt::init() {
// Initalize contexts
rsaEncryptCtx = (EVP_CIPHER_CTX*)malloc(sizeof(EVP_CIPHER_CTX));
aesEncryptCtx = (EVP_CIPHER_CTX*)malloc(sizeof(EVP_CIPHER_CTX));

rsaDecryptCtx = (EVP_CIPHER_CTX*)malloc(sizeof(EVP_CIPHER_CTX));
aesDecryptCtx = (EVP_CIPHER_CTX*)malloc(sizeof(EVP_CIPHER_CTX));

// Always a good idea to check if malloc failed
if(rsaEncryptCtx == NULL || aesEncryptCtx == NULL || rsaDecryptCtx == NULL || aesDecryptCtx == NULL) {
    return FAILURE;
}

// Init these here to make valgrind happy
EVP_CIPHER_CTX_init(rsaEncryptCtx);
EVP_CIPHER_CTX_init(aesEncryptCtx);

EVP_CIPHER_CTX_init(rsaDecryptCtx);
EVP_CIPHER_CTX_init(aesDecryptCtx);

// Init RSA
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);

if(EVP_PKEY_keygen_init(ctx) <= 0) {
    return FAILURE;
}

if(EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, RSA_KEYLEN) <= 0) {
    return FAILURE;
}

if(EVP_PKEY_keygen(ctx, &localKeypair) <= 0) {
    return FAILURE;
}

EVP_PKEY_CTX_free(ctx);

// Init AES
aesKey = (unsigned char*)malloc(AES_KEYLEN/8);
aesIV = (unsigned char*)malloc(AES_KEYLEN/16);

unsigned char *aesPass = (unsigned char*)malloc(AES_KEYLEN/8);
unsigned char *aesSalt = (unsigned char*)malloc(8);

if(aesKey == NULL || aesIV == NULL || aesPass == NULL || aesSalt == NULL) {
    return FAILURE;
}

// For the AES key we have the option of using a PBKDF (password-baswed key derivation formula)
// or just using straight random data for the key and IV. Depending on your use case, you will
// want to pick one or another.
#ifdef USE_PBKDF
    // Get some random data to use as the AES pass and salt
    if(RAND_bytes(aesPass, AES_KEYLEN/8) == 0) {
        return FAILURE;
    }

    if(RAND_bytes(aesSalt, 8) == 0) {
        return FAILURE;
    }

    if(EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha256(), aesSalt, aesPass, AES_KEYLEN/8, AES_ROUNDS, aesKey, aesIV) == 0) {
        return FAILURE;
    }
#else
    if(RAND_bytes(aesKey, AES_KEYLEN/8) == 0) {
        return FAILURE;
    }

    if(RAND_bytes(aesIV, AES_KEYLEN/16) == 0) {
        return FAILURE;
    }
#endif

free(aesPass);
free(aesSalt);

return SUCCESS;
}

如图所示,一切正常,但问题是我所连接的服务器需要长度约为200-250的数据包,而我的数据包长度约为70。这意味着当他们加密数据时(我使用的数据和原始客户端使用的数据相同),加密长度将是一个大数字(~240)。另外,还有一种替代方案,用于使用java编写的原始客户端(我实际上是这样做的)生成正确长度的正确加密数据。

我认为读取私钥时应该有问题,因为当我调用
PEM\u write\u PrivateKey(stdout,localKeypair,NULL,NULL,0,0,NULL)
控制台中打印的密钥与我想要读取的私钥完全不同,或者我使用了错误的密钥长度?!我不知道。


欢迎提供任何帮助首先,您的信息有误。执行副总裁印章。。。操作不使用rsa专用加密。执行副总裁印章。。使用rsa_public_加密和EVP_Open。。使用rsa_私有_解密


秒,加密密钥的大小取决于RSA密钥的大小。在代码中,您使用RSA_KEYLEN作为密钥大小。我认为服务器的密钥大小可能是2048(位)长。您使用512(位)长。

问题到底是什么?有关读取和写入键的信息,请参阅。请参阅以获取加密和解密。@noloader抱歉,您甚至没有尝试阅读我写的所有内容。事实上,我已经通读了
pem(3)
evp(3)
回答标题中提出的问题(如何读取和使用钥匙)。至于你的协议问题,谁知道呢。我们无法对源文件中的注释执行任何操作。它没有告诉我们任何有用的东西。您应该检查参考实现。
if (!AfxSocketInit())
Util_Log(0, 2, _T("AfxSocketInit() failed."));

FILE* privKey;

int err  = fopen_s( &privKey, "E:\\gkey.pem", "r" );

if( err != 0 ){
    Util_Log(0, 2, _T("Failed to open 'gkey.pem' file."));
    return;
}

err = m_encrypt.readPrivateKey(privKey);

fclose(privKey);

if( err != 0 ){
    Util_Log(0, 2, _T("readPrivateKey Failed."));
    return;
}


sendGSPSessionInit();

bool CGarenaInterface::sendGSPSessionInit(void)
{
FILE *f;
if(AllocConsole()) {
freopen_s(&f, "CONOUT$", "wt", stdout);
SetConsoleTitle(_T("Debug Console"));
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
}

Util_Log(0, 0, _T("Sending GSP session init ..."));

int nEncSize = 0;
int nDecSize = 0;
uint8_t* EncOut = NULL;
uint8_t* DecOut = NULL;
unsigned char *ek;
unsigned char *iv;
size_t ekl;
size_t ivl;

CByteBuffer *bytebuffer = new CByteBuffer();
CByteBuffer *bytebuffer2 = new CByteBuffer();
bytebuffer->Allocate(50);
bytebuffer->PutBytes(m_encrypt.aesKey, 32);
bytebuffer->PutBytes(m_encrypt.aesIV, 16);
bytebuffer->PutShort(0xF00F);

printf("\n original:\n");
Util_HexPrint(*bytebuffer, bytebuffer->ByteBuffer->len);

nEncSize = m_encrypt.rsaEncrypt(*bytebuffer, bytebuffer->ByteBuffer->len, &EncOut, &ek, &ekl, &iv, &ivl);

printf("encrypted:\n");
Util_HexPrint(EncOut, nEncSize);

nDecSize = m_encrypt.rsaDecrypt(EncOut, nEncSize, ek, ekl, iv, ivl, &DecOut);

printf("decrypted:\n");
Util_HexPrint(DecOut, nDecSize);

bytebuffer2->Allocate(nEncSize + 6);
bytebuffer2->PutInt(258);
bytebuffer2->PutShort(0x00AD);
bytebuffer2->PutBytes(EncOut, nEncSize);

printf("\n final:\n");
Util_HexPrint(*bytebuffer2, bytebuffer2->ByteBuffer->len);

//  m_socket.Create();
//  m_socket.m_buffer = *bytebuffer2;
//  m_socket.nBufLen = bytebuffer2->ByteBuffer->len;
//  m_socket.Connect(GARENA_MAIN_SERVER_ADDRESS, 7456);


delete bytebuffer;
bytebuffer = NULL;
//  delete bytebuffer2;
//  bytebuffer2 = NULL;

free(EncOut);
free(DecOut);
free(ek);
free(iv);
EncOut = NULL;
DecOut = NULL;
ek = NULL;
iv = NULL;


return true;
}