Skip to content
Snippets Groups Projects
Verified Commit 74c5b9e4 authored by Joe Donofry's avatar Joe Donofry
Browse files

Update E2E Key Export to follow specification at:

https://matrix.org/docs/spec/client_server/unstable.html#key-export-format

Currently, importing does not work.  Do not use this commit
if you intend to keep import/export working.  I also have not yet
cleaned up the code, so there might be some nasties that have
not been discovered.
parent 5422d281
No related branches found
No related tags found
No related merge requests found
......@@ -14,6 +14,7 @@
#include "mtxclient/crypto/objects.hpp"
#include "mtxclient/crypto/types.hpp"
#include "mtxclient/crypto/utils.hpp"
namespace mtx {
namespace crypto {
......
#pragma once
#include <string>
#include <vector>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>
namespace mtx {
namespace crypto {
//! Data representation used to interact with libolm.
using BinaryBuf = std::vector<uint8_t>;
//! Simple wrapper around the OpenSSL PKCS5_PBKDF2_HMAC function
BinaryBuf PBKDF2_HMAC_SHA_512(const std::string pass, const BinaryBuf salt, uint32_t iterations);
BinaryBuf AES_CTR_256(const std::string plaintext, const BinaryBuf aes256Key, BinaryBuf iv);
BinaryBuf HMAC_SHA256(const BinaryBuf hmacKey, const BinaryBuf data);
void uint32_to_uint8 (uint8_t b[4], uint32_t u32);
void print_binary_buf(const BinaryBuf buf) ;
} // namespace crypto
} // namespace mtx
\ No newline at end of file
......@@ -2,8 +2,9 @@
#include "mtxclient/crypto/client.hpp"
#include "mtxclient/crypto/types.hpp"
#include "mtxclient/crypto/utils.hpp"
#include "sodium.h"
#include <sodium.h>
using json = nlohmann::json;
using namespace mtx::crypto;
......@@ -536,35 +537,64 @@ mtx::crypto::encrypt_exported_sessions(const mtx::crypto::ExportedSessionKeys &k
std::string pass)
{
const auto plaintext = json(keys).dump();
const auto msg_len = plaintext.size();
const auto ciphertext_len = crypto_secretbox_MACBYTES + msg_len;
auto nonce = create_buffer(crypto_secretbox_NONCEBYTES);
auto ciphertext = create_buffer(ciphertext_len);
auto nonce = create_buffer(AES_BLOCK_SIZE);
auto salt = create_buffer(crypto_pwhash_SALTBYTES);
auto key = derive_key(pass, salt);
crypto_secretbox_easy(reinterpret_cast<unsigned char *>(ciphertext.data()),
reinterpret_cast<const unsigned char *>(plaintext.data()),
msg_len,
nonce.data(),
reinterpret_cast<const unsigned char *>(key.data()));
//auto key = derive_key(pass, salt);
auto buf = create_buffer(64U);
// Format of the output buffer: (nonce + salt + ciphertext)
BinaryBuf output{nonce};
//crypto_secretbox_easy(reinterpret_cast<unsigned char *>(ciphertext.data()),
// reinterpret_cast<const unsigned char *>(plaintext.data()),
// msg_len,
// nonce.data(),
// reinterpret_cast<const unsigned char *>(key.data()));
uint32_t iterations = 100000;
buf = mtx::crypto::PBKDF2_HMAC_SHA_512(pass,
salt,
iterations);
BinaryBuf aes256 = BinaryBuf(buf.begin(), buf.begin() + 32);
BinaryBuf hmac256 = BinaryBuf(buf.begin() + 32, buf.begin() + (2 * 32));
auto ciphertext = mtx::crypto::AES_CTR_256(plaintext,
aes256,
nonce);
uint8_t iterationsArr[4];
mtx::crypto::uint32_to_uint8(iterationsArr, iterations);
// Format of the output buffer: (0x01 + salt + IV + number of rounds + ciphertext + hmac-sha-256)
BinaryBuf output{0x01};
output.insert(
output.end(), std::make_move_iterator(salt.begin()), std::make_move_iterator(salt.end()));
output.insert(output.end(),
std::make_move_iterator(nonce.begin()),
std::make_move_iterator(nonce.end()));
output.insert(output.end(), &iterationsArr[0], &iterationsArr[4]);
output.insert(output.end(),
std::make_move_iterator(ciphertext.begin()),
std::make_move_iterator(ciphertext.end()));
return std::string(output.begin(), output.end());
// Need to hmac-sha256 our string so far, and then use that to finish making the output.
auto hmacSha256 = mtx::crypto::HMAC_SHA256(hmac256, output);
output.insert(output.end(),
std::make_move_iterator(hmacSha256.begin()),
std::make_move_iterator(hmacSha256.end()));
auto encrypted = std::string(output.begin(), output.end());
return encrypted;
}
mtx::crypto::ExportedSessionKeys
mtx::crypto::decrypt_exported_sessions(const std::string &data, std::string pass)
{
std::cout << "decrypt_exported_sessions data: " << data << std::endl;
if (data.size() <
crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES + crypto_pwhash_SALTBYTES)
throw sodium_exception{"decrypt_exported_sessions", "ciphertext too small"};
......
#include "mtxclient/crypto/utils.hpp"
#include <iostream>
namespace mtx {
namespace crypto {
BinaryBuf
PBKDF2_HMAC_SHA_512(const std::string pass, const BinaryBuf salt, uint32_t iterations) {
uint8_t out[SHA512_DIGEST_LENGTH];
PKCS5_PBKDF2_HMAC(&pass[0], pass.size(), salt.data(), salt.size(), iterations, EVP_sha512(), SHA512_DIGEST_LENGTH, out);
BinaryBuf output(out, out + SHA512_DIGEST_LENGTH);
return output;
}
BinaryBuf
AES_CTR_256(const std::string plaintext, const BinaryBuf aes256Key, BinaryBuf iv) {
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
unsigned char *cipher;
uint8_t *iv_data = iv.data();
// need to set bit 63 to 0
*(iv_data) &= ~(1UL << 63);
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) {
//handleErrors();
}
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_ctr(), NULL, aes256Key.data(), iv_data)) {
//handleErrors();
}
/* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, cipher, &len, reinterpret_cast<const unsigned char*>(&plaintext.c_str()[0]), plaintext.size())) {
//handleErrors();
}
ciphertext_len = len;
/* Finalise the encryption. Further ciphertext bytes may be written at
* this stage.
*/
if(1 != EVP_EncryptFinal_ex(ctx, cipher + len, &len)) {
//handleErrors();
}
ciphertext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return BinaryBuf(reinterpret_cast<uint8_t *>(cipher), cipher + ciphertext_len);
}
BinaryBuf
HMAC_SHA256 (const BinaryBuf hmacKey, const BinaryBuf data) {
unsigned int len = SHA256_DIGEST_LENGTH;
unsigned char digest[SHA256_DIGEST_LENGTH];
HMAC(EVP_sha256(), hmacKey.data(), hmacKey.size(), data.data(), data.size(), digest, &len);
BinaryBuf output(digest, digest + SHA256_DIGEST_LENGTH);
return output;
}
void
print_binary_buf(const BinaryBuf buf) {
for (uint8_t val : buf) {
std::cout << std::to_string(val) << ",";
}
std::cout << std::endl;
}
void uint32_to_uint8 (uint8_t b[4], uint32_t u32) {
b[3] = (uint8_t)u32;
b[2] = (uint8_t)(u32>>=8);
b[1] = (uint8_t)(u32>>=8);
b[0] = (uint8_t)(u32>>=8);
}
} // namespace crypto
} // namespace mtx
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment