Function stub: // Send a message to the server,
using the common format for secure messages,
// then take the response from
the server, decrypt it, and return
it・
///
/// Many of the messages in our server have a common form (@rblock. @ablock):
///
- erblock enc (pubkey,
padR ("CD" aeskey. length ( (msg)))
// - @ablock enc(aeskey, (msg)
///
/ @param sd An open socket /// @param pub The server's public key, for encrypting the aes key /// @param cmd The command that is being sent
// @param msg The contents of the
@ablock
///
/// @returns a vector with the (decrypted) result, or an empty vector on error vector<uint8
t> send_cmd(int sd,
RSA *pub, const string cmd, const vector<uint8
_t> &msg) {
}
Helper functions:
/// Run the AES symmetric encryption/decryption algorithm on a buffer of bytes.
/// Note that this will do either encryption or decryption, depending on how the
/// provided CTX has been configured. After calling, the CTX cannot be used
/// again until it is reset.
///
/// NB: This is a forward declaration. This version of aes_crypt_msg is
/// implemented in my_crypto.cc.
///
/// @param ctx The pre-configured AES context to use for this operation
/// @param msg A buffer of bytes to encrypt/decrypt
///
/// @return A vector with the encrypted or decrypted result, or an empty
/// vector if there was an error
vector<uint8_t> aes_crypt_msg(EVP_CIPHER_CTX *ctx, const unsigned char *start,
int count);
/// Run the AES symmetric encryption/decryption algorithm on a vector. Note
/// that this will do either encryption or decryption, depending on how the
/// provided CTX has been configured. After calling, the CTX cannot be used
/// again until it is reset.
///
/// @param ctx The pre-configured AES context to use for this operation
/// @param msg A vector to encrypt/decrypt
///
/// @return A vector with the encrypted or decrypted result, or an empty
/// vector if there was an error
vector<uint8_t> aes_crypt_msg(EVP_CIPHER_CTX *ctx, const vector<uint8_t> &msg) {
return aes_crypt_msg(ctx, msg.data(), msg.size());
}
/// Run the AES symmetric encryption/decryption algorithm on a string. Note that
/// this will do either encryption or decryption, depending on how the provided
/// CTX has been configured. After calling, the CTX cannot be used again until
/// it is reset.
///
/// @param ctx The pre-configured AES context to use for this operation
/// @param msg A string to encrypt/decrypt
///
/// @return A vector with the encrypted or decrypted result, or an empty
/// vector if there was an error
vector<uint8_t> aes_crypt_msg(EVP_CIPHER_CTX *ctx, const string &msg) {
return aes_crypt_msg(ctx, (unsigned char *)msg.c_str(), msg.length());
}
/// Create an AES key. A key is two parts, the key itself, and the
/// initialization vector. Each is just random bits. Our key will be a stream
/// of random bits, long enough to be split into the actual key and the iv.
///
/// @return A vector holding the key and iv bits, or an empty vector on error
vector<uint8_t> create_aes_key() {
vector<uint8_t> key(AES_KEYSIZE + AES_IVSIZE);
if (!RAND_bytes(key.data(), AES_KEYSIZE) ||
!RAND_bytes(key.data() + AES_KEYSIZE, AES_IVSIZE))
return err<vector<uint8_t>>({}, "Error in RAND_bytes()");
return key;
}
/// Create an aes context for doing a single encryption or decryption. The
/// context must be reset after each full encrypt/decrypt.
///
/// @param key A vector holding the bits of the key and iv
/// @param encrypt true to encrypt, false to decrypt
///
/// @return An AES context for doing encryption. Note that the context can be
/// reset in order to re-use this object for another encryption.
EVP_CIPHER_CTX *create_aes_context(const vector<uint8_t> &key, bool encrypt) {
// create and initialize a context for the AES operations we are going to do
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (ctx == nullptr)
return err<EVP_CIPHER_CTX *>(nullptr,
"Error: OpenSSL couldn't create context: ",
ERR_error_string(ERR_get_error(), 0));
ContextManager c([&]() { EVP_CIPHER_CTX_cleanup(ctx); }); // reclaim on exit
// Make sure the key and iv lengths we have up above are valid
if (!EVP_CipherInit_ex(ctx, EVP_aes_256_cbc(), 0, 0, 0, encrypt))
return err<EVP_CIPHER_CTX *>(nullptr,
"Error: OpenSSL couldn't initialize context: ",
ERR_error_string(ERR_get_error(), 0));
if ((EVP_CIPHER_CTX_key_length(ctx) != AES_KEYSIZE) ||
(EVP_CIPHER_CTX_iv_length(ctx) != AES_IVSIZE))
return err<EVP_CIPHER_CTX *>(nullptr,
"Error: OpenSSL couldn't initialize context: ",
ERR_error_string(ERR_get_error(), 0));
// Set the key and iv on the AES context, and set the mode to encrypt or
// decrypt
if (!EVP_CipherInit_ex(ctx, nullptr, nullptr, key.data(),
key.data() + AES_KEYSIZE, encrypt))
return err<EVP_CIPHER_CTX *>(nullptr,
"Error: OpenSSL couldn't re-init context: ",
ERR_error_string(ERR_get_error(), 0));
c.disable(); // don't reclaim ctx on exit, because we're good
return ctx;
}