Skip to content

Commit a87060d

Browse files
authored
Fix RSA online encryption (#81)
MOPPAND-1726 Signed-off-by: Raul Metsma <[email protected]>
1 parent a6701a4 commit a87060d

File tree

5 files changed

+69
-93
lines changed

5 files changed

+69
-93
lines changed

cdoc/CDoc2Reader.cpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ std::string
5050
libcdoc::CDoc2::getSaltForExpand(const std::string& label)
5151
{
5252
std::ostringstream oss;
53-
oss << libcdoc::CDoc2::KEK.data() << cdoc20::header::EnumNameFMKEncryptionMethod(cdoc20::header::FMKEncryptionMethod::XOR) << label;
53+
oss << libcdoc::CDoc2::KEK << cdoc20::header::EnumNameFMKEncryptionMethod(cdoc20::header::FMKEncryptionMethod::XOR) << label;
5454
return oss.str();
5555
}
5656

@@ -59,9 +59,10 @@ std::string
5959
libcdoc::CDoc2::getSaltForExpand(const std::vector<uint8_t>& key_material, const std::vector<uint8_t>& rcpt_key)
6060
{
6161
std::ostringstream oss;
62-
oss << libcdoc::CDoc2::KEK.data() << cdoc20::header::EnumNameFMKEncryptionMethod(cdoc20::header::FMKEncryptionMethod::XOR) <<
63-
std::string(rcpt_key.cbegin(), rcpt_key.cend()) <<
64-
std::string(key_material.cbegin(), key_material.cend());
62+
oss << libcdoc::CDoc2::KEK
63+
<< cdoc20::header::EnumNameFMKEncryptionMethod(cdoc20::header::FMKEncryptionMethod::XOR)
64+
<< std::string_view((const char*)rcpt_key.data(), rcpt_key.size())
65+
<< std::string_view((const char*)key_material.data(), key_material.size());
6566
return oss.str();
6667
}
6768

@@ -128,7 +129,7 @@ CDoc2Reader::getFMK(std::vector<uint8_t>& fmk, unsigned int lock_idx)
128129
std::vector<uint8_t> kek_pm;
129130
crypto->extractHKDF(kek_pm, lock.getBytes(Lock::SALT), lock.getBytes(Lock::PW_SALT), lock.getInt(Lock::KDF_ITER), lock_idx);
130131
LOG_DBG("password2");
131-
kek = libcdoc::Crypto::expand(kek_pm, std::vector<uint8_t>(info_str.cbegin(), info_str.cend()), 32);
132+
kek = libcdoc::Crypto::expand(kek_pm, info_str, 32);
132133
if (kek.empty()) return libcdoc::CRYPTO_ERROR;
133134
LOG_DBG("password3");
134135
} else if (lock.type == Lock::Type::SYMMETRIC_KEY) {
@@ -137,10 +138,10 @@ CDoc2Reader::getFMK(std::vector<uint8_t>& fmk, unsigned int lock_idx)
137138
std::string info_str = libcdoc::CDoc2::getSaltForExpand(lock.label);
138139
std::vector<uint8_t> kek_pm;
139140
crypto->extractHKDF(kek_pm, lock.getBytes(Lock::SALT), {}, 0, lock_idx);
140-
kek = libcdoc::Crypto::expand(kek_pm, std::vector<uint8_t>(info_str.cbegin(), info_str.cend()), 32);
141+
kek = libcdoc::Crypto::expand(kek_pm, info_str, 32);
141142

142143
LOG_DBG("Label: {}", lock.label);
143-
LOG_DBG("info: {}", toHex(std::vector<uint8_t>(info_str.cbegin(), info_str.cend())));
144+
LOG_DBG("info: {}", toHex(info_str));
144145
LOG_TRACE_KEY("salt: {}", lock.getBytes(Lock::SALT));
145146
LOG_TRACE_KEY("kek_pm: {}", kek_pm);
146147
LOG_TRACE_KEY("kek: {}", kek);
@@ -200,9 +201,9 @@ CDoc2Reader::getFMK(std::vector<uint8_t>& fmk, unsigned int lock_idx)
200201

201202
std::string info_str = libcdoc::CDoc2::getSaltForExpand(key_material, lock.getBytes(Lock::Params::RCPT_KEY));
202203

203-
LOG_DBG("info: {}", toHex(std::vector<uint8_t>(info_str.cbegin(), info_str.cend())));
204+
LOG_DBG("info: {}", toHex(info_str));
204205

205-
kek = libcdoc::Crypto::expand(kek_pm, std::vector<uint8_t>(info_str.cbegin(), info_str.cend()), libcdoc::CDoc2::KEY_LEN);
206+
kek = libcdoc::Crypto::expand(kek_pm, info_str, libcdoc::CDoc2::KEY_LEN);
206207
}
207208
} else if (lock.type == Lock::Type::SHARE_SERVER) {
208209
/* SALT */
@@ -322,7 +323,7 @@ CDoc2Reader::getFMK(std::vector<uint8_t>& fmk, unsigned int lock_idx)
322323
LOG_ERROR("{}", last_error);
323324
return libcdoc::CRYPTO_ERROR;
324325
}
325-
std::vector<uint8_t> hhk = libcdoc::Crypto::expand(fmk, std::vector<uint8_t>(libcdoc::CDoc2::HMAC.cbegin(), libcdoc::CDoc2::HMAC.cend()));
326+
std::vector<uint8_t> hhk = libcdoc::Crypto::expand(fmk, libcdoc::CDoc2::HMAC);
326327

327328
LOG_TRACE_KEY("xor: {}", lock.encrypted_fmk);
328329
LOG_TRACE_KEY("fmk: {}", fmk);
@@ -386,7 +387,7 @@ CDoc2Reader::beginDecryption(const std::vector<uint8_t>& fmk)
386387
}
387388
}
388389
priv->_at_nonce = false;
389-
std::vector<uint8_t> cek = libcdoc::Crypto::expand(fmk, std::vector<uint8_t>(libcdoc::CDoc2::CEK.cbegin(), libcdoc::CDoc2::CEK.cend()));
390+
std::vector<uint8_t> cek = libcdoc::Crypto::expand(fmk, libcdoc::CDoc2::CEK);
390391
LOG_TRACE_KEY("cek: {}", cek);
391392

392393
priv->dec = std::make_unique<libcdoc::DecryptionSource>(*priv->_src, EVP_chacha20_poly1305(), cek, libcdoc::CDoc2::NONCE_LEN);

cdoc/CDoc2Writer.cpp

Lines changed: 51 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ CDoc2Writer::writeHeader(const std::vector<libcdoc::Recipient> &recipients)
6363
return rv;
6464
}
6565

66-
auto hhk = libcdoc::Crypto::expand(fmk, {libcdoc::CDoc2::HMAC.cbegin(), libcdoc::CDoc2::HMAC.cend()});
67-
auto cek = libcdoc::Crypto::expand(fmk, {libcdoc::CDoc2::CEK.cbegin(), libcdoc::CDoc2::CEK.cend()});
66+
auto hhk = libcdoc::Crypto::expand(fmk, libcdoc::CDoc2::HMAC);
67+
auto cek = libcdoc::Crypto::expand(fmk, libcdoc::CDoc2::CEK);
6868
std::fill(fmk.begin(), fmk.end(), 0);
6969
LOG_TRACE_KEY("cek: {}", cek);
7070
LOG_TRACE_KEY("hhk: {}", hhk);
@@ -202,6 +202,25 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
202202
const libcdoc::Recipient& rcpt = recipients.at(rcpt_idx);
203203
if (rcpt.isPKI()) {
204204
std::vector<uint8_t> key_material, kek;
205+
std::string send_url;
206+
if(rcpt.isKeyServer()) {
207+
if(!conf) {
208+
setLastError("Configuration is missing");
209+
LOG_ERROR("{}", last_error);
210+
return libcdoc::CONFIGURATION_ERROR;
211+
}
212+
if(!network) {
213+
setLastError("Network backend is missing");
214+
LOG_ERROR("{}", last_error);
215+
return libcdoc::CONFIGURATION_ERROR;
216+
}
217+
send_url = conf->getValue(rcpt.server_id, libcdoc::Configuration::KEYSERVER_SEND_URL);
218+
if (send_url.empty()) {
219+
setLastError("Missing keyserver URL for ID " + rcpt.server_id);
220+
LOG_ERROR("{}", last_error);
221+
return libcdoc::CONFIGURATION_ERROR;
222+
}
223+
}
205224
if(rcpt.pk_type == libcdoc::Recipient::PKType::RSA) {
206225
crypto->random(kek, libcdoc::CDoc2::KEY_LEN);
207226
if (libcdoc::Crypto::xor_data(xor_key, fmk, kek) != libcdoc::OK) {
@@ -218,9 +237,25 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
218237
key_material = libcdoc::Crypto::encrypt(publicKey.get(), RSA_PKCS1_OAEP_PADDING, kek);
219238

220239
LOG_TRACE_KEY("publicKeyDer: {}", rcpt.rcpt_key);
221-
LOG_TRACE_KEY("kek: {}", kek);
222-
LOG_TRACE_KEY("fmk_xor_kek: {}", xor_key);
223240
LOG_TRACE_KEY("enc_kek: {}", key_material);
241+
LOG_TRACE_KEY("kek: {}", kek);
242+
LOG_TRACE_KEY("xor: {}", xor_key);
243+
if(rcpt.isKeyServer()) {
244+
libcdoc::NetworkBackend::CapsuleInfo cinfo;
245+
auto result = network->sendKey(cinfo, send_url, rcpt.rcpt_key, key_material, "rsa", rcpt.expiry_ts);
246+
if (result < 0) {
247+
setLastError(network->getLastErrorStr(result));
248+
LOG_ERROR("{}", last_error);
249+
return libcdoc::IO_ERROR;
250+
}
251+
252+
LOG_DBG("Keyserver Id: {}", rcpt.server_id);
253+
LOG_DBG("Transaction Id: {}", cinfo.transaction_id);
254+
255+
fb_rcpts.push_back(createRSAServerCapsule(builder, rcpt, cinfo.transaction_id, cinfo.expiry_time, xor_key));
256+
} else {
257+
fb_rcpts.push_back(createRSACapsule(builder, rcpt, key_material, xor_key));
258+
}
224259
} else {
225260
auto publicKey = libcdoc::Crypto::fromECPublicKeyDer(rcpt.rcpt_key, NID_secp384r1);
226261
if(!publicKey) {
@@ -232,12 +267,9 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
232267
std::vector<uint8_t> sharedSecret = libcdoc::Crypto::deriveSharedSecret(ephKey.get(), publicKey.get());
233268
key_material = libcdoc::Crypto::toPublicKeyDer(ephKey.get());
234269
std::vector<uint8_t> kekPm = libcdoc::Crypto::extract(sharedSecret, std::vector<uint8_t>(libcdoc::CDoc2::KEKPREMASTER.cbegin(), libcdoc::CDoc2::KEKPREMASTER.cend()));
235-
std::string info_str = std::string() + libcdoc::CDoc2::KEK.data() +
236-
cdoc20::header::EnumNameFMKEncryptionMethod(cdoc20::header::FMKEncryptionMethod::XOR) +
237-
std::string(rcpt.rcpt_key.cbegin(), rcpt.rcpt_key.cend()) +
238-
std::string(key_material.cbegin(), key_material.cend());
270+
std::string info_str = libcdoc::CDoc2::getSaltForExpand(key_material, rcpt.rcpt_key);
239271

240-
kek = libcdoc::Crypto::expand(kekPm, std::vector<uint8_t>(info_str.cbegin(), info_str.cend()), fmk.size());
272+
kek = libcdoc::Crypto::expand(kekPm, info_str, fmk.size());
241273
if (libcdoc::Crypto::xor_data(xor_key, fmk, kek) != libcdoc::OK) {
242274
setLastError("Internal error");
243275
LOG_ERROR("{}", last_error);
@@ -249,65 +281,11 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
249281
LOG_TRACE_KEY("ephPublicKeyDer: {}", key_material);
250282
LOG_TRACE_KEY("sharedSecret: {}", sharedSecret);
251283
LOG_TRACE_KEY("kekPm: {}", kekPm);
252-
}
253-
LOG_TRACE_KEY("kek: {}", kek);
254-
LOG_TRACE_KEY("xor: {}", xor_key);
255-
256-
if(rcpt.pk_type == libcdoc::Recipient::PKType::RSA) {
257-
if(rcpt.isKeyServer()) {
258-
if(!conf) {
259-
setLastError("Configuration is missing");
260-
LOG_ERROR("{}", last_error);
261-
return libcdoc::CONFIGURATION_ERROR;
262-
}
263-
if(!network) {
264-
setLastError("Network backend is missing");
265-
LOG_ERROR("{}", last_error);
266-
return libcdoc::CONFIGURATION_ERROR;
267-
}
268-
std::string send_url = conf->getValue(rcpt.server_id, libcdoc::Configuration::KEYSERVER_SEND_URL);
269-
if (send_url.empty()) {
270-
setLastError("Missing keyserver URL for ID " + rcpt.server_id);
271-
LOG_ERROR("{}", last_error);
272-
return libcdoc::CONFIGURATION_ERROR;
273-
}
274-
libcdoc::NetworkBackend::CapsuleInfo cinfo;
275-
int result = network->sendKey(cinfo, send_url, rcpt.rcpt_key, key_material, "RSA", rcpt.expiry_ts);
276-
if (result < 0) {
277-
setLastError(network->getLastErrorStr(result));
278-
LOG_ERROR("{}", last_error);
279-
return libcdoc::IO_ERROR;
280-
}
281-
282-
LOG_DBG("Keyserver Id: {}", rcpt.server_id);
283-
LOG_DBG("Transaction Id: {}", cinfo.transaction_id);
284-
285-
auto record = createRSAServerCapsule(builder, rcpt, cinfo.transaction_id, cinfo.expiry_time, xor_key);
286-
fb_rcpts.push_back(std::move(record));
287-
} else {
288-
auto record = createRSACapsule(builder, rcpt, key_material, xor_key);
289-
fb_rcpts.push_back(std::move(record));
290-
}
291-
} else {
284+
LOG_TRACE_KEY("kek: {}", kek);
285+
LOG_TRACE_KEY("xor: {}", xor_key);
292286
if(rcpt.isKeyServer()) {
293-
if(!conf) {
294-
setLastError("Configuration is missing");
295-
LOG_ERROR("{}", last_error);
296-
return libcdoc::CONFIGURATION_ERROR;
297-
}
298-
if(!network) {
299-
setLastError("Network backend is missing");
300-
LOG_ERROR("{}", last_error);
301-
return libcdoc::CONFIGURATION_ERROR;
302-
}
303-
std::string send_url = conf->getValue(rcpt.server_id, libcdoc::Configuration::KEYSERVER_SEND_URL);
304-
if (send_url.empty()) {
305-
setLastError("Missing keyserver URL for ID " + rcpt.server_id);
306-
LOG_ERROR("{}", last_error);
307-
return libcdoc::CONFIGURATION_ERROR;
308-
}
309287
libcdoc::NetworkBackend::CapsuleInfo cinfo;
310-
int result = network->sendKey(cinfo, send_url, rcpt.rcpt_key, key_material, "ecc_secp384r1", rcpt.expiry_ts);
288+
auto result = network->sendKey(cinfo, send_url, rcpt.rcpt_key, key_material, "ecc_secp384r1", rcpt.expiry_ts);
311289
if (result < 0) {
312290
setLastError(network->getLastErrorStr(result));
313291
LOG_ERROR("{}", last_error);
@@ -317,11 +295,9 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
317295
LOG_DBG("Keyserver Id: {}", rcpt.server_id);
318296
LOG_DBG("Transaction Id: {}", cinfo.transaction_id);
319297

320-
auto record = createECCServerCapsule(builder, rcpt, cinfo.transaction_id, cinfo.expiry_time, xor_key);
321-
fb_rcpts.push_back(std::move(record));
298+
fb_rcpts.push_back(createECCServerCapsule(builder, rcpt, cinfo.transaction_id, cinfo.expiry_time, xor_key));
322299
} else {
323-
auto record = createECCCapsule(builder, rcpt, key_material, xor_key);
324-
fb_rcpts.push_back(std::move(record));
300+
fb_rcpts.push_back(createECCCapsule(builder, rcpt, key_material, xor_key));
325301
}
326302
}
327303
} else if (rcpt.isSymmetric()) {
@@ -344,11 +320,11 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
344320
setLastError(crypto->getLastErrorStr(result));
345321
return result;
346322
}
347-
std::vector<uint8_t> kek = libcdoc::Crypto::expand(kek_pm, std::vector<uint8_t>(info_str.cbegin(), info_str.cend()), libcdoc::CDoc2::KEY_LEN);
323+
std::vector<uint8_t> kek = libcdoc::Crypto::expand(kek_pm, info_str, libcdoc::CDoc2::KEY_LEN);
348324

349325
LOG_DBG("Label: {}", rcpt.label);
350326
LOG_DBG("KDF iter: {}", rcpt.kdf_iter);
351-
LOG_DBG("info: {}", toHex(std::vector<uint8_t>(info_str.cbegin(), info_str.cend())));
327+
LOG_DBG("info: {}", toHex(info_str));
352328
LOG_TRACE_KEY("salt: {}", salt);
353329
LOG_TRACE_KEY("pw_salt: {}", pw_salt);
354330
LOG_TRACE_KEY("kek_pm: {}", kek_pm);
@@ -361,11 +337,9 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
361337
return libcdoc::CRYPTO_ERROR;
362338
}
363339
if (rcpt.kdf_iter > 0) {
364-
auto offs = createPasswordCapsule(builder, rcpt, salt, pw_salt, xor_key);
365-
fb_rcpts.push_back(std::move(offs));
340+
fb_rcpts.push_back(createPasswordCapsule(builder, rcpt, salt, pw_salt, xor_key));
366341
} else {
367-
auto offs = createSymmetricKeyCapsule(builder, rcpt, salt, xor_key);
368-
fb_rcpts.push_back(std::move(offs));
342+
fb_rcpts.push_back(createSymmetricKeyCapsule(builder, rcpt, salt, xor_key));
369343
}
370344
} else if (rcpt.isKeyShare()) {
371345
std::string url_list = conf->getValue(rcpt.server_id, libcdoc::Configuration::SHARE_SERVER_URLS);
@@ -405,7 +379,7 @@ CDoc2Writer::buildHeader(std::vector<uint8_t>& header, const std::vector<libcdoc
405379
// KEK_i = HKDF_Expand(KEK_i_pm, "CDOC2kek" + FMKEncryptionMethod + RecipientInfo_i, L)
406380
std::string info_str = std::string("CDOC2kek") + cdoc20::header::EnumNameFMKEncryptionMethod(cdoc20::header::FMKEncryptionMethod::XOR) + RecipientInfo_i;
407381
LOG_DBG("Info: {}", info_str);
408-
std::vector<uint8_t> kek = libcdoc::Crypto::expand(kek_pm, std::vector<uint8_t>(info_str.cbegin(), info_str.cend()));
382+
std::vector<uint8_t> kek = libcdoc::Crypto::expand(kek_pm, info_str);
409383
LOG_TRACE_KEY("kek: {}", kek);
410384
if (kek.empty()) return libcdoc::CRYPTO_ERROR;
411385
if (libcdoc::Crypto::xor_data(xor_key, fmk, kek) != libcdoc::OK) {

cdoc/Crypto.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ uint32_t Crypto::keySize(const std::string &algo)
243243
}
244244

245245
std::vector<uint8_t>
246-
Crypto::hkdf(const std::vector<uint8_t> &key, const std::vector<uint8_t> &salt, const std::vector<uint8_t> &info, int len, int mode)
246+
Crypto::hkdf(const std::vector<uint8_t> &key, const std::vector<uint8_t> &salt, std::string_view info, int len, int mode)
247247
{
248248
auto ctx = make_unique_ptr<EVP_PKEY_CTX_free>(EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr));
249249
if (!ctx)
@@ -259,15 +259,15 @@ Crypto::hkdf(const std::vector<uint8_t> &key, const std::vector<uint8_t> &salt,
259259
SSL_FAILED(EVP_PKEY_CTX_set_hkdf_md(ctx.get(), EVP_sha256()), "EVP_PKEY_CTX_set_hkdf_md") ||
260260
SSL_FAILED(EVP_PKEY_CTX_set1_hkdf_key(ctx.get(), key.data(), int(key.size())), "EVP_PKEY_CTX_set1_hkdf_key") ||
261261
(!salt.empty() && SSL_FAILED(EVP_PKEY_CTX_set1_hkdf_salt(ctx.get(), salt.data(), int(salt.size())), "EVP_PKEY_CTX_set1_hkdf_salt")) ||
262-
(!info.empty() && SSL_FAILED(EVP_PKEY_CTX_add1_hkdf_info(ctx.get(), info.data(), int(info.size())), "EVP_PKEY_CTX_add1_hkdf_info")) ||
262+
(!info.empty() && SSL_FAILED(EVP_PKEY_CTX_add1_hkdf_info(ctx.get(), (uint8_t*)info.data(), int(info.size())), "EVP_PKEY_CTX_add1_hkdf_info")) ||
263263
SSL_FAILED(EVP_PKEY_derive(ctx.get(), out.data(), &outlen), "EVP_PKEY_derive"))
264264
return {};
265265

266266
return out;
267267
}
268268

269269
std::vector<uint8_t>
270-
Crypto::expand(const std::vector<uint8_t> &key, const std::vector<uint8_t> &info, int len)
270+
Crypto::expand(const std::vector<uint8_t> &key, std::string_view info, int len)
271271
{
272272
return hkdf(key, {}, info, len, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY);
273273
}

cdoc/Crypto.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ class Crypto
7676
static Key generateKey(const std::string &method);
7777
static uint32_t keySize(const std::string &algo);
7878

79-
static std::vector<uint8_t> hkdf(const std::vector<uint8_t> &key, const std::vector<uint8_t> &salt, const std::vector<uint8_t> &info, int len = 32, int mode = 0);
80-
static std::vector<uint8_t> expand(const std::vector<uint8_t> &key, const std::vector<uint8_t> &info, int len = 32);
79+
static std::vector<uint8_t> hkdf(const std::vector<uint8_t> &key, const std::vector<uint8_t> &salt, std::string_view info, int len = 32, int mode = 0);
80+
static std::vector<uint8_t> expand(const std::vector<uint8_t> &key, std::string_view info, int len = 32);
8181
static std::vector<uint8_t> extract(const std::vector<uint8_t> &key, const std::vector<uint8_t> &salt, int len = 32);
8282
static std::vector<uint8_t> sign_hmac(const std::vector<uint8_t> &key, const std::vector<uint8_t> &data);
8383

libcdoc.i

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ static std::vector<unsigned char> SWIG_JavaArrayToVectorUnsignedChar(JNIEnv *jen
446446

447447
%ignore libcdoc::Recipient::rcpt_key;
448448
%ignore libcdoc::Recipient::cert;
449+
%ignore libcdoc::Recipient::getLabel;
449450
%extend libcdoc::Recipient {
450451
std::vector<uint8_t> getRcptKey() {
451452
return $self->rcpt_key;

0 commit comments

Comments
 (0)