add initial implementation of basic private key encryption functionality

This commit is contained in:
Hubert Chathi 2018-06-11 17:48:45 -04:00
parent 6a2a2741e8
commit 128d45cc83
7 changed files with 752 additions and 1 deletions

View file

@ -21,7 +21,7 @@ JS_TARGET := javascript/olm.js
JS_EXPORTED_FUNCTIONS := javascript/exported_functions.json
PUBLIC_HEADERS := include/olm/olm.h include/olm/outbound_group_session.h include/olm/inbound_group_session.h
PUBLIC_HEADERS := include/olm/olm.h include/olm/outbound_group_session.h include/olm/inbound_group_session.h include/olm/pk.h
SOURCES := $(wildcard src/*.cpp) $(wildcard src/*.c) \
lib/crypto-algorithms/sha256.c \
@ -42,6 +42,7 @@ JS_OBJECTS := $(addprefix $(BUILD_DIR)/javascript/,$(OBJECTS))
JS_PRE := $(wildcard javascript/*pre.js)
JS_POST := javascript/olm_outbound_group_session.js \
javascript/olm_inbound_group_session.js \
javascript/olm_pk.js \
javascript/olm_post.js
DOCS := tracing/README.html \
docs/megolm.html \

148
include/olm/pk.h Normal file
View file

@ -0,0 +1,148 @@
/* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OLM_PK_H_
#define OLM_PK_H_
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct OlmPkEncryption OlmPkEncryption;
/* The size of an encryption object in bytes */
size_t olm_pk_encryption_size();
/** Initialise an encryption object using the supplied memory
* The supplied memory must be at least olm_pk_encryption_size() bytes */
OlmPkEncryption *olm_pk_encryption(
void * memory
);
/** A null terminated string describing the most recent error to happen to an
* encryption object */
const char * olm_pk_encryption_last_error(
OlmPkEncryption * encryption
);
/** Clears the memory used to back this encryption object */
size_t olm_clear_pk_encryption(
OlmPkEncryption *encryption
);
/** Set the recipient's public key for encrypting to */
size_t olm_pk_encryption_set_recipient_key(
OlmPkEncryption *encryption,
void const *public_key, size_t public_key_length
);
/** Get the length of the ciphertext that will correspond to a plaintext of the
* given length. */
size_t olm_pk_ciphertext_length(
OlmPkEncryption *encryption,
size_t plaintext_length
);
/** Get the length of the message authentication code. */
size_t olm_pk_mac_length(
OlmPkEncryption *encryption
);
/** Get the length of a public or ephemeral key */
size_t olm_pk_key_length();
/** The number of random bytes needed to encrypt a message. */
size_t olm_pk_encrypt_random_length(
OlmPkEncryption *encryption
);
/** Encrypt a plaintext for the recipient set using
* olm_pk_encryption_set_recipient_key. Returns olm_error() on failure. If the
* ciphertext, mac, or ephemeral_key buffers were too small then
* olm_pk_encryption_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". If there
* weren't enough random bytes then olm_pk_encryption_last_error() will be
* "NOT_ENOUGH_RANDOM". */
size_t olm_pk_encrypt(
OlmPkEncryption *encryption,
void const * plaintext, size_t plaintext_length,
void * ciphertext, size_t ciphertext_length,
void * mac, size_t mac_length,
void * ephemeral_key, size_t ephemeral_key_size,
void * random, size_t random_length
);
typedef struct OlmPkDecryption OlmPkDecryption;
/* The size of a decryption object in bytes */
size_t olm_pk_decryption_size();
/** Initialise a decryption object using the supplied memory
* The supplied memory must be at least olm_pk_decryption_size() bytes */
OlmPkDecryption *olm_pk_decryption(
void * memory
);
/** A null terminated string describing the most recent error to happen to a
* decription object */
const char * olm_pk_decryption_last_error(
OlmPkDecryption * decryption
);
/** Clears the memory used to back this decryption object */
size_t olm_clear_pk_decryption(
OlmPkDecryption *decryption
);
/** The number of random bytes needed to generate a new key. */
size_t olm_pk_generate_key_random_length();
/** Generate a new key to use for decrypting messages. The associated public
* key will be written to the pubkey buffer. Returns olm_error() on failure. If
* the pubkey buffer is too small then olm_pk_decryption_last_error() will be
* "OUTPUT_BUFFER_TOO_SMALL". If there weren't enough random bytes then
* olm_pk_decryption_last_error() will be "NOT_ENOUGH_RANDOM". */
size_t olm_pk_generate_key(
OlmPkDecryption * decryption,
void * pubkey, size_t pubkey_length,
void * random, size_t random_length
);
/** Get the length of the plaintext that will correspond to a ciphertext of the
* given length. */
size_t olm_pk_max_plaintext_length(
OlmPkDecryption * decryption,
size_t ciphertext_length
);
/** Decrypt a ciphertext. The input ciphertext buffer is destroyed. Returns
* the length of the plaintext on success. Returns olm_error() on failure. If
* the plaintext buffer is too small then olm_pk_encryption_last_error() will
* be "OUTPUT_BUFFER_TOO_SMALL". */
size_t olm_pk_decrypt(
OlmPkDecryption * decrytion,
void const * ephemeral_key, size_t ephemeral_key_length,
void const * mac, size_t mac_length,
void * ciphertext, size_t ciphertext_length,
void * plaintext, size_t max_plaintext_length
);
#ifdef __cplusplus
}
#endif
#endif /* OLM_PK_H_ */

179
javascript/olm_pk.js Normal file
View file

@ -0,0 +1,179 @@
function PkEncryption() {
var size = Module['_olm_pk_encryption_size']();
this.buf = malloc(size);
this.ptr = Module['_olm_pk_encryption'](this.buf);
}
function pk_encryption_method(wrapped) {
return function() {
var result = wrapped.apply(this, arguments);
if (result === OLM_ERROR) {
var message = Pointer_stringify(
Module['_olm_pk_encryption_last_error'](arguments[0])
);
throw new Error("OLM." + message);
}
return result;
}
}
PkEncryption.prototype['free'] = function() {
Module['_olm_clear_pk_encryption'](this.ptr);
free(this.ptr);
}
PkEncryption.prototype['set_recipient_key'] = restore_stack(function(key) {
var key_array = array_from_string(key);
var key_buffer = stack(key_array);
pk_encryption_method(Module['_olm_pk_encryption_set_recipient_key'])(
this.ptr, key_buffer, key_array.length
);
});
PkEncryption.prototype['encrypt'] = restore_stack(function(
plaintext
) {
var plaintext_buffer, ciphertext_buffer, plaintext_length;
try {
plaintext_length = Module['lengthBytesUTF8'](plaintext)
plaintext_buffer = malloc(plaintext_length + 1);
Module['stringToUTF8'](plaintext, plaintext_buffer, plaintext_length + 1);
var random_length = pk_encryption_method(
Module['_olm_pk_encrypt_random_length']
)();
var random = random_stack(random_length);
var ciphertext_length = pk_encryption_method(
Module['_olm_pk_ciphertext_length']
)(this.ptr, plaintext_length);
ciphertext_buffer = malloc(ciphertext_length + NULL_BYTE_PADDING_LENGTH);
var mac_length = pk_encryption_method(
Module['_olm_pk_mac_length']
)(this.ptr);
var mac_buffer = stack(mac_length + NULL_BYTE_PADDING_LENGTH);
Module['setValue'](
mac_buffer+mac_length,
0, "i8"
);
var ephemeral_length = pk_encryption_method(
Module['_olm_pk_key_length']
)();
var ephemeral_buffer = stack(ephemeral_length + NULL_BYTE_PADDING_LENGTH);
Module['setValue'](
ephemeral_buffer+ephemeral_length,
0, "i8"
);
pk_encryption_method(Module['_olm_pk_encrypt'])(
this.ptr,
plaintext_buffer, plaintext_length,
ciphertext_buffer, ciphertext_length,
mac_buffer, mac_length,
ephemeral_buffer, ephemeral_length,
random, random_length
);
// UTF8ToString requires a null-terminated argument, so add the
// null terminator.
Module['setValue'](
ciphertext_buffer+ciphertext_length,
0, "i8"
);
return {
"ciphertext": Module['UTF8ToString'](ciphertext_buffer),
"mac": Pointer_stringify(mac_buffer),
"ephemeral": Pointer_stringify(ephemeral_buffer)
};
} finally {
if (plaintext_buffer !== undefined) {
// don't leave a copy of the plaintext in the heap.
bzero(plaintext_buffer, plaintext_length + 1);
free(plaintext_buffer);
}
if (ciphertext_buffer !== undefined) {
free(ciphertext_buffer);
}
}
});
function PkDecryption() {
var size = Module['_olm_pk_decryption_size']();
this.buf = malloc(size);
this.ptr = Module['_olm_pk_decryption'](this.buf);
}
function pk_decryption_method(wrapped) {
return function() {
var result = wrapped.apply(this, arguments);
if (result === OLM_ERROR) {
var message = Pointer_stringify(
Module['_olm_pk_decryption_last_error'](arguments[0])
);
throw new Error("OLM." + message);
}
return result;
}
}
PkDecryption.prototype['free'] = function() {
Module['_olm_clear_pk_decryption'](this.ptr);
free(this.ptr);
}
PkDecryption.prototype['generate_key'] = restore_stack(function () {
var random_length = pk_decryption_method(
Module['_olm_pk_key_length'] // FIXME: wrong method
)();
var random_buffer = random_stack(random_length);
var pubkey_length = pk_encryption_method(
Module['_olm_pk_key_length']
)();
var pubkey_buffer = stack(pubkey_length);
pk_decryption_method(Module['_olm_pk_generate_key'])(
this.ptr,
pubkey_buffer, pubkey_length,
random_buffer, random_length
);
return Pointer_stringify(pubkey_buffer);
});
PkDecryption.prototype['decrypt'] = restore_stack(function (
ephemeral_key, mac, ciphertext
) {
var plaintext_buffer, ciphertext_buffer, plaintext_max_length;
try {
ciphertext_length = Module['lengthBytesUTF8'](ciphertext)
ciphertext_buffer = malloc(ciphertext_length + 1);
Module['stringToUTF8'](ciphertext, ciphertext_buffer, ciphertext_length + 1);
var ephemeralkey_array = array_from_string(ephemeral_key);
var ephemeralkey_buffer = stack(ephemeralkey_array);
var mac_array = array_from_string(mac);
var mac_buffer = stack(mac_array);
plaintext_max_length = pk_decryption_method(Module['_olm_pk_max_plaintext_length'])(
this.ptr,
ciphertext_length
);
plaintext_buffer = malloc(plaintext_max_length + NULL_BYTE_PADDING_LENGTH);
var plaintext_length = pk_decryption_method(Module['_olm_pk_decrypt'])(
this.ptr,
ephemeralkey_buffer, ephemeralkey_array.length,
mac_buffer, mac_array.length,
ciphertext_buffer, ciphertext_length,
plaintext_buffer, plaintext_max_length
);
// UTF8ToString requires a null-terminated argument, so add the
// null terminator.
Module['setValue'](
plaintext_buffer+plaintext_length,
0, "i8"
);
return Module['UTF8ToString'](plaintext_buffer);
} finally {
if (plaintext_buffer !== undefined) {
// don't leave a copy of the plaintext in the heap.
bzero(plaintext_buffer, plaintext_length + 1);
free(plaintext_buffer);
}
if (ciphertext_buffer !== undefined) {
free(ciphertext_buffer);
}
}
})

View file

@ -461,6 +461,8 @@ Utility.prototype['ed25519_verify'] = restore_stack(function(
olm_exports["Account"] = Account;
olm_exports["Session"] = Session;
olm_exports["Utility"] = Utility;
olm_exports["PkEncryption"] = PkEncryption;
olm_exports["PkDecryption"] = PkDecryption;
olm_exports["get_library_version"] = restore_stack(function() {
var buf = stack(3);

View file

@ -0,0 +1,64 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
"use strict";
var Olm = require('../olm');
if (!Object.keys) {
Object.keys = function(o) {
var k=[], p;
for (p in o) if (Object.prototype.hasOwnProperty.call(o,p)) k.push(p);
return k;
}
}
describe("pk", function() {
var encryption, decryption;
beforeEach(function() {
encryption = new Olm.PkEncryption();
decryption = new Olm.PkDecryption();
});
afterEach(function () {
if (encryption !== undefined) {
encryption.free();
encryption = undefined;
}
if (decryption !== undefined) {
decryption.free();
decryption = undefined;
}
});
it('should encrypt and decrypt', function () {
var TEST_TEXT='têst1';
var pubkey = decryption.generate_key();
encryption.set_recipient_key(pubkey);
var encrypted = encryption.encrypt(TEST_TEXT);
var decrypted = decryption.decrypt(encrypted.ephemeral, encrypted.mac, encrypted.ciphertext);
console.log(TEST_TEXT, "->", decrypted);
expect(decrypted).toEqual(TEST_TEXT);
TEST_TEXT='hot beverage: ☕';
encryption.set_recipient_key(pubkey);
encrypted = encryption.encrypt(TEST_TEXT);
decrypted = decryption.decrypt(encrypted.ephemeral, encrypted.mac, encrypted.ciphertext);
console.log(TEST_TEXT, "->", decrypted);
expect(decrypted).toEqual(TEST_TEXT);
});
});

253
src/pk.cpp Normal file
View file

@ -0,0 +1,253 @@
/* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "olm/pk.h"
#include "olm/cipher.h"
#include "olm/crypto.h"
#include "olm/ratchet.hh"
#include "olm/error.h"
#include "olm/memory.hh"
#include "olm/base64.hh"
extern "C" {
static const std::size_t MAC_LENGTH = 8;
const struct _olm_cipher_aes_sha_256 olm_pk_cipher_aes_sha256 =
OLM_CIPHER_INIT_AES_SHA_256("");
const struct _olm_cipher *olm_pk_cipher =
OLM_CIPHER_BASE(&olm_pk_cipher_aes_sha256);
struct OlmPkEncryption {
OlmErrorCode last_error;
_olm_curve25519_public_key recipient_key;
};
const char * olm_pk_encryption_last_error(
OlmPkEncryption * encryption
) {
auto error = encryption->last_error;
return _olm_error_to_string(error);
}
size_t olm_pk_encryption_size() {
return sizeof(OlmPkEncryption);
}
OlmPkEncryption *olm_pk_encryption(
void * memory
) {
olm::unset(memory, sizeof(OlmPkEncryption));
return new(memory) OlmPkEncryption;
}
size_t olm_clear_pk_encryption(
OlmPkEncryption *encryption
) {
/* Clear the memory backing the encryption */
olm::unset(encryption, sizeof(OlmPkEncryption));
/* Initialise a fresh encryption object in case someone tries to use it */
new(encryption) OlmPkEncryption();
return sizeof(OlmPkEncryption);
}
size_t olm_pk_encryption_set_recipient_key (
OlmPkEncryption *encryption,
void const * key, size_t key_length
) {
if (key_length < olm_pk_key_length()) {
encryption->last_error =
OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL; // FIXME:
return std::size_t(-1);
}
olm::decode_base64((const uint8_t*)key, olm_pk_key_length(), (uint8_t *)encryption->recipient_key.public_key);
return 0;
}
size_t olm_pk_ciphertext_length(
OlmPkEncryption *encryption,
size_t plaintext_length
) {
return olm::encode_base64_length(_olm_cipher_aes_sha_256_ops.encrypt_ciphertext_length(olm_pk_cipher, plaintext_length));
}
size_t olm_pk_mac_length(
OlmPkEncryption *encryption
) {
return olm::encode_base64_length(_olm_cipher_aes_sha_256_ops.mac_length(olm_pk_cipher));
}
size_t olm_pk_encrypt_random_length(
OlmPkEncryption *encryption
) {
return CURVE25519_KEY_LENGTH;
}
size_t olm_pk_encrypt(
OlmPkEncryption *encryption,
void const * plaintext, size_t plaintext_length,
void * ciphertext, size_t ciphertext_length,
void * mac, size_t mac_length,
void * ephemeral_key, size_t ephemeral_key_size,
void * random, size_t random_length
) {
if (ciphertext_length
< olm_pk_ciphertext_length(encryption, plaintext_length)
|| mac_length
< _olm_cipher_aes_sha_256_ops.mac_length(olm_pk_cipher)
|| ephemeral_key_size
< olm_pk_key_length()) {
encryption->last_error =
OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
return std::size_t(-1);
}
if (random_length < olm_pk_encrypt_random_length(encryption)) {
encryption->last_error =
OlmErrorCode::OLM_NOT_ENOUGH_RANDOM;
return std::size_t(-1);
}
_olm_curve25519_key_pair ephemeral_keypair;
_olm_crypto_curve25519_generate_key((uint8_t *) random, &ephemeral_keypair);
olm::encode_base64((const uint8_t *)ephemeral_keypair.public_key.public_key, CURVE25519_KEY_LENGTH, (uint8_t *)ephemeral_key);
olm::SharedKey secret;
_olm_crypto_curve25519_shared_secret(&ephemeral_keypair, &encryption->recipient_key, secret);
size_t raw_ciphertext_length = _olm_cipher_aes_sha_256_ops.encrypt_ciphertext_length(olm_pk_cipher, plaintext_length);
uint8_t *ciphertext_pos = (uint8_t *) ciphertext + ciphertext_length - raw_ciphertext_length;
uint8_t raw_mac[MAC_LENGTH];
size_t result = _olm_cipher_aes_sha_256_ops.encrypt(
olm_pk_cipher,
secret, sizeof(secret),
(const uint8_t *) plaintext, plaintext_length,
(uint8_t *) ciphertext_pos, raw_ciphertext_length,
(uint8_t *) raw_mac, MAC_LENGTH
);
if (result != std::size_t(-1)) {
olm::encode_base64(raw_mac, MAC_LENGTH, (uint8_t *)mac);
olm::encode_base64(ciphertext_pos, raw_ciphertext_length, (uint8_t *)ciphertext);
}
return result;
}
struct OlmPkDecryption {
OlmErrorCode last_error;
_olm_curve25519_key_pair key_pair;
};
const char * olm_pk_decryption_last_error(
OlmPkDecryption * decryption
) {
auto error = decryption->last_error;
return _olm_error_to_string(error);
}
size_t olm_pk_decryption_size() {
return sizeof(OlmPkDecryption);
}
OlmPkDecryption *olm_pk_decryption(
void * memory
) {
olm::unset(memory, sizeof(OlmPkDecryption));
return new(memory) OlmPkDecryption;
}
size_t olm_clear_pk_decryption(
OlmPkDecryption *decryption
) {
/* Clear the memory backing the decryption */
olm::unset(decryption, sizeof(OlmPkDecryption));
/* Initialise a fresh decryption object in case someone tries to use it */
new(decryption) OlmPkDecryption();
return sizeof(OlmPkDecryption);
}
size_t olm_pk_generate_key_random_length() {
return CURVE25519_KEY_LENGTH;
}
size_t olm_pk_key_length() {
return olm::encode_base64_length(CURVE25519_KEY_LENGTH);
}
size_t olm_pk_generate_key(
OlmPkDecryption * decryption,
void * pubkey, size_t pubkey_length,
void * random, size_t random_length
) {
if (pubkey_length < CURVE25519_KEY_LENGTH) {
decryption->last_error =
OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
return std::size_t(-1);
}
if (random_length < olm_pk_generate_key_random_length()) {
decryption->last_error =
OlmErrorCode::OLM_NOT_ENOUGH_RANDOM;
return std::size_t(-1);
}
_olm_crypto_curve25519_generate_key((uint8_t *) random, &decryption->key_pair);
olm::encode_base64((const uint8_t *)decryption->key_pair.public_key.public_key, CURVE25519_KEY_LENGTH, (uint8_t *)pubkey);
return 0;
}
size_t olm_pk_max_plaintext_length(
OlmPkDecryption * decryption,
size_t ciphertext_length
) {
return _olm_cipher_aes_sha_256_ops.decrypt_max_plaintext_length(olm_pk_cipher, olm::decode_base64_length(ciphertext_length));
}
size_t olm_pk_decrypt(
OlmPkDecryption * decryption,
void const * ephemeral_key, size_t ephemeral_key_length,
void const * mac, size_t mac_length,
void * ciphertext, size_t ciphertext_length,
void * plaintext, size_t max_plaintext_length
) {
if (max_plaintext_length
< olm_pk_max_plaintext_length(decryption, ciphertext_length)) {
decryption->last_error =
OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
return std::size_t(-1);
}
struct _olm_curve25519_public_key ephemeral;
olm::decode_base64((const uint8_t*)ephemeral_key, ephemeral_key_length, (uint8_t *)ephemeral.public_key);
olm::SharedKey secret;
_olm_crypto_curve25519_shared_secret(&decryption->key_pair, &ephemeral, secret);
uint8_t raw_mac[MAC_LENGTH];
olm::decode_base64((const uint8_t*)mac, olm::encode_base64_length(MAC_LENGTH), raw_mac);
size_t raw_ciphertext_length = olm::decode_base64_length(ciphertext_length);
olm::decode_base64((const uint8_t *)ciphertext, ciphertext_length, (uint8_t *)ciphertext);
size_t result = _olm_cipher_aes_sha_256_ops.decrypt(
olm_pk_cipher,
secret, sizeof(secret),
(uint8_t *) raw_mac, MAC_LENGTH,
(const uint8_t *) ciphertext, raw_ciphertext_length,
(uint8_t *) plaintext, max_plaintext_length
);
if (result == std::size_t(-1)) {
// we already checked the buffer sizes, so the only error that decrypt
// will return is if the MAC is incorrect
decryption->last_error =
OlmErrorCode::OLM_BAD_MESSAGE_MAC;
return std::size_t(-1);
} else {
return result;
}
}
}

104
tests/test_pk.cpp Normal file
View file

@ -0,0 +1,104 @@
#include "olm/pk.h"
#include "olm/crypto.h"
#include "olm/olm.h"
#include "unittest.hh"
#include <iostream>
int main() {
{ /* Encryption Test Case 1 */
TestCase test_case("Public Key Encryption/Decryption Test Case 1");
std::uint8_t decryption_buffer[::olm_pk_decryption_size()];
OlmPkDecryption *decryption = olm_pk_decryption(decryption_buffer);
std::uint8_t alice_private[32] = {
0x77, 0x07, 0x6D, 0x0A, 0x73, 0x18, 0xA5, 0x7D,
0x3C, 0x16, 0xC1, 0x72, 0x51, 0xB2, 0x66, 0x45,
0xDF, 0x4C, 0x2F, 0x87, 0xEB, 0xC0, 0x99, 0x2A,
0xB1, 0x77, 0xFB, 0xA5, 0x1D, 0xB9, 0x2C, 0x2A
};
/*
std::uint8_t alice_public[32] = {
0x85, 0x20, 0xF0, 0x09, 0x89, 0x30, 0xA7, 0x54,
0x74, 0x8B, 0x7D, 0xDC, 0xB4, 0x3E, 0xF7, 0x5A,
0x0D, 0xBF, 0x3A, 0x0D, 0x26, 0x38, 0x1A, 0xF4,
0xEB, 0xA4, 0xA9, 0x8E, 0xAA, 0x9B, 0x4E, 0x6A
};
*/
std::uint8_t bob_private[32] = {
0x5D, 0xAB, 0x08, 0x7E, 0x62, 0x4A, 0x8A, 0x4B,
0x79, 0xE1, 0x7F, 0x8B, 0x83, 0x80, 0x0E, 0xE6,
0x6F, 0x3B, 0xB1, 0x29, 0x26, 0x18, 0xB6, 0xFD,
0x1C, 0x2F, 0x8B, 0x27, 0xFF, 0x88, 0xE0, 0xEB
};
/*
std::uint8_t bob_public[32] = {
0xDE, 0x9E, 0xDB, 0x7D, 0x7B, 0x7D, 0xC1, 0xB4,
0xD3, 0x5B, 0x61, 0xC2, 0xEC, 0xE4, 0x35, 0x37,
0x3F, 0x83, 0x43, 0xC8, 0x5B, 0x78, 0x67, 0x4D,
0xAD, 0xFC, 0x7E, 0x14, 0x6F, 0x88, 0x2B, 0x4F
};
*/
std::uint8_t pubkey[::olm_pk_key_length()];
olm_pk_generate_key(
decryption,
pubkey, sizeof(pubkey),
alice_private, sizeof(alice_private)
);
//FIXME:assert_equals(alice_public, pubkey, 32);
std::uint8_t encryption_buffer[::olm_pk_encryption_size()];
OlmPkEncryption *encryption = olm_pk_encryption(encryption_buffer);
olm_pk_encryption_set_recipient_key(encryption, pubkey, sizeof(pubkey));
const size_t plaintext_length = 14;
const std::uint8_t *plaintext = (std::uint8_t *) "This is a test";
size_t ciphertext_length = olm_pk_ciphertext_length(encryption, plaintext_length);
std::uint8_t *ciphertext_buffer = (std::uint8_t *) malloc(ciphertext_length);
std::uint8_t output_buffer[::olm_pk_mac_length(encryption)];
std::uint8_t ephemeral_key[::olm_pk_key_length()];
olm_pk_encrypt(
encryption,
plaintext, plaintext_length,
ciphertext_buffer, ciphertext_length,
output_buffer, sizeof(output_buffer),
ephemeral_key, sizeof(ephemeral_key),
bob_private, sizeof(bob_private)
);
//FIXME:assert_equals(bob_public, ephemeral_key, 32);
size_t max_plaintext_length = olm_pk_max_plaintext_length(decryption, ciphertext_length);
std::uint8_t *plaintext_buffer = (std::uint8_t *) malloc(max_plaintext_length);
olm_pk_decrypt(
decryption,
ephemeral_key, sizeof(ephemeral_key),
output_buffer, sizeof(output_buffer),
ciphertext_buffer, ciphertext_length,
plaintext_buffer, max_plaintext_length
);
assert_equals(plaintext, plaintext_buffer, plaintext_length);
free(ciphertext_buffer);
free(plaintext_buffer);
}
}