"The size of an account object in bytes" account_size() = ccall((:olm_account_size, libolm), Csize_t, ()) """Initialise an account object using the supplied memory The supplied memory must be at least olm_account_size() bytes""" function account() memory = allocate(account_size()) (ccall((:olm_account, libolm), Ptr{Cvoid}, (Ptr{Cvoid},), memory), memory) end "The number of random bytes needed to create an account." create_account_random_length(a::OlmAccount) = ccall((:olm_create_account_random_length, libolm), Csize_t, (Ptr{Cvoid},), a.ptr) """Creates a new account. Returns olm_error() on failure. If there weren't enough random bytes then olm_account_last_error() will be NOT_ENOUGH_RANDOM""" function create(a::OlmAccount) random_length = create_account_random_length(a) random = allocate(random_length) res = ccall((:olm_create_account, libolm), Csize_t, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), a.ptr, random, random_length) return res != error end function OlmAccount() a = OlmAccount(account()...) create(a) a end """Loads an account from a pickled base64 string. Decrypts the account using the supplied key. Returns olm_error() on failure. If the key doesn't match the one used to encrypt the account then olm_account_last_error() will be "BAD_ACCOUNT_KEY". If the base64 couldn't be decoded then olm_account_last_error() will be "INVALID_BASE64". The input pickled buffer is destroyed""" function unpickle!(a::OlmAccount, pickle::Vector{UInt8}, passphrase::Vector{UInt8}) memlength = pickle_length(a) res = ccall((:olm_unpickle_account, libolm), Csize_t, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t, Ptr{Cvoid}, Csize_t,), a.ptr, passphrase, length(passphrase), pickle, length(pickle)) # If passphrase is empty, pickle is not encrypted, delete it. # Else, deleting the key is fine erase!(length(passphrase) == 0 ? passphrase : pickle, func = rand) if res == error throw(last_error(a)) else a end end """Initialize a pickled account. Note htat passphrase is cleared after use. """ function OlmAccount(pickle::Vector{UInt8}, passphrase::Vector{UInt8}) a = OlmAccount(account()...) unpickle!(a, pickle, passphrase) end OlmAccount(pickle::Vector{UInt8}) = OlmAccount(pickle, Char[]) function OlmAccount(pickle::Vector{UInt8}, b::Base.SecretBuffer) res = OlmAccount(pickle, b.data) Base.shred!(b) res end """A null terminated string describing the most recent error to happen to an account""" last_error(a::OlmAccount) = ccall((:olm_account_last_error, libolm), Cstring, (Ptr{Cvoid},), a.ptr) |> unsafe_string """A null terminated string describing the most recent error to happen to a session""" last_error(s::OlmSession) = ccall((:olm_session_last_error, libolm), Cstring, (Ptr{Cvoid},), s.ptr) |> unsafe_string "Returns the number of bytes needed to store an account" pickle_length(a::OlmAccount) = ccall((:olm_pickle_account_length, libolm), Csize_t, (Ptr{Cvoid},), a.ptr) "Returns the number of bytes needed to store a session" pickle_length(s::OlmSession) = ccall((:olm_pickle_session_length, libolm), Csize_t, (Ptr{Cvoid},), s.ptr) """Stores an account as a base64 string. Encrypts the account using the supplied key. Returns the length of the pickled account on success. Returns olm_error() on failure. If the pickle output buffer is smaller than olm_pickle_account_length() then olm_account_last_error() will be "OUTPUT_BUFFER_TOO_SMALL".""" function pickle!(a::OlmAccount, passphrase::Vector{UInt8}) memlength = pickle_length(a) memory = allocate(memlength) res = ccall((:olm_pickle_account, libolm), Csize_t, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t, Ptr{Cvoid}, Csize_t,), a.ptr, passphrase, length(passphrase), memory, memlength) # zero(Char) does not extists, but rand does erase!(passphrase, func = rand) # Check results if res == memlength memory else # TODO: Custom exceptions throw(last_error(a)) end end pickle!(a::OlmAccount) = pickle!(a, UInt8[]) function pickle!(a::OlmAccount, s::Base.SecretBuffer) res = pickle!(a, s.data) Base.shred!(s) res end # Base.getpass("Account encryption key") "The size of the output buffer needed to hold the identity keys" identity_keys_length(a::OlmAccount) = ccall((:olm_account_identity_keys_length, libolm), Csize_t, (Ptr{Cvoid},), a.ptr) "The largest number of one time keys this account can store." max_number_of_one_time_keys() = ccall((:olm_account_max_number_of_one_time_keys, libolm), Csize_t, ()) """The number of random bytes needed to generate a given number of new one time keys.""" function generate_one_time_keys_random_length(a::OlmAccount, count::Integer) ccall((:olm_account_generate_one_time_keys_random_length, libolm), Csize_t, (Ptr{Cvoid}, Csize_t), a.ptr, count) end """Marks the current set of one time keys as being published.""" mark_keys_as_published(a::OlmAccount) = ccall((:olm_account_mark_keys_as_published, libolm), Csize_t, (Ptr{Cvoid},), a.ptr) "The length of an ed25519 signature encoded as base64." signature_length(a::OlmAccount) = ccall((:olm_account_signature_length, libolm), Csize_t, (Ptr{Cvoid},), a.ptr) "The size of the output buffer needed to hold the one time keys" one_time_keys_length(a::OlmAccount) = ccall((:olm_account_one_time_keys_length, libolm), Csize_t, (Ptr{Cvoid},), a.ptr) """Writes the public parts of the identity keys for the account into the identity_keys output buffer. Returns olm_error() on failure. If the identity_keys buffer was too small then olm_account_last_error() will be OUTPUT_BUFFER_TOO_SMALL.""" function identity_keys(a::OlmAccount) identity_key_length = identity_keys_length(a) identity_keys = allocate(identity_key_length) res = ccall((:olm_account_identity_keys, libolm), Csize_t, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), a.ptr, identity_keys, identity_key_length) identity_keys |> String end """Signs a message with the ed25519 key for this account. Returns olm_error() on failure. If the signature buffer was too small then olm_account_last_error() will be OUTPUT_BUFFER_TOO_SMALL""" function sign!(a::OlmAccount, message) siglength = signature_length(a) output = allocate(siglength) ccall((:olm_account_sign, libolm), Csize_t, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t, Ptr{Cvoid}, Csize_t), a.ptr, message, length(message), output, siglength) # zero(Char) does not extists, but rand does erase!(message, func = rand) String(deepcopy(output)) end """Generates a number of new one time keys. If the total number of keys stored by this account exceeds max_number_of_one_time_keys() then the old keys are discarded. Returns olm_error() on error. If the number of random bytes is too small then olm_account_last_error() will be NOT_ENOUGH_RANDOM.""" function generate_one_time_keys(a::OlmAccount, count::Integer) 0 < count <= max_number_of_one_time_keys() || throw("Error: invalid number of keys") len = generate_one_time_keys_random_length(a, count) random = rallocate(len) res = ccall((:olm_account_generate_one_time_keys, libolm), Csize_t, (Ptr{Cvoid}, Csize_t, Ptr{Cvoid}, Csize_t), a.ptr, count, random, len) erase!(random) Int(res) end """Writes the public parts of the unpublished one time keys for the account into the one_time_keys output buffer.

The returned data is a JSON-formatted object with the single property curve25519, which is itself an object mapping key id to base64-encoded Curve25519 key. For example:

{
  curve25519: {
     "AAAAAA": "wo76WcYtb0Vk/pBOdmduiGJ0wIEjW4IBMbbQn7aSnTo",
     "AAAAAB": "LRvjo46L1X2vx69sS9QNFD29HWulxrmW11Up5AfAjgU"
  }
}
Returns olm_error() on failure.

If the one_time_keys buffer was too small then olm_account_last_error() will be "OUTPUT_BUFFER_TOO_SMALL".""" function one_time_keys(a::OlmAccount) one_time_keys_len = one_time_keys_length(a) one_time_keys = allocate(one_time_keys_len) res = ccall((:olm_account_one_time_keys, libolm), Csize_t, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), a.ptr, one_time_keys, one_time_keys_len) if res == error throw(last_error(a)) end JSON.parse(String(deepcopy(one_time_keys))) end