Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/lavabit/magma.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLadar Levison <ladar@lavabit.com>2017-06-23 13:51:33 +0300
committerLadar Levison <ladar@lavabit.com>2017-06-23 13:51:33 +0300
commitc0f95ac9368a066a7c3fa97134cbed470b59cb80 (patch)
tree841eb38cc2a2f914c6ad150bee90ac7b798ff09e
parenta48e11b028b14f20e4914164535465ca13eb6d10 (diff)
First attempt at part_decrypt added to the repo. Tests still failing.
-rw-r--r--check/magma/prime/prime_check.c6
-rw-r--r--src/providers/prime/messages/chunks/chunks.h2
-rw-r--r--src/providers/prime/messages/chunks/encrypted.c7
-rw-r--r--src/providers/prime/messages/chunks/signature.c4
-rw-r--r--src/providers/prime/messages/messages.c17
-rw-r--r--src/providers/prime/messages/parts/parts.c88
6 files changed, 68 insertions, 56 deletions
diff --git a/check/magma/prime/prime_check.c b/check/magma/prime/prime_check.c
index 39fd93dd..ed826148 100644
--- a/check/magma/prime/prime_check.c
+++ b/check/magma/prime/prime_check.c
@@ -221,7 +221,7 @@ START_TEST (check_prime_chunk_encrypted_s) {
st_sprint(errmsg, "Encrypted chunk creation failed.");
result = false;
}
- else if (result && !(set = encrypted_chunk_get(signing_pub, decrypt_keks, encrypted_chunk_buffer(chunk), MANAGEDBUF(1024)))) {
+ else if (result && !(set = encrypted_chunk_get(signing_pub, decrypt_keks, encrypted_chunk_buffer(chunk), MANAGEDBUF(1024), NULL))) {
st_sprint(errmsg, "Encrypted chunk parsing failed.");
result = false;
}
@@ -242,7 +242,7 @@ START_TEST (check_prime_chunk_encrypted_s) {
st_sprint(errmsg, "Encrypted chunk creation failed.");
result = false;
}
- else if (result && !(set = encrypted_chunk_get(signing_pub, decrypt_keks, encrypted_chunk_buffer(chunk), MANAGEDBUF(1024)))) {
+ else if (result && !(set = encrypted_chunk_get(signing_pub, decrypt_keks, encrypted_chunk_buffer(chunk), MANAGEDBUF(1024), NULL))) {
st_sprint(errmsg, "Encrypted chunk parsing failed.");
result = false;
}
@@ -264,7 +264,7 @@ START_TEST (check_prime_chunk_encrypted_s) {
st_sprint(errmsg, "Encrypted chunk creation failed.");
result = false;
}
- else if (result && !(set = encrypted_chunk_get(signing_pub, decrypt_keks, encrypted_chunk_buffer(chunk), MANAGEDBUF(1024)))) {
+ else if (result && !(set = encrypted_chunk_get(signing_pub, decrypt_keks, encrypted_chunk_buffer(chunk), MANAGEDBUF(1024), NULL))) {
st_sprint(errmsg, "Encrypted chunk parsing failed.");
result = false;
}
diff --git a/src/providers/prime/messages/chunks/chunks.h b/src/providers/prime/messages/chunks/chunks.h
index fae1dcfa..d0d0e8cb 100644
--- a/src/providers/prime/messages/chunks/chunks.h
+++ b/src/providers/prime/messages/chunks/chunks.h
@@ -55,8 +55,8 @@ prime_encrypted_chunk_t * encrypted_chunk_alloc(void);
stringer_t * encrypted_chunk_buffer(prime_encrypted_chunk_t *chunk);
void encrypted_chunk_cleanup(prime_encrypted_chunk_t *chunk);
void encrypted_chunk_free(prime_encrypted_chunk_t *chunk);
+stringer_t * encrypted_chunk_get(ed25519_key_t *signing, prime_chunk_keks_t *keks, stringer_t *chunk, stringer_t *output, bool_t *spanning);
prime_encrypted_chunk_t * encrypted_chunk_set(prime_message_chunk_type_t type, ed25519_key_t *signing, prime_chunk_keks_t *keks, prime_message_chunk_flags_t flags, stringer_t *payload);
-stringer_t * encrypted_chunk_get(ed25519_key_t *signing, prime_chunk_keks_t *keks, stringer_t *chunk, stringer_t *output);
#endif
diff --git a/src/providers/prime/messages/chunks/encrypted.c b/src/providers/prime/messages/chunks/encrypted.c
index ab69d4f5..77a66242 100644
--- a/src/providers/prime/messages/chunks/encrypted.c
+++ b/src/providers/prime/messages/chunks/encrypted.c
@@ -172,7 +172,7 @@ prime_encrypted_chunk_t * encrypted_chunk_set(prime_message_chunk_type_t type, e
/**
* @brief Take an encrypted message chunk, in serialized form, and return the decrypted payload data.
*/
-stringer_t * encrypted_chunk_get(ed25519_key_t *signing, prime_chunk_keks_t *keks, stringer_t *chunk, stringer_t *output) {
+stringer_t * encrypted_chunk_get(ed25519_key_t *signing, prime_chunk_keks_t *keks, stringer_t *chunk, stringer_t *output, bool_t *spanning) {
int32_t payload_size = 0;
uint32_t big_endian_size = 0;
@@ -188,7 +188,6 @@ stringer_t * encrypted_chunk_get(ed25519_key_t *signing, prime_chunk_keks_t *kek
return NULL;
}
- /// HIGH: Add support for payloads that span across multiple chunks.
// The minimum legal chunk size would be 4 + 32 + 80 + 64 = 180, while the max would be 4 + 32 + 69 + 128 + 16,777,099 =
// 16,777,332, which accounts for the chunk header, and keyslots, which might be included in the buffer, but not in the
// chunk header length.
@@ -252,6 +251,10 @@ stringer_t * encrypted_chunk_get(ed25519_key_t *signing, prime_chunk_keks_t *kek
// Flags
mm_copy((uchr_t *)&flags, (uchr_t *)st_data_get(payload) + ED25519_SIGNATURE_LEN + 3, 1);
+ // If the spanning variable is valid pointer, then we'll check whether the spanning flag was set and let the caller know.
+ if (spanning && (flags & PRIME_CHUNK_FLAG_SPANNING) == PRIME_CHUNK_FLAG_SPANNING) *spanning = true;
+ else if (spanning) *spanning = false;
+
// Padding
mm_copy((uchr_t *)&padding, (uchr_t *)st_data_get(payload) + ED25519_SIGNATURE_LEN + 4, 1);
diff --git a/src/providers/prime/messages/chunks/signature.c b/src/providers/prime/messages/chunks/signature.c
index 14c5b213..0b4c583d 100644
--- a/src/providers/prime/messages/chunks/signature.c
+++ b/src/providers/prime/messages/chunks/signature.c
@@ -72,6 +72,10 @@ int_t signature_tree_add(prime_signature_tree_t *chunk, stringer_t *data) {
return 0;
}
+/**
+ * @brief Calculates the tree signature value by concatenating the hashes together, and generating an Ed25519 signature
+ * using the result.
+ */
stringer_t * signature_tree_get(ed25519_key_t *signing, prime_signature_tree_t *chunk, prime_chunk_keks_t *keks) {
placer_t buffer;
diff --git a/src/providers/prime/messages/messages.c b/src/providers/prime/messages/messages.c
index 3b026f37..bed67aaf 100644
--- a/src/providers/prime/messages/messages.c
+++ b/src/providers/prime/messages/messages.c
@@ -132,7 +132,7 @@ stringer_t * naked_message_get(stringer_t *message, prime_org_signet_t *org, pri
remaining -= st_length_get(&chunk[1]);
if (chunk_header_read(PLACER(data, remaining), &type, &size, &chunk[2]) < 0 || type != PRIME_CHUNK_HEADERS ||
- !(headers = encrypted_chunk_get(keys.signing, keks, &chunk[2], NULL))) {
+ !(headers = encrypted_chunk_get(keys.signing, keks, &chunk[2], NULL, NULL))) {
ephemeral_chunk_cleanup(ephemeral);
keks_free(keks);
return NULL;
@@ -227,6 +227,7 @@ prime_message_t * naked_message_set(stringer_t *message, prime_org_key_t *destin
uint32_t big_endian_size = 0;
prime_message_t *result = NULL;
prime_signature_tree_t *tree = NULL;
+ prime_encrypted_chunk_t *chunk = NULL;
stringer_t *common = NULL, *holder[10];
placer_t header = pl_null(), body = pl_null();
uint16_t type = htobe16(PRIME_MESSAGE_NAKED);
@@ -266,11 +267,12 @@ prime_message_t * naked_message_set(stringer_t *message, prime_org_key_t *destin
holder[8] = mail_header_fetch_cleaned(&header, PLACER("In-Reply-To", 11));
holder[9] = mail_header_fetch_cleaned(&header, PLACER("Message-ID", 10));
- /// LOW: An effective, albeit kludgey, logic to ensure common headers are formatted correctly, and the values reside on a single line.
+ /// LOW: Effective, albeit kludgey, logic to ensure common headers are formatted correctly, and each header field is
+ /// reformatted values reside on a single line.
common = st_merge("nsnnsnnsnnsnnsnnsnnsnnsnnsnnsn",
(holder[0] ? "Date: " : ""), holder[0], (holder[0] ? "\n" : ""),
(holder[1] ? "Subject: " : ""), holder[1], (holder[1] ? "\n" : ""),
- (holder[2] ? "From: " : ""), holder[2], (holder[2] ? "\encrypted_chunk_buffer(n" : ""),
+ (holder[2] ? "From: " : ""), holder[2], (holder[2] ? "\n" : ""),
(holder[3] ? "Sender: " : ""), holder[3], (holder[3] ? "\n" : ""),
(holder[4] ? "Reply-To: " : ""), holder[4], (holder[4] ? "\n" : ""),
(holder[5] ? "To: " : ""), holder[5], (holder[5] ? "\n" : ""),
@@ -312,7 +314,14 @@ prime_message_t * naked_message_set(stringer_t *message, prime_org_key_t *destin
signature_tree_add(tree, ephemeral_chunk_buffer(result->envelope.ephemeral));
signature_tree_add(tree, encrypted_chunk_buffer(result->metadata.common));
signature_tree_add(tree, encrypted_chunk_buffer(result->metadata.headers));
- signature_tree_add(tree, encrypted_chunk_buffer(result->content.body));
+
+ // Because the content chunks like the message body can be spanning chunks, we need to use an iterator which goes through
+ // the linked list, adding each chunk to the tree signature separately.
+ chunk = result->content.body;
+ while (chunk) {
+ signature_tree_add(tree, encrypted_chunk_buffer(chunk));
+ chunk = chunk->next;
+ }
// Calculate the tree signature.
result->signatures.tree = signature_tree_get(result->keys.signing, tree, &(result->keks));
diff --git a/src/providers/prime/messages/parts/parts.c b/src/providers/prime/messages/parts/parts.c
index 65429d05..c2a9ecf2 100644
--- a/src/providers/prime/messages/parts/parts.c
+++ b/src/providers/prime/messages/parts/parts.c
@@ -25,8 +25,10 @@ prime_encrypted_chunk_t * part_encrypt(prime_message_chunk_type_t type, ed25519_
return NULL;
}
- while (remaining) {
-//
+ // Process the payload. If the entire payload will fit, encrypt the entire buffer (or what remains), otherwise we'll set
+ // the spanning chunk flag, and loop around until we finish processing the entire payload.
+ do {
+
// Process the payload. If the entire payload will fit, encrypt the entire buffer (or what remains), otherwise we'll
// the next 16,777,098 bytes, set the spanning chunk flag, and loop around to finish the job.
if (!(holder = encrypted_chunk_set(type, signing, keks, (remaining > 16777098 ? PRIME_CHUNK_FLAG_SPANNING : PRIME_CHUNK_FLAG_NONE),
@@ -47,7 +49,8 @@ prime_encrypted_chunk_t * part_encrypt(prime_message_chunk_type_t type, ed25519_
// Advance our pointer and calculate the number of remaining bytes.
data += (remaining > 16777098 ? 16777098 : remaining);
remaining -= (remaining > 16777098 ? 16777098 : remaining);
- }
+
+ } while (remaining);
return result;
}
@@ -62,54 +65,47 @@ stringer_t * part_decrypt(ed25519_key_t *signing, prime_chunk_keks_t *keks, stri
// uint32_t legnth = 0;
// placer_t chunk = pl_null();
+ uchr_t *data = NULL;
+ bool_t spanning = false;
+ size_t length = 0, remaining = 0;
+ stringer_t *result = NULL, *payload = NULL;
+
// We need a signing key, encryption key, and at least one actor.
- if (!signing || ed25519_type(signing) != ED25519_PUB ||
+ if (!signing || st_empty_out(part, &data, &remaining) ||ed25519_type(signing) != ED25519_PUB ||
!keks || (!keks->author && !keks->origin && !keks->destination && !keks->recipient) || !part) {
log_pedantic("Invalid parameters passed to the encrypted chunk parser.");
return NULL;
}
- return NULL;
-//
-// size_t part_size;
-// uint8_t curr_type;
-// uint32_t chunk_size = 0;
-// placer_t slice = pl_null();
-// stringer_t *result = NULL, *curr_chunk = NULL;
-//
-// // Set the data buffer of the part stringer to the beginning of the payload.
-// st_data_set(part, st_data_get(payload));
-//
-// while (true) {
-//
-// // Read the chunk headers from the beginning of the remaining payload.
-// if (chunk_header_read(payload, &curr_type, &chunk_size, &slice) != 0) break;
-// part_size += st_length_get(&slice);
-//
-// // TODO: Instead, check if the spanning-chunk flag (128) is set in the header.
-// // Check if the chunk is still a part of the part that we are decrypting.
-// if (curr_type != type) break;
-//
-// // Pass this into encrypted_chunk_get().
-// if (!(curr_chunk = encrypted_chunk_get(signing, keks, &slice, NULL))) {
-// st_cleanup(result);
-// return NULL;
-// }
-//
-// // Either append curr_chunk onto result or set result equal to chunk.
-// result = st_append(result, curr_chunk);
-//
-// // Free curr_chunk.
-// st_free(curr_chunk);
-//
-// // Update payload and loop if necessary.
-// st_data_set(payload, st_data_get(payload) + st_length_get(&slice));
-// st_length_set(payload, st_length_get(payload) - st_length_get(&slice));
-// }
-//
-// // Construct the part-spanning chunk placer.
-// st_length_set(part, part_size);
-//
-// return result;
+ // Decrypt the first chunk, and if the spanning chunk flag is set, keep looping until we encounter a chunk without the
+ // spanning chunk flag, or we exhaust the data buffer.
+ do {
+
+ if (!(payload = encrypted_chunk_get(signing, keks, PLACER(data, (length = chunk_header_size(PLACER(data, remaining)))), NULL, &spanning))) {
+ log_pedantic("Body part decryption failed.");
+ return NULL;
+ }
+ else if (result) {
+ result = st_append(result, payload);
+ st_free(payload);
+ }
+ else {
+ result = payload;
+ }
+
+ data += length;
+ remaining -= length;
+
+ } while (remaining && spanning);
+
+ // If the entire buffer was processed and the spanning flag is still set, then our result is incomplete, so rather than
+ // return partial data, we return NULL to indicate an error.
+ if (!remaining && spanning) {
+ log_pedantic("Body part decryption failed. The last chunk in the span is missing.");
+ st_free(result);
+ return NULL;
+ }
+
+ return result;
}