First version. Almost everything is implemented. Missing library
Right now I'm hadrcoding guix path for the library. Should find out how to use BinaryBuildermaster
commit
e1b004dbc4
|
@ -0,0 +1,59 @@
|
||||||
|
# This file is machine-generated - editing it directly is not advised
|
||||||
|
|
||||||
|
[[Base64]]
|
||||||
|
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
|
||||||
|
|
||||||
|
[[Dates]]
|
||||||
|
deps = ["Printf"]
|
||||||
|
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
|
||||||
|
|
||||||
|
[[Distributed]]
|
||||||
|
deps = ["Random", "Serialization", "Sockets"]
|
||||||
|
uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"
|
||||||
|
|
||||||
|
[[InteractiveUtils]]
|
||||||
|
deps = ["Markdown"]
|
||||||
|
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
|
||||||
|
|
||||||
|
[[JSON]]
|
||||||
|
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
|
||||||
|
git-tree-sha1 = "b34d7cef7b337321e97d22242c3c2b91f476748e"
|
||||||
|
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
|
||||||
|
version = "0.21.0"
|
||||||
|
|
||||||
|
[[Logging]]
|
||||||
|
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
|
||||||
|
|
||||||
|
[[Markdown]]
|
||||||
|
deps = ["Base64"]
|
||||||
|
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
|
||||||
|
|
||||||
|
[[Mmap]]
|
||||||
|
uuid = "a63ad114-7e13-5084-954f-fe012c677804"
|
||||||
|
|
||||||
|
[[Parsers]]
|
||||||
|
deps = ["Dates", "Test"]
|
||||||
|
git-tree-sha1 = "0139ba59ce9bc680e2925aec5b7db79065d60556"
|
||||||
|
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
|
||||||
|
version = "0.3.10"
|
||||||
|
|
||||||
|
[[Printf]]
|
||||||
|
deps = ["Unicode"]
|
||||||
|
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
|
||||||
|
|
||||||
|
[[Random]]
|
||||||
|
deps = ["Serialization"]
|
||||||
|
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
||||||
|
|
||||||
|
[[Serialization]]
|
||||||
|
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
|
||||||
|
|
||||||
|
[[Sockets]]
|
||||||
|
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"
|
||||||
|
|
||||||
|
[[Test]]
|
||||||
|
deps = ["Distributed", "InteractiveUtils", "Logging", "Random"]
|
||||||
|
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
|
||||||
|
|
||||||
|
[[Unicode]]
|
||||||
|
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
|
|
@ -0,0 +1,8 @@
|
||||||
|
name = "Olm"
|
||||||
|
uuid = "35e2252f-68e6-415a-955a-e84ed199fea9"
|
||||||
|
authors = ["nixo <nicolo@nixo.xyz>"]
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
|
||||||
|
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
|
@ -0,0 +1,39 @@
|
||||||
|
module Olm # include("olm.jl")
|
||||||
|
using Random
|
||||||
|
using JSON
|
||||||
|
|
||||||
|
const libolm = "/gnu/store/ks2szjc82r1wqaxdq4vsy6sq9plwd4fs-libolm-3.1.4/lib/libolm.so"
|
||||||
|
const error = ccall((:olm_error, libolm), Csize_t, ())
|
||||||
|
|
||||||
|
struct OlmAccount
|
||||||
|
ptr::Ptr{Cvoid}
|
||||||
|
# Should I store it?
|
||||||
|
# memory::Vector{UInt}
|
||||||
|
end
|
||||||
|
|
||||||
|
struct OlmSession
|
||||||
|
ptr::Ptr{Cvoid}
|
||||||
|
end
|
||||||
|
|
||||||
|
struct OlmUtility
|
||||||
|
ptr::Ptr{Cvoid}
|
||||||
|
end
|
||||||
|
|
||||||
|
include("memory.jl")
|
||||||
|
include("wrapper.jl")
|
||||||
|
|
||||||
|
# # Save/Load account!
|
||||||
|
# a = OlmAccount()
|
||||||
|
# generate_one_time_keys(a, 10)
|
||||||
|
# # deleted after use
|
||||||
|
# enc_key = "pass" |> collect
|
||||||
|
# dec_key = deepcopy(enc_key)
|
||||||
|
# enc_key = dec_key = Char[]
|
||||||
|
# p = pickle!(a, enc_key)
|
||||||
|
# write("account.bin", p)
|
||||||
|
# d = read("account.bin", String) |> collect .|> UInt8
|
||||||
|
# @assert d == p
|
||||||
|
# n = OlmAccount(d, dec_key)
|
||||||
|
# o = OlmAccount(p, dec_key)
|
||||||
|
|
||||||
|
end # Olm
|
|
@ -0,0 +1,13 @@
|
||||||
|
"Allocate an UInt8 array of length size, all zeros"
|
||||||
|
allocate(size) = zeros(UInt8, size)
|
||||||
|
const SRND = Random.RandomDevice()
|
||||||
|
"Allocate a criptographycally secure random UInt8 array of length size"
|
||||||
|
rallocate(size) = rand(SRND, UInt8, size)
|
||||||
|
|
||||||
|
"""Replace all elements of an array with zeros. A custom function accepting
|
||||||
|
"type" may be passed as FUNC argument used instead of ZERO"""
|
||||||
|
function erase!(array::Array{T}; func = zero) where T
|
||||||
|
for i in 1:length(array)
|
||||||
|
array[i] = func(T)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,220 @@
|
||||||
|
"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)
|
||||||
|
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{Char}, passphrase::Vector{Char})
|
||||||
|
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),
|
||||||
|
collect(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{Char}, passphrase::Vector{Char})
|
||||||
|
a = OlmAccount(account())
|
||||||
|
unpickle!(a, pickle, passphrase)
|
||||||
|
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{Char})
|
||||||
|
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
|
||||||
|
throw(last_error(a))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
pickle!(a::OlmAccount) = pickle!(a, Char[])
|
||||||
|
|
||||||
|
# Base.getpass("Account encryption key")
|
||||||
|
|
||||||
|
"The size of the output buffer needed to hold the identity keys"
|
||||||
|
account_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)
|
||||||
|
erase!(message)
|
||||||
|
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.
|
||||||
|
<p>
|
||||||
|
The returned data is a JSON-formatted object with the single property
|
||||||
|
<tt>curve25519</tt>, which is itself an object mapping key id to
|
||||||
|
base64-encoded Curve25519 key. For example:
|
||||||
|
<pre>
|
||||||
|
{
|
||||||
|
curve25519: {
|
||||||
|
"AAAAAA": "wo76WcYtb0Vk/pBOdmduiGJ0wIEjW4IBMbbQn7aSnTo",
|
||||||
|
"AAAAAB": "LRvjo46L1X2vx69sS9QNFD29HWulxrmW11Up5AfAjgU"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
Returns olm_error() on failure.
|
||||||
|
<p>
|
||||||
|
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
|
Loading…
Reference in New Issue