Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
matrix-org
Olm
Commits
4abead9e
Commit
4abead9e
authored
Jun 15, 2015
by
Mark Haines
Browse files
Add c interface which wraps the cpp classes
parent
7cdde735
Changes
2
Hide whitespace changes
Inline
Side-by-side
include/axolotl/axolotl.hh
0 → 100644
View file @
4abead9e
#ifndef AXOLOTL_HH_
#define AXOLOTL_HH_
#include <stddef.h>
#ifdef __cplusplus
extern
"C"
{
#endif
static
const
size_t
AXOLOTL_MESSAGE_TYPE_PRE_KEY
=
0
;
static
const
size_t
AXOLOTL_MESSAGE_TYPE_MESSAGE
=
1
;
struct
AxolotlAccount
;
struct
AxolotlSession
;
size_t
axolotl_account_size
();
size_t
axolotl_session_size
();
AxolotlAccount
*
axolotl_account
(
void
*
memory
);
AxolotlSession
*
axolotl_session
(
void
*
memory
);
size_t
axolotl_error
();
const
char
*
axolotl_account_last_error
(
AxolotlSession
*
account
);
const
char
*
axolotl_session_last_error
(
AxolotlSession
*
session
);
size_t
axolotl_pickle_account_length
(
AxolotlAccount
*
account
);
size_t
axolotl_pickle_session_length
(
AxolotlSession
*
session
);
size_t
axolotl_pickle_account
(
AxolotlAccount
*
account
,
void
const
*
key
,
size_t
key_length
,
void
*
pickled
,
size_t
pickled_length
);
size_t
axolotl_pickle_session
(
AxolotlSession
*
session
,
void
const
*
key
,
size_t
key_length
,
void
*
pickled
,
size_t
pickled_length
);
size_t
axolotl_unpickle_account
(
AxolotlAccount
*
account
,
void
const
*
key
,
size_t
key_length
,
void
*
pickled
,
size_t
pickled_length
);
size_t
axolotl_unpickle_session
(
AxolotlSession
*
session
,
void
const
*
key
,
size_t
key_length
,
void
*
pickled
,
size_t
pickled_length
);
size_t
axolotl_create_account_random_length
(
AxolotlAccount
*
account
);
size_t
axolotl_create_account
(
AxolotlAccount
*
account
,
void
const
*
random
,
size_t
random_length
);
size_t
axolotl_account_identity_keys_length
(
AxolotlAccount
*
account
);
size_t
axolotl_account_identity_keys
(
AxolotlAccount
*
account
,
void
*
identity_keys
,
size_t
identity_key_length
);
size_t
axolotl_account_one_time_keys_length
(
AxolotlAccount
*
account
);
size_t
axolotl_account_one_time_keys
(
AxolotlAccount
*
account
,
void
*
identity_keys
,
size_t
identity_key_length
);
/* TODO: Add methods for marking keys as used, generating new keys, and
* tracking which keys have been uploaded to the central servers */
size_t
axolotl_create_outbound_session_random_length
(
AxolotlSession
*
session
);
size_t
axolotl_create_outbound_session
(
AxolotlSession
*
session
,
AxolotlAccount
*
account
,
void
const
*
their_identity_key
,
size_t
their_identity_key_length
,
unsigned
their_one_time_key_id
,
void
const
*
their_one_time_key
,
size_t
their_one_time_key_length
,
void
const
*
random
,
size_t
random_length
);
size_t
axolotl_create_inbound_session
(
AxolotlSession
*
session
,
AxolotlAccount
*
account
,
void
*
one_time_key_message
,
size_t
message_length
);
size_t
axolotl_matches_inbound_session
(
AxolotlSession
*
session
,
void
*
one_time_key_message
,
size_t
message_length
);
size_t
axolotl_encrypt_message_type
(
AxolotlSession
*
session
);
size_t
axolotl_encrypt_random_length
(
AxolotlSession
*
session
);
size_t
axolotl_encrypt_message_length
(
AxolotlSession
*
session
,
size_t
plaintext_length
);
size_t
axolotl_encrypt
(
AxolotlSession
*
session
,
void
const
*
plaintext
,
size_t
plaintext_length
,
void
const
*
random
,
size_t
random_length
,
void
*
message
,
size_t
message_length
);
size_t
axolotl_decrypt_max_plaintext_length
(
AxolotlSession
*
session
,
size_t
message_type
,
void
*
message
,
size_t
message_length
);
size_t
axolotl_decrypt
(
AxolotlSession
*
session
,
size_t
message_type
,
void
*
message
,
size_t
message_length
,
void
*
plaintext
,
size_t
max_plaintext_length
);
#ifdef __cplusplus
}
#endif
#endif
/* AXOLOTL_HH_ */
src/axolotl.cpp
0 → 100644
View file @
4abead9e
#include "axolotl/axolotl.hh"
#include "axolotl/session.hh"
#include "axolotl/account.hh"
#include "axolotl/base64.hh"
#include "axolotl/cipher.hh"
#include <new>
#include <cstring>
namespace
{
static
AxolotlAccount
*
to_c
(
axolotl
::
Account
*
account
)
{
return
reinterpret_cast
<
AxolotlAccount
*>
(
account
);
}
static
AxolotlSession
*
to_c
(
axolotl
::
Session
*
account
)
{
return
reinterpret_cast
<
AxolotlSession
*>
(
account
);
}
static
axolotl
::
Account
*
from_c
(
AxolotlAccount
*
account
)
{
return
reinterpret_cast
<
axolotl
::
Account
*>
(
account
);
}
static
axolotl
::
Session
*
from_c
(
AxolotlSession
*
account
)
{
return
reinterpret_cast
<
axolotl
::
Session
*>
(
account
);
}
static
std
::
uint8_t
*
from_c
(
void
*
bytes
)
{
return
reinterpret_cast
<
std
::
uint8_t
*>
(
bytes
);
}
static
std
::
uint8_t
const
*
from_c
(
void
const
*
bytes
)
{
return
reinterpret_cast
<
std
::
uint8_t
const
*>
(
bytes
);
}
static
const
std
::
uint8_t
CIPHER_KDF_INFO
[]
=
"Pickle"
;
static
const
axolotl
::
CipherAesSha256
PICKLE_CIPHER
(
CIPHER_KDF_INFO
,
sizeof
(
CIPHER_KDF_INFO
)
-
1
);
std
::
size_t
enc_output_length
(
size_t
raw_length
)
{
std
::
size_t
length
=
PICKLE_CIPHER
.
encrypt_ciphertext_length
(
raw_length
);
length
+=
PICKLE_CIPHER
.
mac_length
();
return
axolotl
::
encode_base64_length
(
length
);
}
std
::
uint8_t
*
enc_output_pos
(
std
::
uint8_t
*
output
,
size_t
raw_length
)
{
std
::
size_t
length
=
PICKLE_CIPHER
.
encrypt_ciphertext_length
(
raw_length
);
length
+=
PICKLE_CIPHER
.
mac_length
();
return
output
+
axolotl
::
encode_base64_length
(
length
)
-
length
;
}
std
::
size_t
enc_output
(
std
::
uint8_t
const
*
key
,
std
::
size_t
key_length
,
std
::
uint8_t
*
output
,
size_t
raw_length
)
{
std
::
size_t
ciphertext_length
=
PICKLE_CIPHER
.
encrypt_ciphertext_length
(
raw_length
);
std
::
size_t
length
=
ciphertext_length
+
PICKLE_CIPHER
.
mac_length
();
std
::
size_t
base64_length
=
axolotl
::
encode_base64_length
(
length
);
std
::
uint8_t
*
raw_output
=
output
+
base64_length
-
length
;
length
-=
PICKLE_CIPHER
.
mac_length
();
PICKLE_CIPHER
.
encrypt
(
key
,
key_length
,
raw_output
,
raw_length
,
raw_output
,
ciphertext_length
,
raw_output
,
length
);
axolotl
::
encode_base64
(
raw_output
,
length
,
output
);
return
raw_length
;
}
std
::
size_t
enc_input
(
std
::
uint8_t
const
*
key
,
std
::
size_t
key_length
,
std
::
uint8_t
*
input
,
size_t
b64_length
,
axolotl
::
ErrorCode
&
last_error
)
{
std
::
size_t
enc_length
=
axolotl
::
decode_base64_length
(
b64_length
);
if
(
enc_length
==
std
::
size_t
(
-
1
))
{
last_error
=
axolotl
::
ErrorCode
::
INVALID_BASE64
;
return
std
::
size_t
(
-
1
);
}
axolotl
::
decode_base64
(
input
,
b64_length
,
input
);
std
::
size_t
raw_length
=
enc_length
-
PICKLE_CIPHER
.
mac_length
();
std
::
size_t
result
=
PICKLE_CIPHER
.
decrypt
(
key
,
key_length
,
input
,
enc_length
,
input
,
raw_length
,
input
,
raw_length
);
if
(
result
==
std
::
size_t
(
-
1
))
{
last_error
=
axolotl
::
ErrorCode
::
BAD_ACCOUNT_KEY
;
}
return
result
;
}
std
::
size_t
b64_output_length
(
size_t
raw_length
)
{
return
axolotl
::
encode_base64_length
(
raw_length
);
}
std
::
uint8_t
*
b64_output_pos
(
std
::
uint8_t
*
output
,
size_t
raw_length
)
{
return
output
+
axolotl
::
encode_base64_length
(
raw_length
)
-
raw_length
;
}
std
::
size_t
b64_output
(
std
::
uint8_t
*
output
,
size_t
raw_length
)
{
std
::
size_t
base64_length
=
axolotl
::
encode_base64_length
(
raw_length
);
std
::
uint8_t
*
raw_output
=
output
+
base64_length
-
raw_length
;
axolotl
::
encode_base64
(
raw_output
,
raw_length
,
output
);
return
base64_length
;
}
std
::
size_t
b64_input
(
std
::
uint8_t
*
input
,
size_t
b64_length
,
axolotl
::
ErrorCode
&
last_error
)
{
std
::
size_t
raw_length
=
axolotl
::
decode_base64_length
(
b64_length
);
if
(
raw_length
==
std
::
size_t
(
-
1
))
{
last_error
=
axolotl
::
ErrorCode
::
INVALID_BASE64
;
return
std
::
size_t
(
-
1
);
}
axolotl
::
decode_base64
(
input
,
b64_length
,
input
);
return
raw_length
;
}
const
char
*
errors
[
9
]
{
"SUCCESS"
,
"NOT_ENOUGH_RANDOM"
,
"OUTPUT_BUFFER_TOO_SMALL"
,
"BAD_MESSAGE_VERSION"
,
"BAD_MESSAGE_FORMAT"
,
"BAD_MESSAGE_MAC"
,
"BAD_MESSAGE_KEY_ID"
,
"INVALID_BASE64"
,
"BAD_ACCOUNT_KEY"
,
};
}
// namespace
extern
"C"
{
size_t
axolotl_error
()
{
return
std
::
size_t
(
-
1
);
}
const
char
*
axolotl_account_last_error
(
AxolotlSession
*
account
)
{
unsigned
error
=
unsigned
(
from_c
(
account
)
->
last_error
);
if
(
error
<
9
)
{
return
errors
[
error
];
}
else
{
return
"UNKNOWN_ERROR"
;
}
}
const
char
*
axolotl_session_last_error
(
AxolotlSession
*
session
)
{
unsigned
error
=
unsigned
(
from_c
(
session
)
->
last_error
);
if
(
error
<
9
)
{
return
errors
[
error
];
}
else
{
return
"UNKNOWN_ERROR"
;
}
}
size_t
axolotl_account_size
()
{
return
sizeof
(
axolotl
::
Account
);
}
size_t
axolotl_session_size
()
{
return
sizeof
(
axolotl
::
Session
);
}
AxolotlAccount
*
axolotl_account
(
void
*
memory
)
{
return
to_c
(
new
(
memory
)
axolotl
::
Account
());
}
AxolotlSession
*
axolotl_session
(
void
*
memory
)
{
return
to_c
(
new
(
memory
)
axolotl
::
Session
());
}
size_t
axolotl_pickle_account_length
(
AxolotlAccount
*
account
)
{
return
enc_output_length
(
pickle_length
(
*
from_c
(
account
)));
}
size_t
axolotl_pickle_session_length
(
AxolotlSession
*
session
)
{
return
enc_output_length
(
pickle_length
(
*
from_c
(
session
)));
}
size_t
axolotl_pickle_account
(
AxolotlAccount
*
account
,
void
const
*
key
,
size_t
key_length
,
void
*
pickled
,
size_t
pickled_length
)
{
axolotl
::
Account
&
object
=
*
from_c
(
account
);
std
::
size_t
raw_length
=
pickle_length
(
object
);
if
(
pickled_length
<
enc_output_length
(
raw_length
))
{
object
.
last_error
=
axolotl
::
ErrorCode
::
OUTPUT_BUFFER_TOO_SMALL
;
return
size_t
(
-
1
);
}
pickle
(
enc_output_pos
(
from_c
(
pickled
),
raw_length
),
object
);
return
enc_output
(
from_c
(
key
),
key_length
,
from_c
(
pickled
),
raw_length
);
}
size_t
axolotl_pickle_session
(
AxolotlSession
*
session
,
void
const
*
key
,
size_t
key_length
,
void
*
pickled
,
size_t
pickled_length
)
{
axolotl
::
Session
&
object
=
*
from_c
(
session
);
std
::
size_t
raw_length
=
pickle_length
(
object
);
if
(
pickled_length
<
enc_output_length
(
raw_length
))
{
object
.
last_error
=
axolotl
::
ErrorCode
::
OUTPUT_BUFFER_TOO_SMALL
;
return
size_t
(
-
1
);
}
pickle
(
enc_output_pos
(
from_c
(
pickled
),
raw_length
),
object
);
return
enc_output
(
from_c
(
key
),
key_length
,
from_c
(
pickled
),
raw_length
);
}
size_t
axolotl_unpickle_account
(
AxolotlAccount
*
account
,
void
const
*
key
,
size_t
key_length
,
void
*
pickled
,
size_t
pickled_length
)
{
axolotl
::
Account
&
object
=
*
from_c
(
account
);
std
::
uint8_t
*
const
pos
=
from_c
(
pickled
);
std
::
size_t
raw_length
=
enc_input
(
from_c
(
key
),
key_length
,
pos
,
pickled_length
,
object
.
last_error
);
if
(
raw_length
==
std
::
size_t
(
-
1
))
{
return
std
::
size_t
(
-
1
);
}
std
::
uint8_t
*
const
end
=
pos
+
raw_length
;
unpickle
(
pos
,
end
,
object
);
return
pickled_length
;
}
size_t
axolotl_unpickle_session
(
AxolotlSession
*
session
,
void
const
*
key
,
size_t
key_length
,
void
*
pickled
,
size_t
pickled_length
)
{
axolotl
::
Session
&
object
=
*
from_c
(
session
);
std
::
uint8_t
*
const
pos
=
from_c
(
pickled
);
std
::
size_t
raw_length
=
enc_input
(
from_c
(
key
),
key_length
,
pos
,
pickled_length
,
object
.
last_error
);
if
(
raw_length
==
std
::
size_t
(
-
1
))
{
return
std
::
size_t
(
-
1
);
}
std
::
uint8_t
*
const
end
=
pos
+
raw_length
;
unpickle
(
pos
,
end
,
object
);
return
pickled_length
;
}
size_t
axolotl_create_account_random_length
(
AxolotlAccount
*
account
)
{
return
from_c
(
account
)
->
new_account_random_length
();
}
size_t
axolotl_create_account
(
AxolotlAccount
*
account
,
void
const
*
random
,
size_t
random_length
)
{
return
from_c
(
account
)
->
new_account
(
from_c
(
random
),
random_length
);
}
namespace
{
static
const
std
::
size_t
OUTPUT_KEY_LENGTH
=
2
+
10
+
2
+
axolotl
::
encode_base64_length
(
32
)
+
3
;
void
output_key
(
axolotl
::
LocalKey
const
&
key
,
std
::
uint8_t
sep
,
std
::
uint8_t
*
output
)
{
output
[
0
]
=
sep
;
output
[
1
]
=
'['
;
std
::
memset
(
output
+
2
,
' '
,
10
);
uint32_t
value
=
key
.
id
;
uint8_t
*
number
=
output
+
11
;
*
number
=
'0'
+
value
%
10
;
value
/=
10
;
while
(
value
)
{
*
(
--
number
)
=
'0'
+
value
%
10
;
value
/=
10
;
}
output
[
12
]
=
','
;
output
[
13
]
=
'"'
;
axolotl
::
encode_base64
(
key
.
key
.
public_key
,
32
,
output
+
14
);
output
[
OUTPUT_KEY_LENGTH
-
3
]
=
'"'
;
output
[
OUTPUT_KEY_LENGTH
-
2
]
=
']'
;
output
[
OUTPUT_KEY_LENGTH
-
1
]
=
'\n'
;
}
}
// namespace
size_t
axolotl_account_identity_keys_length
(
AxolotlAccount
*
account
)
{
return
OUTPUT_KEY_LENGTH
*
2
+
1
;
}
size_t
axolotl_account_identity_keys
(
AxolotlAccount
*
account
,
void
*
identity_keys
,
size_t
identity_key_length
)
{
std
::
size_t
length
=
OUTPUT_KEY_LENGTH
*
2
+
1
;
if
(
identity_key_length
<
length
)
{
from_c
(
account
)
->
last_error
=
axolotl
::
ErrorCode
::
OUTPUT_BUFFER_TOO_SMALL
;
return
size_t
(
-
1
);
}
std
::
uint8_t
*
output
=
from_c
(
identity_keys
);
output_key
(
from_c
(
account
)
->
identity_key
,
'['
,
output
);
output
+=
OUTPUT_KEY_LENGTH
;
output
+=
OUTPUT_KEY_LENGTH
;
output
[
0
]
=
']'
;
return
length
;
}
size_t
axolotl_account_one_time_keys_length
(
AxolotlAccount
*
account
)
{
size_t
count
=
from_c
(
account
)
->
one_time_keys
.
size
();
return
OUTPUT_KEY_LENGTH
*
(
count
+
1
)
+
1
;
}
size_t
axolotl_account_one_time_keys
(
AxolotlAccount
*
account
,
void
*
identity_keys
,
size_t
identity_key_length
)
{
std
::
size_t
length
=
axolotl_account_one_time_keys_length
(
account
);
if
(
identity_key_length
<
length
)
{
from_c
(
account
)
->
last_error
=
axolotl
::
ErrorCode
::
OUTPUT_BUFFER_TOO_SMALL
;
return
size_t
(
-
1
);
}
std
::
uint8_t
*
output
=
from_c
(
identity_keys
);
output_key
(
from_c
(
account
)
->
last_resort_one_time_key
,
'['
,
output
);
output
+=
OUTPUT_KEY_LENGTH
;
for
(
auto
const
&
key
:
from_c
(
account
)
->
one_time_keys
)
{
output_key
(
key
,
','
,
output
);
output
+=
OUTPUT_KEY_LENGTH
;
}
output
[
0
]
=
']'
;
return
length
;
}
size_t
axolotl_create_outbound_session
(
AxolotlSession
*
session
,
AxolotlAccount
*
account
,
void
const
*
their_identity_key
,
size_t
their_identity_key_length
,
unsigned
their_one_time_key_id
,
void
const
*
their_one_time_key
,
size_t
their_one_time_key_length
,
void
const
*
random
,
size_t
random_length
)
{
if
(
axolotl
::
decode_base64_length
(
their_identity_key_length
)
!=
32
||
axolotl
::
decode_base64_length
(
their_one_time_key_length
)
!=
32
)
{
from_c
(
session
)
->
last_error
=
axolotl
::
ErrorCode
::
INVALID_BASE64
;
return
std
::
size_t
(
-
1
);
}
axolotl
::
Curve25519PublicKey
identity_key
;
axolotl
::
RemoteKey
one_time_key
;
axolotl
::
decode_base64
(
from_c
(
their_identity_key
),
their_identity_key_length
,
identity_key
.
public_key
);
one_time_key
.
id
=
their_one_time_key_id
;
axolotl
::
decode_base64
(
from_c
(
their_one_time_key
),
their_one_time_key_length
,
one_time_key
.
key
.
public_key
);
return
from_c
(
session
)
->
new_outbound_session
(
*
from_c
(
account
),
identity_key
,
one_time_key
,
from_c
(
random
),
random_length
);
}
size_t
axolotl_create_inbound_session
(
AxolotlSession
*
session
,
AxolotlAccount
*
account
,
void
*
one_time_key_message
,
size_t
message_length
)
{
std
::
size_t
raw_length
=
b64_input
(
from_c
(
one_time_key_message
),
message_length
,
from_c
(
session
)
->
last_error
);
if
(
raw_length
==
std
::
size_t
(
-
1
))
{
return
std
::
size_t
(
-
1
);
}
return
from_c
(
session
)
->
new_inbound_session
(
*
from_c
(
account
),
from_c
(
one_time_key_message
),
raw_length
);
}
size_t
axolotl_matches_inbound_session
(
AxolotlSession
*
session
,
void
*
one_time_key_message
,
size_t
message_length
)
{
std
::
size_t
raw_length
=
b64_input
(
from_c
(
one_time_key_message
),
message_length
,
from_c
(
session
)
->
last_error
);
if
(
raw_length
==
std
::
size_t
(
-
1
))
{
return
std
::
size_t
(
-
1
);
}
bool
matches
=
from_c
(
session
)
->
matches_inbound_session
(
from_c
(
one_time_key_message
),
raw_length
);
return
matches
?
1
:
0
;