Compare commits

..

2 commits

Author SHA1 Message Date
Richard van der Hoff
06a1b66ea9 Update megolm.md
69+64 != 129
2022-11-30 13:06:04 +00:00
Richard van der Hoff
2ac6177f9c Simplify the ratchet 2022-11-30 12:26:48 +00:00
43 changed files with 430 additions and 542 deletions

View file

@ -1,33 +1,3 @@
Changes in `3.2.16 <https://gitlab.matrix.org/matrix-org/olm/tags/3.2.16>`_
===========================================================================
This release includes the following changes since 3.2.15:
* Fix and modernize the Python packaging (thanks to Alfred Wingate)
Changes in `3.2.15 <https://gitlab.matrix.org/matrix-org/olm/tags/3.2.15>`_
===========================================================================
This release includes the following changes since 3.2.14:
* Improvements to Python packaging
* No longer depend on ``future`` since Python 2 is no longer supported.
* Improve compatibility with tox 4.
* Add support for making standalone sdist.
* Improvements to Nix flake (Thanks to Jon Ringer)
* Improve structure.
* Enable Darwin builds.
* Typescript type fix.
Changes in `3.2.14 <https://gitlab.matrix.org/matrix-org/olm/tags/3.2.14>`_
===========================================================================
This release includes the following changes since 3.2.13:
* TypeScript type improvements.
* Improvements to Python packaging
* Documentation improvements.
Changes in `3.2.13 <https://gitlab.matrix.org/matrix-org/olm/tags/3.2.13>`_ Changes in `3.2.13 <https://gitlab.matrix.org/matrix-org/olm/tags/3.2.13>`_
=========================================================================== ===========================================================================

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.4) cmake_minimum_required(VERSION 3.4)
project(olm VERSION 3.2.16 LANGUAGES CXX C) project(olm VERSION 3.2.13 LANGUAGES CXX C)
option(OLM_TESTS "Build tests" ON) option(OLM_TESTS "Build tests" ON)
option(BUILD_SHARED_LIBS "Build as a shared library" ON) option(BUILD_SHARED_LIBS "Build as a shared library" ON)

View file

@ -8,6 +8,7 @@ RELEASE_OPTIMIZE_FLAGS ?= -O3
DEBUG_OPTIMIZE_FLAGS ?= -g -O0 -U_FORTIFY_SOURCE DEBUG_OPTIMIZE_FLAGS ?= -g -O0 -U_FORTIFY_SOURCE
JS_OPTIMIZE_FLAGS ?= -O3 JS_OPTIMIZE_FLAGS ?= -O3
FUZZER_OPTIMIZE_FLAGS ?= -O3 FUZZER_OPTIMIZE_FLAGS ?= -O3
CC = gcc
EMCC = emcc EMCC = emcc
EMAR = emar EMAR = emar
AR = ar AR = ar
@ -30,7 +31,7 @@ JS_ASMJS_TARGET := javascript/olm_legacy.js
WASM_TARGET := $(BUILD_DIR)/wasm/libolm.a WASM_TARGET := $(BUILD_DIR)/wasm/libolm.a
JS_EXPORTED_FUNCTIONS := javascript/exported_functions.json JS_EXPORTED_FUNCTIONS := javascript/exported_functions.json
JS_EXPORTED_RUNTIME_METHODS := [ALLOC_STACK,writeAsciiToMemory,intArrayFromString,UTF8ToString,stringToUTF8] JS_EXPORTED_RUNTIME_METHODS := [ALLOC_STACK,writeAsciiToMemory,intArrayFromString]
JS_EXTERNS := javascript/externs.js JS_EXTERNS := javascript/externs.js
PUBLIC_HEADERS := include/olm/olm.h include/olm/outbound_group_session.h include/olm/inbound_group_session.h include/olm/pk.h include/olm/sas.h include/olm/error.h include/olm/olm_export.h PUBLIC_HEADERS := include/olm/olm.h include/olm/outbound_group_session.h include/olm/inbound_group_session.h include/olm/pk.h include/olm/sas.h include/olm/error.h include/olm/olm_export.h
@ -93,7 +94,7 @@ LDFLAGS += -Wall -Werror
CFLAGS_NATIVE = -fPIC CFLAGS_NATIVE = -fPIC
CXXFLAGS_NATIVE = -fPIC CXXFLAGS_NATIVE = -fPIC
EMCCFLAGS = --closure 1 --memory-init-file 0 -s NO_FILESYSTEM=1 -s INVOKE_RUN=0 -s MODULARIZE=1 -Wno-error=closure EMCCFLAGS = --closure 1 --memory-init-file 0 -s NO_FILESYSTEM=1 -s INVOKE_RUN=0 -s MODULARIZE=1
# Olm generally doesn't need a lot of memory to encrypt / decrypt its usual # Olm generally doesn't need a lot of memory to encrypt / decrypt its usual
# payloads (ie. Matrix messages), but we do need about 128K of heap to encrypt # payloads (ie. Matrix messages), but we do need about 128K of heap to encrypt
@ -105,7 +106,7 @@ EMCCFLAGS = --closure 1 --memory-init-file 0 -s NO_FILESYSTEM=1 -s INVOKE_RUN=0
# we don't use this for the legacy build.) # we don't use this for the legacy build.)
EMCCFLAGS_WASM += -s TOTAL_STACK=65536 -s TOTAL_MEMORY=262144 -s ALLOW_MEMORY_GROWTH EMCCFLAGS_WASM += -s TOTAL_STACK=65536 -s TOTAL_MEMORY=262144 -s ALLOW_MEMORY_GROWTH
EMCCFLAGS_ASMJS += -s WASM=0 EMCCFLAGS_ASMJS += -s WASM=0 -Wno-error=closure
EMCC.c = $(EMCC) $(CFLAGS) $(CPPFLAGS) -c -DNDEBUG -DOLM_STATIC_DEFINE=1 EMCC.c = $(EMCC) $(CFLAGS) $(CPPFLAGS) -c -DNDEBUG -DOLM_STATIC_DEFINE=1
EMCC.cc = $(EMCC) $(CXXFLAGS) $(CPPFLAGS) -c -DNDEBUG -DOLM_STATIC_DEFINE=1 EMCC.cc = $(EMCC) $(CXXFLAGS) $(CPPFLAGS) -c -DNDEBUG -DOLM_STATIC_DEFINE=1

View file

@ -3,7 +3,7 @@ Pod::Spec.new do |s|
# The libolm version # The libolm version
MAJOR = 3 MAJOR = 3
MINOR = 2 MINOR = 2
PATCH = 16 PATCH = 13
s.name = "OLMKit" s.name = "OLMKit"
s.version = "#{MAJOR}.#{MINOR}.#{PATCH}" s.version = "#{MAJOR}.#{MINOR}.#{PATCH}"

View file

@ -2,7 +2,7 @@
import PackageDescription import PackageDescription
let major = 3, minor = 2, patch = 16 let major = 3, minor = 2, patch = 13
let package = Package( let package = Package(
name: "Olm", name: "Olm",

View file

@ -52,16 +52,13 @@ You can use pre-built npm packages, available at
#### Python #### Python
A Python source package and pre-built packages for certain architectures from Pre-built packages for Python are available for certain architectures at
<https://pypi.org/project/python-olm/>. If a pre-built package is not <https://gitlab.matrix.org/matrix-org/olm/-/packages?type=PyPI>. They can be
available for your architecture, you will need: installed by running
- cmake (recommended) or GNU make ```bash
- a C/C++ compiler pip install python-olm --extra-index-url https://gitlab.matrix.org/api/v4/projects/27/packages/pypi/simple
```
to build the source package.
You can then run `pip install python-olm`.
Currently, we try to provide packages for all supported versions of Python on Currently, we try to provide packages for all supported versions of Python on
x86-64, i686, and aarch64, but we cannot guarantee that packages for all x86-64, i686, and aarch64, but we cannot guarantee that packages for all
@ -206,7 +203,7 @@ endorsed by the Matrix.org Foundation C.I.C.
## Release process ## Release process
First: bump version numbers in ``common.mk``, ``CMakeLists.txt``, First: bump version numbers in ``common.mk``, ``CMakeLists.txt``,
``javascript/package.json``, ``python/pyproject.toml``, ``OLMKit.podspec``, ``javascript/package.json``, ``python/olm/__version__.py``, ``OLMKit.podspec``,
``Package.swift``, and ``android/gradle.properties``. ``Package.swift``, and ``android/gradle.properties``.
Also, ensure the changelog is up to date, and that everything is committed to Also, ensure the changelog is up to date, and that everything is committed to

View file

@ -11,8 +11,8 @@
SET(CMAKE_SYSTEM_NAME Windows) SET(CMAKE_SYSTEM_NAME Windows)
# which compilers to use for C and C++ # which compilers to use for C and C++
SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc-posix) SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++-posix) SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
SET(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) SET(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
# here is the target environment located # here is the target environment located

View file

@ -26,7 +26,7 @@ org.gradle.configureondemand=false
# Ref: https://github.com/vanniktech/gradle-maven-publish-plugin # Ref: https://github.com/vanniktech/gradle-maven-publish-plugin
GROUP=org.matrix.android GROUP=org.matrix.android
POM_ARTIFACT_ID=olm POM_ARTIFACT_ID=olm
VERSION_NAME=3.2.16 VERSION_NAME=3.2.13
POM_PACKAGING=aar POM_PACKAGING=aar

View file

@ -1,4 +1,4 @@
MAJOR := 3 MAJOR := 3
MINOR := 2 MINOR := 2
PATCH := 16 PATCH := 13

View file

@ -28,56 +28,18 @@ channels. Provided that peer-to-peer channel provides authenticity of the
messages to the participants and deniability of the messages to third parties, messages to the participants and deniability of the messages to third parties,
the Megolm session will inherit those properties. the Megolm session will inherit those properties.
## The Megolm ratchet algorithm ## The Megolm V2 ratchet algorithm
The Megolm ratchet $`R_i`$ consists of four parts, $`R_{i,j}`$ for The Megolm V2 ratchet $`R_i`$ is based on a single key whose length depends
$`j \in {0,1,2,3}`$. The length of each part depends on the hash function on the hash function in use (256 bits for this version of Megolm).
in use (256 bits for this version of Megolm).
The ratchet is initialised with cryptographically-secure random data, and The key is initialised with cryptographically-secure random data, and
advanced as follows: after each use is advanced by setting $`R_{i+1} = H(R_i)`$, where $`H`$ is
a hash function.
```math The ratchet value, $`R_{i}`$, is hashed to generate the keys used
\begin{aligned} to encrypt each message. This scheme allows a client
R_{i,0} &= to decrypt chat history onwards from the earliest value of the ratchet
\begin{cases}
H_0\left(R_{2^{24}(n-1),0}\right) &\text{if }\exists n | i = 2^{24}n\\
R_{i-1,0} &\text{otherwise}
\end{cases}\\
R_{i,1} &=
\begin{cases}
H_1\left(R_{2^{24}(n-1),0}\right) &\text{if }\exists n | i = 2^{24}n\\
H_1\left(R_{2^{16}(m-1),1}\right) &\text{if }\exists m | i = 2^{16}m\\
R_{i-1,1} &\text{otherwise}
\end{cases}\\
R_{i,2} &=
\begin{cases}
H_2\left(R_{2^{24}(n-1),0}\right) &\text{if }\exists n | i = 2^{24}n\\
H_2\left(R_{2^{16}(m-1),1}\right) &\text{if }\exists m | i = 2^{16}m\\
H_2\left(R_{2^8(p-1),2}\right) &\text{if }\exists p | i = 2^8p\\
R_{i-1,2} &\text{otherwise}
\end{cases}\\
R_{i,3} &=
\begin{cases}
H_3\left(R_{2^{24}(n-1),0}\right) &\text{if }\exists n | i = 2^{24}n\\
H_3\left(R_{2^{16}(m-1),1}\right) &\text{if }\exists m | i = 2^{16}m\\
H_3\left(R_{2^8(p-1),2}\right) &\text{if }\exists p | i = 2^8p\\
H_3\left(R_{i-1,3}\right) &\text{otherwise}
\end{cases}
\end{aligned}
```
where $`H_0`$, $`H_1`$, $`H_2`$, and $`H_3`$ are different hash
functions. In summary: every $`2^8`$ iterations, $`R_{i,3}`$ is
reseeded from $`R_{i,2}`$. Every $`2^{16}`$ iterations, $`R_{i,2}`$
and $`R_{i,3}`$ are reseeded from $`R_{i,1}`$. Every $`2^{24}`$
iterations, $`R_{i,1}`$, $`R_{i,2}`$ and $`R_{i,3}`$ are reseeded
from $`R_{i,0}`$.
The complete ratchet value, $`R_{i}`$, is hashed to generate the keys used
to encrypt each message. This scheme allows the ratchet to be advanced an
arbitrary amount forwards while needing at most 1020 hash computations. A
client can decrypt chat history onwards from the earliest value of the ratchet
it is aware of, but cannot decrypt history from before that point without it is aware of, but cannot decrypt history from before that point without
reversing the hash function. reversing the hash function.
@ -85,7 +47,6 @@ This allows a participant to share its ability to decrypt chat history with
another from a point in the conversation onwards by giving a copy of the another from a point in the conversation onwards by giving a copy of the
ratchet at that point in the conversation. ratchet at that point in the conversation.
## The Megolm protocol ## The Megolm protocol
### Session setup ### Session setup
@ -95,8 +56,7 @@ session consists of three parts:
* a 32 bit counter, $`i`$. * a 32 bit counter, $`i`$.
* an [Ed25519][] keypair, $`K`$. * an [Ed25519][] keypair, $`K`$.
* a ratchet, $`R_i`$, which consists of four 256-bit values, * a ratchet, $`R_i`$, consisting of a single 256-bit value.
$`R_{i,j}`$ for $`j \in {0,1,2,3}`$.
The counter $`i`$ is initialised to $`0`$. A new Ed25519 keypair is The counter $`i`$ is initialised to $`0`$. A new Ed25519 keypair is
generated for $`K`$. The ratchet is simply initialised with 1024 bits of generated for $`K`$. The ratchet is simply initialised with 1024 bits of
@ -157,18 +117,16 @@ received the session data.
### Advancing the ratchet ### Advancing the ratchet
After each message is encrypted, the ratchet is advanced. This is done as After each message is encrypted, the ratchet is advanced. This is done as
described in [The Megolm ratchet algorithm](#the-megolm-ratchet-algorithm), using the following definitions: described in [The Megolm V2 ratchet algorithm](#the-megolm-v2-ratchet-algorithm),
using the following definition for $`H`$:
```math ```math
\begin{aligned} \begin{aligned}
H_0(A) &\equiv \operatorname{HMAC}(A,\text{``\char`\\x00"}) \\ H(A) &\equiv \operatorname{HMAC}(A,\text{``\char`\\x00"}) \\
H_1(A) &\equiv \operatorname{HMAC}(A,\text{``\char`\\x01"}) \\
H_2(A) &\equiv \operatorname{HMAC}(A,\text{``\char`\\x02"}) \\
H_3(A) &\equiv \operatorname{HMAC}(A,\text{``\char`\\x03"}) \\
\end{aligned} \end{aligned}
``` ```
where $`\operatorname{HMAC}(A, T)`$ is the HMAC-SHA-256 of ``T``, using ``A`` as the where $`\operatorname{HMAC}(A, T)`$ is the HMAC-SHA-256 of $`T`$, using $`A`$ as the
key. key.
For outbound sessions, the updated ratchet and counter are stored in the For outbound sessions, the updated ratchet and counter are stored in the
@ -191,16 +149,16 @@ session.
The session sharing format is as follows: The session sharing format is as follows:
``` ```
+---+----+--------+--------+--------+--------+------+-----------+ +---+----+------+------+-----------+
| V | i | R(i,0) | R(i,1) | R(i,2) | R(i,3) | Kpub | Signature | | V | i | R(i) | Kpub | Signature |
+---+----+--------+--------+--------+--------+------+-----------+ +---+----+------+------+-----------+
0 1 5 37 69 101 133 165 229 bytes 0 1 5 37 69 133 bytes
``` ```
The version byte, ``V``, is ``"\x02"``. The version byte, ``V``, is ``"\x04"``.
This is followed by the ratchet index, $`i`$, which is encoded as a This is followed by the ratchet index, $`i`$, which is encoded as a
big-endian 32-bit integer; the ratchet values $`R_{i,j}`$; and the public big-endian 32-bit integer; the ratchet value $`R_{i}`$; and the public
part of the Ed25519 keypair $`K`$. part of the Ed25519 keypair $`K`$.
The data is then signed using the Ed25519 keypair, and the 64-byte signature is The data is then signed using the Ed25519 keypair, and the 64-byte signature is
@ -221,16 +179,16 @@ format](#session-sharing-format) except for dropping the signature.
The Megolm session export format is thus as follows: The Megolm session export format is thus as follows:
``` ```
+---+----+--------+--------+--------+--------+------+ +---+----+------+------+
| V | i | R(i,0) | R(i,1) | R(i,2) | R(i,3) | Kpub | | V | i | R(i) | Kpub |
+---+----+--------+--------+--------+--------+------+ +---+----+------+------+
0 1 5 37 69 101 133 165 bytes 0 1 5 37 69 bytes
``` ```
The version byte, ``V``, is ``"\x01"``. The version byte, ``V``, is ``"\x03"``.
This is followed by the ratchet index, $`i`$, which is encoded as a This is followed by the ratchet index, $`i`$, which is encoded as a
big-endian 32-bit integer; the ratchet values $`R_{i,j}`$; and the public big-endian 32-bit integer; the ratchet value $`R_{i}`$; and the public
part of the Ed25519 keypair $`K`$. part of the Ed25519 keypair $`K`$.
### Message format ### Message format

142
flake.nix
View file

@ -11,30 +11,126 @@
}; };
outputs = { self, nixpkgs, flake-utils, npmlock2nix }: outputs = { self, nixpkgs, flake-utils, npmlock2nix }:
let (
localOverlay = import ./nix/overlay.nix;
pkgsForSystem = system: import nixpkgs {
inherit system;
overlays = [
(final: prev: {
npmlock2nix = final.callPackage npmlock2nix {};
node_modules = final.npmlock2nix.node_modules { src = ./javascript; };
})
localOverlay
];
};
in (
# some systems cause issues, e.g. i686-linux is unsupported by gradle, # some systems cause issues, e.g. i686-linux is unsupported by gradle,
# which causes "nix flake check" to fail. Investigate more later, but for # which causes "nix flake check" to fail. Investigate more later, but for
# now, we will just allow x86_64-linux # now, we will just allow x86_64-linux
flake-utils.lib.eachSystem [ "x86_64-linux" "x86_64-darwin" "aarch64-darwin" ] (system: rec { flake-utils.lib.eachSystem [ "x86_64-linux" ] (system:
legacyPackages = pkgsForSystem system; let
checks = { pkgs = import nixpkgs {
inherit (legacyPackages) olm-gcc-cmake olm-clang-cmake olm-gcc-make; inherit system;
}; overlays = [
packages = { (final: prev: {
javascript = legacyPackages.olm-javascript; npmlock2nix = final.callPackage npmlock2nix {};
}; })
} ];
)); };
node_modules = pkgs.npmlock2nix.node_modules { src = ./javascript; };
in
rec {
checks.gcc-cmake = pkgs.gccStdenv.mkDerivation {
name = "olm";
buildInputs = [ pkgs.cmake ];
src = ./.;
buildPhase = ''
cmake . -Bbuild
cmake --build build
'';
doCheck = true;
checkPhase = ''
cd build/tests
ctest .
cd ../..
'';
};
checks.clang-cmake = pkgs.clangStdenv.mkDerivation {
name = "olm";
buildInputs = [ pkgs.cmake ];
src = ./.;
buildPhase = ''
cmake . -Bbuild
cmake --build build
'';
doCheck = true;
checkPhase = ''
cd build/tests
ctest .
cd ../..
'';
};
checks.gcc-make = pkgs.gccStdenv.mkDerivation {
name = "olm";
src = ./.;
buildPhase = ''
make
'';
doCheck = true;
checkPhase = ''
make test
'';
installPhase = ''
make install PREFIX=$out
'';
};
packages.javascript = pkgs.buildEmscriptenPackage {
pname = "olm";
inherit (builtins.fromJSON (builtins.readFile ./javascript/package.json)) version;
buildInputs = with pkgs; [ gnumake python3 nodejs ];
src = ./.;
postPatch = ''
patchShebangs .
'';
configurePhase = "";
buildPhase = ''
export EM_CACHE=$TMPDIR
make javascript/exported_functions.json
make js
'';
output = [ "out" ];
installPhase = ''
mkdir -p $out/javascript
cd javascript
echo sha256: > checksums.txt
sha256sum olm.js olm_legacy.js olm.wasm >> checksums.txt
echo sha512: >> checksums.txt
sha512sum olm.js olm_legacy.js olm.wasm >> checksums.txt
cp package.json olm.js olm.wasm olm_legacy.js index.d.ts README.md checksums.txt $out/javascript
cd ..
'';
checkPhase = ''
cd javascript
export HOME=$TMPDIR
ln -s ${node_modules}/node_modules ./node_modules
npm test
cd ..
'';
};
packages.default = packages.javascript;
}
)
);
} }

View file

@ -99,9 +99,9 @@ public:
return *this; return *this;
} }
T * this_pos = _data; T * this_pos = _data;
const T * other_pos = other._data; T * const other_pos = other._data;
while (other_pos != other._end) { while (other_pos != other._end) {
*this_pos = *other_pos; *this_pos = *other;
++this_pos; ++this_pos;
++other_pos; ++other_pos;
} }

View file

@ -9,15 +9,15 @@
# ifndef OLM_EXPORT # ifndef OLM_EXPORT
# ifdef olm_EXPORTS # ifdef olm_EXPORTS
/* We are building this library */ /* We are building this library */
# define OLM_EXPORT # define OLM_EXPORT __attribute__((visibility("default")))
# else # else
/* We are using this library */ /* We are using this library */
# define OLM_EXPORT # define OLM_EXPORT __attribute__((visibility("default")))
# endif # endif
# endif # endif
# ifndef OLM_NO_EXPORT # ifndef OLM_NO_EXPORT
# define OLM_NO_EXPORT # define OLM_NO_EXPORT __attribute__((visibility("hidden")))
# endif # endif
#endif #endif

16
javascript/index.d.ts vendored
View file

@ -51,10 +51,7 @@ declare class Session {
has_received_message(): boolean; has_received_message(): boolean;
matches_inbound(one_time_key_message: string): boolean; matches_inbound(one_time_key_message: string): boolean;
matches_inbound_from(identity_key: string, one_time_key_message: string): boolean; matches_inbound_from(identity_key: string, one_time_key_message: string): boolean;
encrypt(plaintext: string): { encrypt(plaintext: string): object;
type: 0 | 1; // 0: PreKey, 1: Message
body: string;
};
decrypt(message_type: number, message: string): string; decrypt(message_type: number, message: string): string;
describe(): string; describe(): string;
} }
@ -73,10 +70,7 @@ declare class InboundGroupSession {
unpickle(key: string | Uint8Array, pickle: string): void; unpickle(key: string | Uint8Array, pickle: string): void;
create(session_key: string): string; create(session_key: string): string;
import_session(session_key: string): string; import_session(session_key: string): string;
decrypt(message: string): { decrypt(message: string): object;
message_index: number;
plaintext: string;
};
session_id(): string; session_id(): string;
first_known_index(): number; first_known_index(): number;
export_session(message_index: number): string; export_session(message_index: number): string;
@ -98,11 +92,7 @@ declare class PkEncryption {
constructor(); constructor();
free(): void; free(): void;
set_recipient_key(key: string): void; set_recipient_key(key: string): void;
encrypt(plaintext: string): { encrypt(plaintext: string): object;
ciphertext: string;
mac: string;
ephemeral: string;
};
} }
declare class PkDecryption { declare class PkDecryption {

View file

@ -14,6 +14,7 @@ if (typeof(window) !== 'undefined') {
var bytes = nodeCrypto['randomBytes'](buf.length); var bytes = nodeCrypto['randomBytes'](buf.length);
buf.set(bytes); buf.set(bytes);
}; };
process = global["process"];
} else { } else {
throw new Error("Cannot find global to attach library to"); throw new Error("Cannot find global to attach library to");
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "@matrix-org/olm", "name": "@matrix-org/olm",
"version": "3.2.16", "version": "3.2.13",
"description": "An implementation of the Double Ratchet cryptographic ratchet", "description": "An implementation of the Double Ratchet cryptographic ratchet",
"main": "olm.js", "main": "olm.js",
"files": [ "files": [
@ -31,5 +31,8 @@
"homepage": "https://gitlab.matrix.org/matrix-org/olm", "homepage": "https://gitlab.matrix.org/matrix-org/olm",
"devDependencies": { "devDependencies": {
"jasmine": "^3.0.0" "jasmine": "^3.0.0"
},
"publishConfig": {
"@matrix-org:registry":"https://gitlab.matrix.org/api/v4/projects/27/packages/npm/"
} }
} }

View file

@ -1,123 +1,123 @@
/********************************************************************* /*********************************************************************
* Filename: aes.h * Filename: aes.h
* Author: Brad Conte (brad AT bradconte.com) * Author: Brad Conte (brad AT bradconte.com)
* Copyright: * Copyright:
* Disclaimer: This code is presented "as is" without any guarantees. * Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding AES implementation. * Details: Defines the API for the corresponding AES implementation.
*********************************************************************/ *********************************************************************/
#ifndef AES_H #ifndef AES_H
#define AES_H #define AES_H
/*************************** HEADER FILES ***************************/ /*************************** HEADER FILES ***************************/
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
/****************************** MACROS ******************************/ /****************************** MACROS ******************************/
#define AES_BLOCK_SIZE 16 // AES operates on 16 bytes at a time #define AES_BLOCK_SIZE 16 // AES operates on 16 bytes at a time
/**************************** DATA TYPES ****************************/ /**************************** DATA TYPES ****************************/
typedef uint8_t BYTE; // 8-bit byte typedef unsigned char BYTE; // 8-bit byte
typedef uint32_t WORD; // 32-bit word, change to "long" for 16-bit machines typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
/*********************** FUNCTION DECLARATIONS **********************/ /*********************** FUNCTION DECLARATIONS **********************/
/////////////////// ///////////////////
// AES // AES
/////////////////// ///////////////////
// Key setup must be done before any AES en/de-cryption functions can be used. // Key setup must be done before any AES en/de-cryption functions can be used.
void aes_key_setup(const BYTE key[], // The key, must be 128, 192, or 256 bits void aes_key_setup(const BYTE key[], // The key, must be 128, 192, or 256 bits
WORD w[], // Output key schedule to be used later WORD w[], // Output key schedule to be used later
int keysize); // Bit length of the key, 128, 192, or 256 int keysize); // Bit length of the key, 128, 192, or 256
void aes_encrypt(const BYTE in[], // 16 bytes of plaintext void aes_encrypt(const BYTE in[], // 16 bytes of plaintext
BYTE out[], // 16 bytes of ciphertext BYTE out[], // 16 bytes of ciphertext
const WORD key[], // From the key setup const WORD key[], // From the key setup
int keysize); // Bit length of the key, 128, 192, or 256 int keysize); // Bit length of the key, 128, 192, or 256
void aes_decrypt(const BYTE in[], // 16 bytes of ciphertext void aes_decrypt(const BYTE in[], // 16 bytes of ciphertext
BYTE out[], // 16 bytes of plaintext BYTE out[], // 16 bytes of plaintext
const WORD key[], // From the key setup const WORD key[], // From the key setup
int keysize); // Bit length of the key, 128, 192, or 256 int keysize); // Bit length of the key, 128, 192, or 256
/////////////////// ///////////////////
// AES - CBC // AES - CBC
/////////////////// ///////////////////
int aes_encrypt_cbc(const BYTE in[], // Plaintext int aes_encrypt_cbc(const BYTE in[], // Plaintext
size_t in_len, // Must be a multiple of AES_BLOCK_SIZE size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
BYTE out[], // Ciphertext, same length as plaintext BYTE out[], // Ciphertext, same length as plaintext
const WORD key[], // From the key setup const WORD key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256 int keysize, // Bit length of the key, 128, 192, or 256
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
// Only output the CBC-MAC of the input. // Only output the CBC-MAC of the input.
int aes_encrypt_cbc_mac(const BYTE in[], // plaintext int aes_encrypt_cbc_mac(const BYTE in[], // plaintext
size_t in_len, // Must be a multiple of AES_BLOCK_SIZE size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
BYTE out[], // Output MAC BYTE out[], // Output MAC
const WORD key[], // From the key setup const WORD key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256 int keysize, // Bit length of the key, 128, 192, or 256
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
/////////////////// ///////////////////
// AES - CTR // AES - CTR
/////////////////// ///////////////////
void increment_iv(BYTE iv[], // Must be a multiple of AES_BLOCK_SIZE void increment_iv(BYTE iv[], // Must be a multiple of AES_BLOCK_SIZE
int counter_size); // Bytes of the IV used for counting (low end) int counter_size); // Bytes of the IV used for counting (low end)
void aes_encrypt_ctr(const BYTE in[], // Plaintext void aes_encrypt_ctr(const BYTE in[], // Plaintext
size_t in_len, // Any byte length size_t in_len, // Any byte length
BYTE out[], // Ciphertext, same length as plaintext BYTE out[], // Ciphertext, same length as plaintext
const WORD key[], // From the key setup const WORD key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256 int keysize, // Bit length of the key, 128, 192, or 256
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
void aes_decrypt_ctr(const BYTE in[], // Ciphertext void aes_decrypt_ctr(const BYTE in[], // Ciphertext
size_t in_len, // Any byte length size_t in_len, // Any byte length
BYTE out[], // Plaintext, same length as ciphertext BYTE out[], // Plaintext, same length as ciphertext
const WORD key[], // From the key setup const WORD key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256 int keysize, // Bit length of the key, 128, 192, or 256
const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long const BYTE iv[]); // IV, must be AES_BLOCK_SIZE bytes long
/////////////////// ///////////////////
// AES - CCM // AES - CCM
/////////////////// ///////////////////
// Returns True if the input parameters do not violate any constraint. // Returns True if the input parameters do not violate any constraint.
int aes_encrypt_ccm(const BYTE plaintext[], // IN - Plaintext. int aes_encrypt_ccm(const BYTE plaintext[], // IN - Plaintext.
WORD plaintext_len, // IN - Plaintext length. WORD plaintext_len, // IN - Plaintext length.
const BYTE associated_data[], // IN - Associated Data included in authentication, but not encryption. const BYTE associated_data[], // IN - Associated Data included in authentication, but not encryption.
unsigned short associated_data_len, // IN - Associated Data length in bytes. unsigned short associated_data_len, // IN - Associated Data length in bytes.
const BYTE nonce[], // IN - The Nonce to be used for encryption. const BYTE nonce[], // IN - The Nonce to be used for encryption.
unsigned short nonce_len, // IN - Nonce length in bytes. unsigned short nonce_len, // IN - Nonce length in bytes.
BYTE ciphertext[], // OUT - Ciphertext, a concatination of the plaintext and the MAC. BYTE ciphertext[], // OUT - Ciphertext, a concatination of the plaintext and the MAC.
WORD *ciphertext_len, // OUT - The length of the ciphertext, always plaintext_len + mac_len. WORD *ciphertext_len, // OUT - The length of the ciphertext, always plaintext_len + mac_len.
WORD mac_len, // IN - The desired length of the MAC, must be 4, 6, 8, 10, 12, 14, or 16. WORD mac_len, // IN - The desired length of the MAC, must be 4, 6, 8, 10, 12, 14, or 16.
const BYTE key[], // IN - The AES key for encryption. const BYTE key[], // IN - The AES key for encryption.
int keysize); // IN - The length of the key in bits. Valid values are 128, 192, 256. int keysize); // IN - The length of the key in bits. Valid values are 128, 192, 256.
// Returns True if the input parameters do not violate any constraint. // Returns True if the input parameters do not violate any constraint.
// Use mac_auth to ensure decryption/validation was preformed correctly. // Use mac_auth to ensure decryption/validation was preformed correctly.
// If authentication does not succeed, the plaintext is zeroed out. To overwride // If authentication does not succeed, the plaintext is zeroed out. To overwride
// this, call with mac_auth = NULL. The proper proceedure is to decrypt with // this, call with mac_auth = NULL. The proper proceedure is to decrypt with
// authentication enabled (mac_auth != NULL) and make a second call to that // authentication enabled (mac_auth != NULL) and make a second call to that
// ignores authentication explicitly if the first call failes. // ignores authentication explicitly if the first call failes.
int aes_decrypt_ccm(const BYTE ciphertext[], // IN - Ciphertext, the concatination of encrypted plaintext and MAC. int aes_decrypt_ccm(const BYTE ciphertext[], // IN - Ciphertext, the concatination of encrypted plaintext and MAC.
WORD ciphertext_len, // IN - Ciphertext length in bytes. WORD ciphertext_len, // IN - Ciphertext length in bytes.
const BYTE assoc[], // IN - The Associated Data, required for authentication. const BYTE assoc[], // IN - The Associated Data, required for authentication.
unsigned short assoc_len, // IN - Associated Data length in bytes. unsigned short assoc_len, // IN - Associated Data length in bytes.
const BYTE nonce[], // IN - The Nonce to use for decryption, same one as for encryption. const BYTE nonce[], // IN - The Nonce to use for decryption, same one as for encryption.
unsigned short nonce_len, // IN - Nonce length in bytes. unsigned short nonce_len, // IN - Nonce length in bytes.
BYTE plaintext[], // OUT - The plaintext that was decrypted. Will need to be large enough to hold ciphertext_len - mac_len. BYTE plaintext[], // OUT - The plaintext that was decrypted. Will need to be large enough to hold ciphertext_len - mac_len.
WORD *plaintext_len, // OUT - Length in bytes of the output plaintext, always ciphertext_len - mac_len . WORD *plaintext_len, // OUT - Length in bytes of the output plaintext, always ciphertext_len - mac_len .
WORD mac_len, // IN - The length of the MAC that was calculated. WORD mac_len, // IN - The length of the MAC that was calculated.
int *mac_auth, // OUT - TRUE if authentication succeeded, FALSE if it did not. NULL pointer will ignore the authentication. int *mac_auth, // OUT - TRUE if authentication succeeded, FALSE if it did not. NULL pointer will ignore the authentication.
const BYTE key[], // IN - The AES key for decryption. const BYTE key[], // IN - The AES key for decryption.
int keysize); // IN - The length of the key in BITS. Valid values are 128, 192, 256. int keysize); // IN - The length of the key in BITS. Valid values are 128, 192, 256.
/////////////////// ///////////////////
// Test functions // Test functions
/////////////////// ///////////////////
int aes_test(); int aes_test();
int aes_ecb_test(); int aes_ecb_test();
int aes_cbc_test(); int aes_cbc_test();
int aes_ctr_test(); int aes_ctr_test();
int aes_ccm_test(); int aes_ccm_test();
#endif // AES_H #endif // AES_H

View file

@ -11,14 +11,13 @@
/*************************** HEADER FILES ***************************/ /*************************** HEADER FILES ***************************/
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
/****************************** MACROS ******************************/ /****************************** MACROS ******************************/
#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest #define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
/**************************** DATA TYPES ****************************/ /**************************** DATA TYPES ****************************/
typedef uint8_t BYTE; // 8-bit byte typedef unsigned char BYTE; // 8-bit byte
typedef uint32_t WORD; // 32-bit word, change to "long" for 16-bit machines typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
typedef struct { typedef struct {
BYTE data[64]; BYTE data[64];

View file

@ -4498,7 +4498,7 @@ namespace {
sigaltstack(&sigStack, &oldSigStack); sigaltstack(&sigStack, &oldSigStack);
struct sigaction sa = {}; struct sigaction sa = {};
sa.sa_handler = handleSignal; // NOLINT sa.sa_handler = handleSignal; // NOLINT
sa.sa_flags = SS_ONSTACK; sa.sa_flags = SA_ONSTACK;
for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {
sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
} }

View file

@ -1684,7 +1684,7 @@ namespace {
sigaltstack(&sigStack, &oldSigStack); sigaltstack(&sigStack, &oldSigStack);
struct sigaction sa = {}; struct sigaction sa = {};
sa.sa_handler = handleSignal; // NOLINT sa.sa_handler = handleSignal; // NOLINT
sa.sa_flags = SS_ONSTACK; sa.sa_flags = SA_ONSTACK;
for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {
sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
} }

View file

@ -1,76 +0,0 @@
final: prev: {
olm-gcc-cmake = prev.gccStdenv.mkDerivation {
name = "olm_gcc_cmake";
src = ./..;
nativeBuildInputs = [ prev.cmake ];
doCheck = true;
checkPhase = ''
(cd tests && ctest . -j $NIX_BUILD_CORES)
'';
};
olm-clang-cmake = prev.clangStdenv.mkDerivation {
name = "olm_clang_cmake";
src = ./..;
nativeBuildInputs = [ prev.cmake ];
doCheck = true;
checkPhase = ''
(cd tests && ctest . -j $NIX_BUILD_CORES)
'';
};
olm-gcc-make = prev.gccStdenv.mkDerivation {
name = "olm";
src = ./..;
doCheck = true;
makeFlags = [ "PREFIX=$out" ];
};
olm-javascript = final.buildEmscriptenPackage {
pname = "olm_javascript";
inherit (builtins.fromJSON (builtins.readFile ../javascript/package.json)) version;
src = ./..;
nativeBuildInputs = with prev; [ gnumake python3 nodejs ];
postPatch = ''
patchShebangs .
'';
configurePhase = false;
buildPhase = ''
export EM_CACHE=$TMPDIR
make javascript/exported_functions.json
make js
'';
installPhase = ''
mkdir -p $out/javascript
cd javascript
echo sha256: > checksums.txt
sha256sum olm.js olm_legacy.js olm.wasm >> checksums.txt
echo sha512: >> checksums.txt
sha512sum olm.js olm_legacy.js olm.wasm >> checksums.txt
cp package.json olm.js olm.wasm olm_legacy.js index.d.ts README.md checksums.txt $out/javascript
cd ..
'';
checkPhase = ''
cd javascript
export HOME=$TMPDIR
ln -s ${final.node_modules}/node_modules ./node_modules
npm test
cd ..
'';
};
}

View file

@ -34,7 +34,7 @@ test:python:
image: docker.io/python:$PYTHON_VERSIONS image: docker.io/python:$PYTHON_VERSIONS
parallel: parallel:
matrix: matrix:
- PYTHON_VERSIONS: [ "3.8", "3.9", "3.10", "3.11", "3.12" ] - PYTHON_VERSIONS: [ "3.6", "3.7", "3.8", "3.9" ]
script: script:
- pip install tox - pip install tox
- make headers - make headers

View file

@ -1,3 +1,5 @@
include include/olm/*.h include include/olm/olm.h
include include/olm/pk.h
include include/olm/sas.h
include Makefile include Makefile
include olm_build.py include olm_build.py

View file

@ -15,18 +15,6 @@ found [here][6].
The full API reference can be found [here][7]. The full API reference can be found [here][7].
# Installation instructions
To install from the source package, you will need:
- cmake (recommended) or GNU make
- a C/C++ compiler
You can then run `pip install python-olm`.
This should work in UNIX-like environments, including macOS, and may work in
other environments too, but is known to not work yet in Windows.
# Accounts # Accounts
Accounts create and hold the central identity of the Olm protocol, they consist of a fingerprint and identity Accounts create and hold the central identity of the Olm protocol, they consist of a fingerprint and identity

View file

@ -1,35 +0,0 @@
#!/bin/bash
set -e
DIR=$(mktemp -d)
SRC=$(pwd)
echo "Making headers"
make headers
cd $DIR
echo "Copying python module"
cp -a $SRC/* .
mkdir -p libolm
echo "Cleaning sources"
make clean > /dev/null
cp -a $SRC/include .
echo "Copying libolm sources"
for src in cmake CMakeLists.txt common.mk include lib Makefile olm.pc.in src tests; do
cp -a $SRC/../$src libolm
done
find libolm -name \*~ -delete
find libolm -name \#\*\# -delete
echo "Building"
patch -p1 < $SRC/packaging.diff
python3 -m build -s
echo "Copying result"
mkdir -p $SRC/dist
cp dist/* $SRC/dist
echo "Cleaning up"
cd $SRC
rm -rf $DIR

View file

@ -0,0 +1,9 @@
__title__ = "python-olm"
__description__ = ("python CFFI bindings for the olm "
"cryptographic ratchet library")
__url__ = "https://github.com/poljar/python-olm"
__version__ = "3.2.13"
__author__ = "Damir Jelić"
__author_email__ = "poljar@termina.org.uk"
__license__ = "Apache 2.0"
__copyright__ = "Copyright 2018-2019 Damir Jelić"

View file

@ -23,6 +23,7 @@
This is designed for avoiding __del__. This is designed for avoiding __del__.
""" """
from __future__ import print_function
import sys import sys
import traceback import traceback

View file

@ -32,6 +32,8 @@ import json
from builtins import bytes, super from builtins import bytes, super
from typing import AnyStr, Dict, Optional, Type from typing import AnyStr, Dict, Optional, Type
from future.utils import bytes_to_native_str
# pylint: disable=no-name-in-module # pylint: disable=no-name-in-module
from _libolm import ffi, lib # type: ignore from _libolm import ffi, lib # type: ignore
@ -91,7 +93,8 @@ class Account(object):
if ret != lib.olm_error(): if ret != lib.olm_error():
return return
last_error = ffi.string((lib.olm_account_last_error(self._account))).decode() last_error = bytes_to_native_str(
ffi.string((lib.olm_account_last_error(self._account))))
raise OlmAccountError(last_error) raise OlmAccountError(last_error)
@ -206,7 +209,7 @@ class Account(object):
for i in range(0, len(bytes_message)): for i in range(0, len(bytes_message)):
bytes_message[i] = 0 bytes_message[i] = 0
return ffi.unpack(out_buffer, out_length).decode() return bytes_to_native_str(ffi.unpack(out_buffer, out_length))
@property @property
def max_one_time_keys(self): def max_one_time_keys(self):

View file

@ -28,6 +28,8 @@ Examples:
from builtins import bytes, super from builtins import bytes, super
from typing import AnyStr, Optional, Tuple, Type from typing import AnyStr, Optional, Tuple, Type
from future.utils import bytes_to_native_str
# pylint: disable=no-name-in-module # pylint: disable=no-name-in-module
from _libolm import ffi, lib # type: ignore from _libolm import ffi, lib # type: ignore
@ -169,9 +171,8 @@ class InboundGroupSession(object):
if ret != lib.olm_error(): if ret != lib.olm_error():
return return
last_error = ffi.string( last_error = bytes_to_native_str(ffi.string(
lib.olm_inbound_group_session_last_error(self._session) lib.olm_inbound_group_session_last_error(self._session)))
).decode()
raise OlmGroupSessionError(last_error) raise OlmGroupSessionError(last_error)
@ -251,7 +252,7 @@ class InboundGroupSession(object):
id_length id_length
) )
self._check_error(ret) self._check_error(ret)
return ffi.unpack(id_buffer, id_length).decode() return bytes_to_native_str(ffi.unpack(id_buffer, id_length))
@property @property
def first_known_index(self): def first_known_index(self):
@ -289,7 +290,7 @@ class InboundGroupSession(object):
message_index message_index
) )
self._check_error(ret) self._check_error(ret)
export_str = ffi.unpack(export_buffer, export_length).decode() export_str = bytes_to_native_str(ffi.unpack(export_buffer, export_length))
# clear out copies of the key # clear out copies of the key
lib.memset(export_buffer, 0, export_length) lib.memset(export_buffer, 0, export_length)
@ -372,9 +373,9 @@ class OutboundGroupSession(object):
if ret != lib.olm_error(): if ret != lib.olm_error():
return return
last_error = ffi.string( last_error = bytes_to_native_str(ffi.string(
lib.olm_outbound_group_session_last_error(self._session) lib.olm_outbound_group_session_last_error(self._session)
).decode() ))
raise OlmGroupSessionError(last_error) raise OlmGroupSessionError(last_error)
@ -482,7 +483,7 @@ class OutboundGroupSession(object):
for i in range(0, len(byte_plaintext)): for i in range(0, len(byte_plaintext)):
byte_plaintext[i] = 0 byte_plaintext[i] = 0
return ffi.unpack(message_buffer, message_length).decode() return bytes_to_native_str(ffi.unpack(message_buffer, message_length))
@property @property
def id(self): def id(self):
@ -498,7 +499,7 @@ class OutboundGroupSession(object):
) )
self._check_error(ret) self._check_error(ret)
return ffi.unpack(id_buffer, id_length).decode() return bytes_to_native_str(ffi.unpack(id_buffer, id_length))
@property @property
def message_index(self): def message_index(self):
@ -528,4 +529,4 @@ class OutboundGroupSession(object):
) )
self._check_error(ret) self._check_error(ret)
return ffi.unpack(key_buffer, key_length).decode() return bytes_to_native_str(ffi.unpack(key_buffer, key_length))

View file

@ -36,6 +36,8 @@ Examples:
from builtins import super from builtins import super
from typing import AnyStr, Type from typing import AnyStr, Type
from future.utils import bytes_to_native_str
from _libolm import ffi, lib # type: ignore from _libolm import ffi, lib # type: ignore
from ._compat import URANDOM, to_bytearray, to_unicode_str from ._compat import URANDOM, to_bytearray, to_unicode_str
@ -114,9 +116,8 @@ class PkEncryption(object):
if ret != lib.olm_error(): if ret != lib.olm_error():
return return
last_error = ffi.string( last_error = bytes_to_native_str(
lib.olm_pk_encryption_last_error(self._pk_encryption) ffi.string(lib.olm_pk_encryption_last_error(self._pk_encryption)))
).decode()
raise PkEncryptionError(last_error) raise PkEncryptionError(last_error)
@ -165,9 +166,12 @@ class PkEncryption(object):
byte_plaintext[i] = 0 byte_plaintext[i] = 0
message = PkMessage( message = PkMessage(
ffi.unpack(ephemeral_key, ephemeral_key_size).decode(), bytes_to_native_str(
ffi.unpack(mac, mac_length).decode(), ffi.unpack(ephemeral_key, ephemeral_key_size)),
ffi.unpack(ciphertext, ciphertext_length).decode(), bytes_to_native_str(
ffi.unpack(mac, mac_length)),
bytes_to_native_str(
ffi.unpack(ciphertext, ciphertext_length))
) )
return message return message
@ -213,19 +217,18 @@ class PkDecryption(object):
random_buffer, random_length random_buffer, random_length
) )
self._check_error(ret) self._check_error(ret)
self.public_key: str = ffi.unpack( self.public_key: str = bytes_to_native_str(ffi.unpack(
key_buffer, key_buffer,
key_length key_length
).decode() ))
def _check_error(self, ret): def _check_error(self, ret):
# type: (int) -> None # type: (int) -> None
if ret != lib.olm_error(): if ret != lib.olm_error():
return return
last_error = ffi.string( last_error = bytes_to_native_str(
lib.olm_pk_decryption_last_error(self._pk_decryption) ffi.string(lib.olm_pk_decryption_last_error(self._pk_decryption)))
).decode()
raise PkDecryptionError(last_error) raise PkDecryptionError(last_error)
@ -303,10 +306,10 @@ class PkDecryption(object):
for i in range(0, len(byte_key)): for i in range(0, len(byte_key)):
byte_key[i] = 0 byte_key[i] = 0
obj.public_key = ffi.unpack( obj.public_key = bytes_to_native_str(ffi.unpack(
pubkey_buffer, pubkey_buffer,
pubkey_length pubkey_length
).decode() ))
return obj return obj
@ -408,14 +411,17 @@ class PkSigning(object):
self._check_error(ret) self._check_error(ret)
self.public_key = ffi.unpack(pubkey_buffer, pubkey_length).decode() self.public_key = bytes_to_native_str(
ffi.unpack(pubkey_buffer, pubkey_length)
)
def _check_error(self, ret): def _check_error(self, ret):
# type: (int) -> None # type: (int) -> None
if ret != lib.olm_error(): if ret != lib.olm_error():
return return
last_error = ffi.string(lib.olm_pk_signing_last_error(self._pk_signing)).decode() last_error = bytes_to_native_str(
ffi.string(lib.olm_pk_signing_last_error(self._pk_signing)))
raise PkSigningError(last_error) raise PkSigningError(last_error)
@ -450,4 +456,6 @@ class PkSigning(object):
signature_buffer, signature_length) signature_buffer, signature_length)
self._check_error(ret) self._check_error(ret)
return ffi.unpack(signature_buffer, signature_length).decode() return bytes_to_native_str(
ffi.unpack(signature_buffer, signature_length)
)

View file

@ -34,6 +34,8 @@ from builtins import bytes
from functools import wraps from functools import wraps
from typing import Optional from typing import Optional
from future.utils import bytes_to_native_str
from _libolm import ffi, lib from _libolm import ffi, lib
from ._compat import URANDOM, to_bytearray, to_bytes from ._compat import URANDOM, to_bytearray, to_bytes
@ -90,7 +92,8 @@ class Sas(object):
if ret != lib.olm_error(): if ret != lib.olm_error():
return return
last_error = ffi.string((lib.olm_sas_last_error(self._sas))).decode() last_error = bytes_to_native_str(
ffi.string((lib.olm_sas_last_error(self._sas))))
raise OlmSasError(last_error) raise OlmSasError(last_error)
@ -112,7 +115,7 @@ class Sas(object):
lib.olm_sas_get_pubkey(self._sas, pubkey_buffer, pubkey_length) lib.olm_sas_get_pubkey(self._sas, pubkey_buffer, pubkey_length)
) )
return ffi.unpack(pubkey_buffer, pubkey_length).decode() return bytes_to_native_str(ffi.unpack(pubkey_buffer, pubkey_length))
@property @property
def other_key_set(self): def other_key_set(self):
@ -205,7 +208,7 @@ class Sas(object):
mac_length mac_length
) )
) )
return ffi.unpack(mac_buffer, mac_length).decode() return bytes_to_native_str(ffi.unpack(mac_buffer, mac_length))
def calculate_mac_fixed_base64(self, message, extra_info): def calculate_mac_fixed_base64(self, message, extra_info):
# type: (str, str) -> str # type: (str, str) -> str
@ -239,7 +242,7 @@ class Sas(object):
mac_length mac_length
) )
) )
return ffi.unpack(mac_buffer, mac_length).decode() return bytes_to_native_str(ffi.unpack(mac_buffer, mac_length))
def calculate_mac_long_kdf(self, message, extra_info): def calculate_mac_long_kdf(self, message, extra_info):
# type: (str, str) -> str # type: (str, str) -> str
@ -273,4 +276,4 @@ class Sas(object):
mac_length mac_length
) )
) )
return ffi.unpack(mac_buffer, mac_length).decode() return bytes_to_native_str(ffi.unpack(mac_buffer, mac_length))

View file

@ -35,6 +35,8 @@ Examples:
from builtins import bytes, super from builtins import bytes, super
from typing import AnyStr, Optional, Type from typing import AnyStr, Optional, Type
from future.utils import bytes_to_native_str
# pylint: disable=no-name-in-module # pylint: disable=no-name-in-module
from _libolm import ffi, lib # type: ignore from _libolm import ffi, lib # type: ignore
@ -144,7 +146,8 @@ class Session(object):
if ret != lib.olm_error(): if ret != lib.olm_error():
return return
last_error = ffi.string(lib.olm_session_last_error(self._session)).decode() last_error = bytes_to_native_str(
ffi.string(lib.olm_session_last_error(self._session)))
raise OlmSessionError(last_error) raise OlmSessionError(last_error)
@ -257,16 +260,16 @@ class Session(object):
if message_type == lib.OLM_MESSAGE_TYPE_PRE_KEY: if message_type == lib.OLM_MESSAGE_TYPE_PRE_KEY:
return OlmPreKeyMessage( return OlmPreKeyMessage(
ffi.unpack( bytes_to_native_str(ffi.unpack(
ciphertext_buffer, ciphertext_buffer,
ciphertext_length ciphertext_length
).decode()) )))
elif message_type == lib.OLM_MESSAGE_TYPE_MESSAGE: elif message_type == lib.OLM_MESSAGE_TYPE_MESSAGE:
return OlmMessage( return OlmMessage(
ffi.unpack( bytes_to_native_str(ffi.unpack(
ciphertext_buffer, ciphertext_buffer,
ciphertext_length ciphertext_length
).decode()) )))
else: # pragma: no cover else: # pragma: no cover
raise ValueError("Unknown message type") raise ValueError("Unknown message type")
@ -337,7 +340,7 @@ class Session(object):
self._check_error( self._check_error(
lib.olm_session_id(self._session, id_buffer, id_length) lib.olm_session_id(self._session, id_buffer, id_length)
) )
return ffi.unpack(id_buffer, id_length).decode() return bytes_to_native_str(ffi.unpack(id_buffer, id_length))
def matches(self, message, identity_key=None): def matches(self, message, identity_key=None):
# type: (OlmPreKeyMessage, Optional[AnyStr]) -> bool # type: (OlmPreKeyMessage, Optional[AnyStr]) -> bool
@ -404,7 +407,7 @@ class Session(object):
lib.olm_session_describe( lib.olm_session_describe(
self._session, describe_buffer, buffer_length self._session, describe_buffer, buffer_length
) )
return ffi.string(describe_buffer).decode() return bytes_to_native_str(ffi.string(describe_buffer))
class InboundSession(Session): class InboundSession(Session):

View file

@ -33,6 +33,8 @@ Examples:
# pylint: disable=redefined-builtin,unused-import # pylint: disable=redefined-builtin,unused-import
from typing import AnyStr, Type from typing import AnyStr, Type
from future.utils import bytes_to_native_str
# pylint: disable=no-name-in-module # pylint: disable=no-name-in-module
from _libolm import ffi, lib # type: ignore from _libolm import ffi, lib # type: ignore
@ -121,7 +123,7 @@ class _Utility(object):
cls._check_error(ret, OlmHashError) cls._check_error(ret, OlmHashError)
return ffi.unpack(hash, hash_length).decode() return bytes_to_native_str(ffi.unpack(hash, hash_length))
def ed25519_verify(key, message, signature): def ed25519_verify(key, message, signature):

View file

@ -15,6 +15,8 @@
# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN # CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
from __future__ import unicode_literals
import os import os
import subprocess import subprocess
@ -26,10 +28,18 @@ PATH = os.path.dirname(__file__)
DEVELOP = os.environ.get("DEVELOP") DEVELOP = os.environ.get("DEVELOP")
compile_args = ["-I../include"] compile_args = ["-I../include"]
link_args = ["-L../build"]
if DEVELOP and DEVELOP.lower() in ["yes", "true", "1"]: if DEVELOP and DEVELOP.lower() in ["yes", "true", "1"]:
link_args.append('-Wl,-rpath=../build') link_args.append('-Wl,-rpath=../build')
# If libolm is compiled statically, we may need to link to the C++ standard
# library dynamically. This flag allows passing the required linker flag to do
# so.
CXX_LIB = os.environ.get("CXX_LIB")
if CXX_LIB:
link_args.append(CXX_LIB)
headers_build = subprocess.Popen("make headers", shell=True) headers_build = subprocess.Popen("make headers", shell=True)
headers_build.wait() headers_build.wait()
@ -43,10 +53,8 @@ ffibuilder.set_source(
#include <olm/sas.h> #include <olm/sas.h>
""", """,
libraries=["olm"], libraries=["olm"],
library_dirs=[os.path.join("..", "build")],
extra_compile_args=compile_args, extra_compile_args=compile_args,
source_extension=".cpp", # we need to link the C++ standard library, so use a C++ extension extra_link_args=link_args)
)
with open(os.path.join(PATH, "include/olm/error.h")) as f: with open(os.path.join(PATH, "include/olm/error.h")) as f:
ffibuilder.cdef(f.read(), override=True) ffibuilder.cdef(f.read(), override=True)

View file

@ -1,56 +0,0 @@
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,3 +1,8 @@
include include/olm/*.h
-include Makefile
include olm_build.py
+include libolm/*
+include libolm/cmake/*
+include libolm/include/olm/*
+recursive-include libolm/lib *
+include libolm/src/*
+recursive-include libolm/tests *
--- a/olm_build.py
+++ b/olm_build.py
@@ -25,12 +25,29 @@
DEVELOP = os.environ.get("DEVELOP")
-compile_args = ["-I../include"]
+compile_args = ["-Ilibolm/include"]
if DEVELOP and DEVELOP.lower() in ["yes", "true", "1"]:
link_args.append('-Wl,-rpath=../build')
-headers_build = subprocess.Popen("make headers", shell=True)
-headers_build.wait()
+# Try to build with cmake first, fall back to GNU make
+try:
+ subprocess.run(
+ ["cmake", ".", "-Bbuild", "-DBUILD_SHARED_LIBS=NO"],
+ cwd="libolm", check=True,
+ )
+ subprocess.run(
+ ["cmake", "--build", "build"],
+ cwd="libolm", check=True,
+ )
+except FileNotFoundError:
+ try:
+ # try "gmake" first because some systems have a non-GNU make
+ # installed as "make"
+ subprocess.run(["gmake", "static"], cwd="libolm", check=True)
+ except FileNotFoundError:
+ # some systems have GNU make installed without the leading "g"
+ # so give that a try (though this may fail if it isn't GNU make)
+ subprocess.run(["make", "static"], cwd="libolm", check=True)
ffibuilder.set_source(
@@ -43,7 +60,7 @@
#include <olm/sas.h>
""",
libraries=["olm"],
- library_dirs=[os.path.join("..", "build")],
+ library_dirs=[os.path.join("libolm", "build")],
extra_compile_args=compile_args,
source_extension=".cpp", # we need to link the C++ standard library, so use a C++ extension
)

View file

@ -1,22 +0,0 @@
[build-system]
requires = ["setuptools", "cffi>=1.0.0"]
build-backend = "setuptools.build_meta"
[project]
name = "python-olm"
version = "3.2.16"
description = "python CFFI bindings for the olm cryptographic ratchet library"
authors = [{name = "Damir Jelić", email = "poljar@termina.org.uk"}]
license = {text = "Apache-2.0"}
readme = "README.md"
classifiers = [
"License :: OSI Approved :: Apache Software License",
"Topic :: Communications",
]
dependencies = ["cffi>=1.0.0"]
[project.urls]
homepage = "https://gitlab.matrix.org/matrix-org/olm/-/tree/master/python"
[tool.setuptools]
packages = [ "olm" ]

View file

@ -1,2 +1,3 @@
future
cffi cffi
typing typing

View file

@ -3,3 +3,6 @@ testpaths = tests
flake8-ignore = flake8-ignore =
olm/*.py F401 olm/*.py F401
tests/*.py W503 tests/*.py W503
[coverage:run]
omit=olm/__version__.py

View file

@ -1,6 +1,34 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os
from codecs import open
from setuptools import setup from setuptools import setup
here = os.path.abspath(os.path.dirname(__file__))
about = {}
with open(os.path.join(here, "olm", "__version__.py"), "r", "utf-8") as f:
exec(f.read(), about)
setup( setup(
cffi_modules=["olm_build.py:ffibuilder"] name=about["__title__"],
version=about["__version__"],
description=about["__description__"],
author=about["__author__"],
author_email=about["__author_email__"],
url=about["__url__"],
license=about["__license__"],
packages=["olm"],
setup_requires=["cffi>=1.0.0"],
cffi_modules=["olm_build.py:ffibuilder"],
install_requires=[
"cffi>=1.0.0",
"future",
"typing;python_version<'3.5'"
],
zip_safe=False,
package_data={
"olm": ["py.typed"]
}
) )

View file

@ -1,6 +1,8 @@
import base64 import base64
import hashlib import hashlib
from future.utils import bytes_to_native_str
from olm import sha256 from olm import sha256
from olm._compat import to_bytes from olm._compat import to_bytes
@ -17,7 +19,7 @@ class TestClass(object):
hashlib.sha256(to_bytes(input1)).digest() hashlib.sha256(to_bytes(input1)).digest()
) )
hashlib_hash = hashlib_hash[:-1].decode() hashlib_hash = bytes_to_native_str(hashlib_hash[:-1])
assert first_hash != second_hash assert first_hash != second_hash
assert hashlib_hash == first_hash assert hashlib_hash == first_hash

View file

@ -6,7 +6,7 @@ envlist = py27,py36,pypy,{py2,py3}-cov,coverage
deps = -rrequirements.txt deps = -rrequirements.txt
-rtest-requirements.txt -rtest-requirements.txt
passenv = TOXENV,CI,TRAVIS,TRAVIS_* passenv = TOXENV CI TRAVIS TRAVIS_*
commands = pytest --benchmark-disable commands = pytest --benchmark-disable
usedevelop = True usedevelop = True

View file

@ -437,7 +437,7 @@ void olm::Session::describe(char *describe_buffer, size_t buflen) {
size = snprintf( size = snprintf(
describe_buffer, remaining, describe_buffer, remaining,
"sender chain index: %lu ", ratchet.sender_chain[0].chain_key.index "sender chain index: %d ", ratchet.sender_chain[0].chain_key.index
); );
CHECK_SIZE_AND_ADVANCE; CHECK_SIZE_AND_ADVANCE;
@ -447,7 +447,7 @@ void olm::Session::describe(char *describe_buffer, size_t buflen) {
for (size_t i = 0; i < ratchet.receiver_chains.size(); ++i) { for (size_t i = 0; i < ratchet.receiver_chains.size(); ++i) {
size = snprintf( size = snprintf(
describe_buffer, remaining, describe_buffer, remaining,
" %lu", ratchet.receiver_chains[i].chain_key.index " %d", ratchet.receiver_chains[i].chain_key.index
); );
CHECK_SIZE_AND_ADVANCE; CHECK_SIZE_AND_ADVANCE;
} }
@ -458,7 +458,7 @@ void olm::Session::describe(char *describe_buffer, size_t buflen) {
for (size_t i = 0; i < ratchet.skipped_message_keys.size(); ++i) { for (size_t i = 0; i < ratchet.skipped_message_keys.size(); ++i) {
size = snprintf( size = snprintf(
describe_buffer, remaining, describe_buffer, remaining,
" %lu", ratchet.skipped_message_keys[i].message_key.index " %d", ratchet.skipped_message_keys[i].message_key.index
); );
CHECK_SIZE_AND_ADVANCE; CHECK_SIZE_AND_ADVANCE;
} }

View file

@ -4498,7 +4498,7 @@ namespace {
sigaltstack(&sigStack, &oldSigStack); sigaltstack(&sigStack, &oldSigStack);
struct sigaction sa = {}; struct sigaction sa = {};
sa.sa_handler = handleSignal; // NOLINT sa.sa_handler = handleSignal; // NOLINT
sa.sa_flags = SS_ONSTACK; sa.sa_flags = SA_ONSTACK;
for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {
sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
} }