Merge pull request #36 from matrix-org/manuroe/olmkit

OLMKit
This commit is contained in:
Richard van der Hoff 2016-12-22 14:43:01 +00:00 committed by GitHub
commit 90b3613053
32 changed files with 2687 additions and 2 deletions

23
.gitignore vendored
View file

@ -5,4 +5,25 @@
/docs/signing.html
/olm-*.tgz
/README.html
/tracing/README.html
/tracing/README.html
# Xcode
build/
DerivedData/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
*.moved-aside
*.xcuserstate
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
Pods/
*.xcworkspace

View file

@ -1,3 +1,10 @@
Changes in `2.0.1 <http://matrix.org/git/olm/commit/?h=2.0.1>`_
===============================================================
This release includes the following changes since 2.0.0
* Add OLMKit, the Objective-C wrapper.
Changes in `2.0.0 <http://matrix.org/git/olm/commit/?h=2.0.0>`_
===============================================================

View file

@ -2,7 +2,7 @@
MAJOR := 2
MINOR := 0
PATCH := 0
PATCH := 1
VERSION := $(MAJOR).$(MINOR).$(PATCH)
PREFIX ?= /usr/local
BUILD_DIR := build

61
OLMKit.podspec Normal file
View file

@ -0,0 +1,61 @@
Pod::Spec.new do |s|
# The libolm version
MAJOR = 2
MINOR = 0
PATCH = 1
s.name = "OLMKit"
s.version = "#{MAJOR}.#{MINOR}.#{PATCH}"
s.summary = "An Objective-C wrapper of olm (http://matrix.org/git/olm)"
s.description = <<-DESC
olm is an implementation of the Double Ratchet cryptographic ratchet in C++
DESC
s.homepage = "http://matrix.org/git/olm"
s.license = { :type => "Apache License, Version 2.0", :file => "LICENSE" }
s.authors = { "Chris Ballinger" => "chrisballinger@gmail.com",
"matrix.org" => "support@matrix.org" }
s.platform = :ios, "5.0"
# Expose the Objective-C wrapper API of libolm
s.public_header_files = "xcode/OLMKit/*.h"
s.source = {
:git => "https://matrix.org/git/olm.git",
:tag => s.version.to_s
}
s.source_files = "xcode/OLMKit/*.{h,m}", "include/**/*.{h,hh}", "src/*.{c,cpp}", "lib/crypto-algorithms/sha256.c", "lib/crypto-algorithms/aes.c", "lib/curve25519-donna/curve25519-donna.c"
# Those files (including .c) are included by ed25519.c. We do not want to compile them twice
s.preserve_paths = "lib/ed25519/**/*.{h,c}"
s.library = "c++"
# Use the same compiler options for C and C++ as olm/Makefile
s.compiler_flags = "-g -O3 -DOLMLIB_VERSION_MAJOR=#{MAJOR} -DOLMLIB_VERSION_MINOR=#{MINOR} -DOLMLIB_VERSION_PATCH=#{PATCH}"
# For headers search paths, manage first the normal installation. Then, use paths used
# when the pod is local
s.xcconfig = {
'USER_HEADER_SEARCH_PATHS' =>"${PODS_ROOT}/OLMKit/include ${PODS_ROOT}/OLMKit/lib #{File.join(File.dirname(__FILE__), 'include')} #{File.join(File.dirname(__FILE__), 'lib')}"
}
s.subspec 'olmc' do |olmc|
olmc.source_files = "src/*.{c}", "lib/curve25519-donna.h", "lib/crypto-algorithms/sha256.{h,c}", "lib/crypto-algorithms/aes.{h,c}", "lib/curve25519-donna/curve25519-donna.c"
olmc.compiler_flags = ' -std=c99 -fPIC'
end
s.subspec 'olmcpp' do |olmcpp|
olmcpp.source_files = "src/*.{cpp}"
olmcpp.compiler_flags = ' -std=c++11 -fPIC'
end
end

View file

@ -33,6 +33,14 @@ To build the javascript bindings, install emscripten from http://kripken.github.
make js
To build the Xcode workspace for Objective-C bindings, run:
.. code:: bash
cd xcode
pod install
open OLMKit.xcworkspace
Release process
---------------
@ -50,6 +58,14 @@ Release process
git tag $VERSION -s
git push --tags
# OLMKit CocoaPod release
# Make sure the version OLMKit.podspec is the same as the git tag
# (this must be checked before git tagging)
pod spec lint OLMKit.podspec --use-libraries --allow-warnings
pod trunk push OLMKit.podspec --use-libraries --allow-warnings
# Check the pod has been successully published with:
pod search OLMKit
It's probably sensible to do the above on a release branch (``release-vx.y.z``
by convention), and merge back to master once complete.

View file

@ -21,6 +21,7 @@
#include "aes.h"
#include <stdio.h>
#include <string.h>
/****************************** MACROS ******************************/
// The least significant byte of the word is rotated to the end.

View file

@ -15,6 +15,7 @@
/*************************** HEADER FILES ***************************/
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include "sha256.h"
/****************************** MACROS ******************************/

View file

@ -0,0 +1,528 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
3274F6021D9A633A005282E4 /* OLMKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3274F5F81D9A633A005282E4 /* OLMKit.framework */; };
3274F6071D9A633A005282E4 /* OLMKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3274F6061D9A633A005282E4 /* OLMKitTests.m */; };
3274F6131D9A698E005282E4 /* OLMKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 3274F6121D9A698E005282E4 /* OLMKit.h */; };
32A151311DABDD4300400192 /* OLMKitGroupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A151301DABDD4300400192 /* OLMKitGroupTests.m */; };
7DBAD311AEA85CF6DB80DCFA /* libPods-OLMKitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7123FABE917D0FB140E036B7 /* libPods-OLMKitTests.a */; };
D667051A0BA47E17CCC4E5D7 /* libPods-OLMKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F2F22FE8F173AF845B882805 /* libPods-OLMKit.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
3274F6031D9A633A005282E4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 3274F5EF1D9A633A005282E4 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 3274F5F71D9A633A005282E4;
remoteInfo = OLMKit;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
1B226B371526F2782C9D6372 /* Pods-OLMKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OLMKit.release.xcconfig"; path = "Pods/Target Support Files/Pods-OLMKit/Pods-OLMKit.release.xcconfig"; sourceTree = "<group>"; };
3274F5F81D9A633A005282E4 /* OLMKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OLMKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3274F5FC1D9A633A005282E4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
3274F6011D9A633A005282E4 /* OLMKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OLMKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3274F6061D9A633A005282E4 /* OLMKitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OLMKitTests.m; sourceTree = "<group>"; };
3274F6081D9A633A005282E4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
3274F6121D9A698E005282E4 /* OLMKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OLMKit.h; sourceTree = "<group>"; };
32A151301DABDD4300400192 /* OLMKitGroupTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OLMKitGroupTests.m; sourceTree = "<group>"; };
7123FABE917D0FB140E036B7 /* libPods-OLMKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-OLMKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
875BA7A520258EA15A31DD82 /* Pods-OLMKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OLMKitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-OLMKitTests/Pods-OLMKitTests.debug.xcconfig"; sourceTree = "<group>"; };
D48E486DAE1F59F4F7EA8C25 /* Pods-OLMKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OLMKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-OLMKitTests/Pods-OLMKitTests.release.xcconfig"; sourceTree = "<group>"; };
E50E6B16E3433A5EB3297DEE /* Pods-OLMKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OLMKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-OLMKit/Pods-OLMKit.debug.xcconfig"; sourceTree = "<group>"; };
F2F22FE8F173AF845B882805 /* libPods-OLMKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-OLMKit.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
3274F5F41D9A633A005282E4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D667051A0BA47E17CCC4E5D7 /* libPods-OLMKit.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
3274F5FE1D9A633A005282E4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
3274F6021D9A633A005282E4 /* OLMKit.framework in Frameworks */,
7DBAD311AEA85CF6DB80DCFA /* libPods-OLMKitTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
1FA3F53DFAAAA773F07F5E56 /* Pods */ = {
isa = PBXGroup;
children = (
E50E6B16E3433A5EB3297DEE /* Pods-OLMKit.debug.xcconfig */,
1B226B371526F2782C9D6372 /* Pods-OLMKit.release.xcconfig */,
875BA7A520258EA15A31DD82 /* Pods-OLMKitTests.debug.xcconfig */,
D48E486DAE1F59F4F7EA8C25 /* Pods-OLMKitTests.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
3274F5EE1D9A633A005282E4 = {
isa = PBXGroup;
children = (
3274F5FA1D9A633A005282E4 /* OLMKit */,
3274F6051D9A633A005282E4 /* OLMKitTests */,
3274F5F91D9A633A005282E4 /* Products */,
1FA3F53DFAAAA773F07F5E56 /* Pods */,
A5D2E6F079A29F7CC2A8D9FE /* Frameworks */,
);
sourceTree = "<group>";
};
3274F5F91D9A633A005282E4 /* Products */ = {
isa = PBXGroup;
children = (
3274F5F81D9A633A005282E4 /* OLMKit.framework */,
3274F6011D9A633A005282E4 /* OLMKitTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
3274F5FA1D9A633A005282E4 /* OLMKit */ = {
isa = PBXGroup;
children = (
3274F6121D9A698E005282E4 /* OLMKit.h */,
3274F5FC1D9A633A005282E4 /* Info.plist */,
);
path = OLMKit;
sourceTree = "<group>";
};
3274F6051D9A633A005282E4 /* OLMKitTests */ = {
isa = PBXGroup;
children = (
3274F6061D9A633A005282E4 /* OLMKitTests.m */,
32A151301DABDD4300400192 /* OLMKitGroupTests.m */,
3274F6081D9A633A005282E4 /* Info.plist */,
);
path = OLMKitTests;
sourceTree = "<group>";
};
A5D2E6F079A29F7CC2A8D9FE /* Frameworks */ = {
isa = PBXGroup;
children = (
F2F22FE8F173AF845B882805 /* libPods-OLMKit.a */,
7123FABE917D0FB140E036B7 /* libPods-OLMKitTests.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
3274F5F51D9A633A005282E4 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
3274F6131D9A698E005282E4 /* OLMKit.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
3274F5F71D9A633A005282E4 /* OLMKit */ = {
isa = PBXNativeTarget;
buildConfigurationList = 3274F60C1D9A633B005282E4 /* Build configuration list for PBXNativeTarget "OLMKit" */;
buildPhases = (
7FBCB292198F4156D9CA3B8D /* [CP] Check Pods Manifest.lock */,
3274F5F31D9A633A005282E4 /* Sources */,
3274F5F41D9A633A005282E4 /* Frameworks */,
3274F5F51D9A633A005282E4 /* Headers */,
3274F5F61D9A633A005282E4 /* Resources */,
30F93582035CD30D211A6C76 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = OLMKit;
productName = OLMKit;
productReference = 3274F5F81D9A633A005282E4 /* OLMKit.framework */;
productType = "com.apple.product-type.framework";
};
3274F6001D9A633A005282E4 /* OLMKitTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 3274F60F1D9A633B005282E4 /* Build configuration list for PBXNativeTarget "OLMKitTests" */;
buildPhases = (
47E69E5BE6A019858DC41D4F /* [CP] Check Pods Manifest.lock */,
3274F5FD1D9A633A005282E4 /* Sources */,
3274F5FE1D9A633A005282E4 /* Frameworks */,
3274F5FF1D9A633A005282E4 /* Resources */,
0A185F0CAE96B33A4CD91B6A /* [CP] Embed Pods Frameworks */,
793D0533290528B7C0E17CAD /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
3274F6041D9A633A005282E4 /* PBXTargetDependency */,
);
name = OLMKitTests;
productName = OLMKitTests;
productReference = 3274F6011D9A633A005282E4 /* OLMKitTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
3274F5EF1D9A633A005282E4 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0810;
ORGANIZATIONNAME = matrix.org;
TargetAttributes = {
3274F5F71D9A633A005282E4 = {
CreatedOnToolsVersion = 8.0;
ProvisioningStyle = Automatic;
};
3274F6001D9A633A005282E4 = {
CreatedOnToolsVersion = 8.0;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 3274F5F21D9A633A005282E4 /* Build configuration list for PBXProject "OLMKit" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 3274F5EE1D9A633A005282E4;
productRefGroup = 3274F5F91D9A633A005282E4 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
3274F5F71D9A633A005282E4 /* OLMKit */,
3274F6001D9A633A005282E4 /* OLMKitTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
3274F5F61D9A633A005282E4 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
3274F5FF1D9A633A005282E4 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
0A185F0CAE96B33A4CD91B6A /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-OLMKitTests/Pods-OLMKitTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
30F93582035CD30D211A6C76 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-OLMKit/Pods-OLMKit-resources.sh\"\n";
showEnvVarsInLog = 0;
};
47E69E5BE6A019858DC41D4F /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
793D0533290528B7C0E17CAD /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-OLMKitTests/Pods-OLMKitTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
7FBCB292198F4156D9CA3B8D /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
3274F5F31D9A633A005282E4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
3274F5FD1D9A633A005282E4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3274F6071D9A633A005282E4 /* OLMKitTests.m in Sources */,
32A151311DABDD4300400192 /* OLMKitGroupTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
3274F6041D9A633A005282E4 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 3274F5F71D9A633A005282E4 /* OLMKit */;
targetProxy = 3274F6031D9A633A005282E4 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
3274F60A1D9A633B005282E4 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
3274F60B1D9A633B005282E4 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
3274F60D1D9A633B005282E4 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = E50E6B16E3433A5EB3297DEE /* Pods-OLMKit.debug.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = OLMKit/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = org.matrix.OLMKit;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Debug;
};
3274F60E1D9A633B005282E4 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 1B226B371526F2782C9D6372 /* Pods-OLMKit.release.xcconfig */;
buildSettings = {
CODE_SIGN_IDENTITY = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = OLMKit/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = org.matrix.OLMKit;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Release;
};
3274F6101D9A633B005282E4 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 875BA7A520258EA15A31DD82 /* Pods-OLMKitTests.debug.xcconfig */;
buildSettings = {
INFOPLIST_FILE = OLMKitTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = org.matrix.OLMKitTests;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
3274F6111D9A633B005282E4 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D48E486DAE1F59F4F7EA8C25 /* Pods-OLMKitTests.release.xcconfig */;
buildSettings = {
INFOPLIST_FILE = OLMKitTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = org.matrix.OLMKitTests;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
3274F5F21D9A633A005282E4 /* Build configuration list for PBXProject "OLMKit" */ = {
isa = XCConfigurationList;
buildConfigurations = (
3274F60A1D9A633B005282E4 /* Debug */,
3274F60B1D9A633B005282E4 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
3274F60C1D9A633B005282E4 /* Build configuration list for PBXNativeTarget "OLMKit" */ = {
isa = XCConfigurationList;
buildConfigurations = (
3274F60D1D9A633B005282E4 /* Debug */,
3274F60E1D9A633B005282E4 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
3274F60F1D9A633B005282E4 /* Build configuration list for PBXNativeTarget "OLMKitTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
3274F6101D9A633B005282E4 /* Debug */,
3274F6111D9A633B005282E4 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 3274F5EF1D9A633A005282E4 /* Project object */;
}

26
xcode/OLMKit/Info.plist Normal file
View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

51
xcode/OLMKit/OLMAccount.h Normal file
View file

@ -0,0 +1,51 @@
/*
Copyright 2016 Chris Ballinger
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <Foundation/Foundation.h>
#import "OLMSerializable.h"
@class OLMSession;
@interface OLMAccount : NSObject <OLMSerializable, NSSecureCoding>
/** Creates new account */
- (instancetype) initNewAccount;
/** public identity keys. base64 encoded in "curve25519" and "ed25519" keys */
- (NSDictionary*) identityKeys;
/** signs message with ed25519 key for account */
- (NSString*) signMessage:(NSData*)messageData;
/** Public parts of the unpublished one time keys for the account */
- (NSDictionary*) oneTimeKeys;
- (BOOL) removeOneTimeKeysForSession:(OLMSession*)session;
/** Marks the current set of one time keys as being published. */
- (void) markOneTimeKeysAsPublished;
/** The largest number of one time keys this account can store. */
- (NSUInteger) maxOneTimeKeys;
/** Generates a number of new one time keys. If the total number of keys stored
* by this account exceeds -maxOneTimeKeys then the old keys are
* discarded. */
- (void) generateOneTimeKeys:(NSUInteger)numberOfKeys;
@end

265
xcode/OLMKit/OLMAccount.m Normal file
View file

@ -0,0 +1,265 @@
/*
Copyright 2016 Chris Ballinger
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "OLMAccount.h"
#import "OLMAccount_Private.h"
#import "OLMSession.h"
#import "OLMSession_Private.h"
#import "OLMUtility.h"
@import Security;
@implementation OLMAccount
- (void) dealloc {
olm_clear_account(_account);
free(_account);
}
- (BOOL) initializeAccountMemory {
size_t accountSize = olm_account_size();
_account = malloc(accountSize);
NSParameterAssert(_account != nil);
if (!_account) {
return NO;
}
_account = olm_account(_account);
NSParameterAssert(_account != nil);
if (!_account) {
return NO;
}
return YES;
}
- (instancetype) init {
self = [super init];
if (!self) {
return nil;
}
BOOL success = [self initializeAccountMemory];
if (!success) {
return nil;
}
return self;
}
- (instancetype) initNewAccount {
self = [self init];
if (!self) {
return nil;
}
size_t randomLength = olm_create_account_random_length(_account);
NSMutableData *random = [OLMUtility randomBytesOfLength:randomLength];
size_t accountResult = olm_create_account(_account, random.mutableBytes, random.length);
[random resetBytesInRange:NSMakeRange(0, random.length)];
if (accountResult == olm_error()) {
const char *error = olm_account_last_error(_account);
NSLog(@"error creating account: %s", error);
return nil;
}
return self;
}
- (NSUInteger) maxOneTimeKeys {
return olm_account_max_number_of_one_time_keys(_account);
}
/** public identity keys */
- (NSDictionary*) identityKeys {
size_t identityKeysLength = olm_account_identity_keys_length(_account);
uint8_t *identityKeysBytes = malloc(identityKeysLength);
if (!identityKeysBytes) {
return nil;
}
size_t result = olm_account_identity_keys(_account, identityKeysBytes, identityKeysLength);
if (result == olm_error()) {
const char *error = olm_account_last_error(_account);
NSLog(@"error getting id keys: %s", error);
free(identityKeysBytes);
return nil;
}
NSData *idKeyData = [NSData dataWithBytesNoCopy:identityKeysBytes length:identityKeysLength freeWhenDone:YES];
NSError *error = nil;
NSDictionary *keysDictionary = [NSJSONSerialization JSONObjectWithData:idKeyData options:0 error:&error];
if (error) {
NSLog(@"Could not decode JSON: %@", error.localizedDescription);
}
return keysDictionary;
}
- (NSString *)signMessage:(NSData *)messageData {
size_t signatureLength = olm_account_signature_length(_account);
uint8_t *signatureBytes = malloc(signatureLength);
if (!signatureBytes) {
return nil;
}
size_t result = olm_account_sign(_account, messageData.bytes, messageData.length, signatureBytes, signatureLength);
if (result == olm_error()) {
const char *error = olm_account_last_error(_account);
NSLog(@"error signing message: %s", error);
free(signatureBytes);
return nil;
}
NSData *signatureData = [NSData dataWithBytesNoCopy:signatureBytes length:signatureLength freeWhenDone:YES];
return [[NSString alloc] initWithData:signatureData encoding:NSUTF8StringEncoding];
}
- (NSDictionary*) oneTimeKeys {
size_t otkLength = olm_account_one_time_keys_length(_account);
uint8_t *otkBytes = malloc(otkLength);
if (!otkBytes) {
return nil;
}
size_t result = olm_account_one_time_keys(_account, otkBytes, otkLength);
if (result == olm_error()) {
const char *error = olm_account_last_error(_account);
NSLog(@"error getting id keys: %s", error);
free(otkBytes);
}
NSData *otk = [NSData dataWithBytesNoCopy:otkBytes length:otkLength freeWhenDone:YES];
NSError *error = nil;
NSDictionary *keysDictionary = [NSJSONSerialization JSONObjectWithData:otk options:0 error:&error];
if (error) {
NSLog(@"Could not decode JSON: %@", error.localizedDescription);
}
return keysDictionary;
}
- (void) generateOneTimeKeys:(NSUInteger)numberOfKeys {
size_t randomLength = olm_account_generate_one_time_keys_random_length(_account, numberOfKeys);
NSMutableData *random = [OLMUtility randomBytesOfLength:randomLength];
size_t result = olm_account_generate_one_time_keys(_account, numberOfKeys, random.mutableBytes, random.length);
[random resetBytesInRange:NSMakeRange(0, random.length)];
if (result == olm_error()) {
const char *error = olm_account_last_error(_account);
NSLog(@"error generating keys: %s", error);
}
}
- (BOOL) removeOneTimeKeysForSession:(OLMSession *)session {
NSParameterAssert(session != nil);
if (!session) {
return NO;
}
size_t result = olm_remove_one_time_keys(self.account, session.session);
if (result == olm_error()) {
const char *error = olm_account_last_error(_account);
NSLog(@"olm_remove_one_time_keys error: %s", error);
return NO;
}
return YES;
}
- (void)markOneTimeKeysAsPublished
{
olm_account_mark_keys_as_published(self.account);
}
#pragma mark OLMSerializable
/** Initializes from encrypted serialized data. Will throw error if invalid key or invalid base64. */
- (instancetype) initWithSerializedData:(NSString*)serializedData key:(NSData*)key error:(NSError**)error {
self = [self init];
if (!self) {
return nil;
}
NSParameterAssert(key.length > 0);
NSParameterAssert(serializedData.length > 0);
if (key.length == 0 || serializedData.length == 0) {
if (error) {
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"Bad length."}];
}
return nil;
}
NSMutableData *pickle = [serializedData dataUsingEncoding:NSUTF8StringEncoding].mutableCopy;
size_t result = olm_unpickle_account(_account, key.bytes, key.length, pickle.mutableBytes, pickle.length);
if (result == olm_error()) {
const char *olm_error = olm_account_last_error(_account);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
if (error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
}
return nil;
}
return self;
}
/** Serializes and encrypts object data, outputs base64 blob */
- (NSString*) serializeDataWithKey:(NSData*)key error:(NSError**)error {
NSParameterAssert(key.length > 0);
size_t length = olm_pickle_account_length(_account);
NSMutableData *pickled = [NSMutableData dataWithLength:length];
size_t result = olm_pickle_account(_account, key.bytes, key.length, pickled.mutableBytes, pickled.length);
if (result == olm_error()) {
const char *olm_error = olm_account_last_error(_account);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
if (error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
}
return nil;
}
NSString *pickleString = [[NSString alloc] initWithData:pickled encoding:NSUTF8StringEncoding];
return pickleString;
}
#pragma mark NSSecureCoding
+ (BOOL) supportsSecureCoding {
return YES;
}
#pragma mark NSCoding
- (id)initWithCoder:(NSCoder *)decoder {
NSString *version = [decoder decodeObjectOfClass:[NSString class] forKey:@"version"];
NSError *error = nil;
if ([version isEqualToString:@"1"]) {
NSString *pickle = [decoder decodeObjectOfClass:[NSString class] forKey:@"pickle"];
NSData *key = [decoder decodeObjectOfClass:[NSData class] forKey:@"key"];
self = [self initWithSerializedData:pickle key:key error:&error];
}
NSParameterAssert(error == nil);
NSParameterAssert(self != nil);
if (!self) {
return nil;
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
NSData *key = [OLMUtility randomBytesOfLength:32];
NSError *error = nil;
NSString *pickle = [self serializeDataWithKey:key error:&error];
NSParameterAssert(pickle.length > 0 && error == nil);
[encoder encodeObject:pickle forKey:@"pickle"];
[encoder encodeObject:key forKey:@"key"];
[encoder encodeObject:@"1" forKey:@"version"];
}
@end

View file

@ -0,0 +1,25 @@
/*
Copyright 2016 Chris Ballinger
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "olm/olm.h"
@interface OLMAccount()
@property (nonatomic) OlmAccount *account;
@end

View file

@ -0,0 +1,30 @@
/*
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <Foundation/Foundation.h>
#import "OLMSerializable.h"
@interface OLMInboundGroupSession : NSObject <OLMSerializable, NSSecureCoding>
- (instancetype) initInboundGroupSessionWithSessionKey:(NSString*)sessionKey error:(NSError**)error;
- (NSString*)sessionIdentifier;
/** base64 ciphertext -> UTF-8 plaintext */
- (NSString*)decryptMessage:(NSString*)message messageIndex:(NSUInteger*)messageIndex error:(NSError**)error;
@end

View file

@ -0,0 +1,244 @@
/*
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "OLMInboundGroupSession.h"
#import "OLMUtility.h"
#include "olm/olm.h"
@interface OLMInboundGroupSession ()
{
OlmInboundGroupSession *session;
}
@end
@implementation OLMInboundGroupSession
- (void)dealloc {
olm_clear_inbound_group_session(session);
free(session);
}
- (instancetype)init {
self = [super init];
if (self)
{
session = malloc(olm_inbound_group_session_size());
if (session) {
session = olm_inbound_group_session(session);
}
if (!session) {
return nil;
}
}
return self;
}
- (instancetype)initInboundGroupSessionWithSessionKey:(NSString *)sessionKey error:(NSError**)error {
self = [self init];
if (self) {
NSData *sessionKeyData = [sessionKey dataUsingEncoding:NSUTF8StringEncoding];
size_t result = olm_init_inbound_group_session(session, sessionKeyData.bytes, sessionKeyData.length);
if (result == olm_error()) {
const char *olm_error = olm_inbound_group_session_last_error(session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
NSLog(@"olm_init_inbound_group_session error: %@", errorString);
if (error && olm_error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain
code:0
userInfo:@{
NSLocalizedDescriptionKey: errorString,
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_init_inbound_group_session error: %@", errorString]
}];
}
return nil;
}
}
return self;
}
- (NSString *)sessionIdentifier {
size_t length = olm_inbound_group_session_id_length(session);
NSMutableData *idData = [NSMutableData dataWithLength:length];
if (!idData) {
return nil;
}
size_t result = olm_inbound_group_session_id(session, idData.mutableBytes, idData.length);
if (result == olm_error()) {
const char *error = olm_inbound_group_session_last_error(session);
NSLog(@"olm_inbound_group_session_id error: %s", error);
return nil;
}
NSString *idString = [[NSString alloc] initWithData:idData encoding:NSUTF8StringEncoding];
return idString;
}
- (NSString *)decryptMessage:(NSString *)message messageIndex:(NSUInteger*)messageIndex error:(NSError**)error
{
NSParameterAssert(message != nil);
NSData *messageData = [message dataUsingEncoding:NSUTF8StringEncoding];
if (!messageData) {
return nil;
}
NSMutableData *mutMessage = messageData.mutableCopy;
size_t maxPlaintextLength = olm_group_decrypt_max_plaintext_length(session, mutMessage.mutableBytes, mutMessage.length);
if (maxPlaintextLength == olm_error()) {
const char *olm_error = olm_inbound_group_session_last_error(session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
NSLog(@"olm_group_decrypt_max_plaintext_length error: %@", errorString);
if (error && olm_error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain
code:0
userInfo:@{
NSLocalizedDescriptionKey: errorString,
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_group_decrypt_max_plaintext_length error: %@", errorString]
}];
}
return nil;
}
// message buffer is destroyed by olm_group_decrypt_max_plaintext_length
mutMessage = messageData.mutableCopy;
NSMutableData *plaintextData = [NSMutableData dataWithLength:maxPlaintextLength];
uint32_t message_index;
size_t plaintextLength = olm_group_decrypt(session, mutMessage.mutableBytes, mutMessage.length, plaintextData.mutableBytes, plaintextData.length, &message_index);
if (plaintextLength == olm_error()) {
const char *olm_error = olm_inbound_group_session_last_error(session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
NSLog(@"olm_group_decrypt error: %@", errorString);
if (error && olm_error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain
code:0
userInfo:@{
NSLocalizedDescriptionKey: errorString,
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_group_decrypt error: %@", errorString]
}];
}
return nil;
}
plaintextData.length = plaintextLength;
NSString *plaintext = [[NSString alloc] initWithData:plaintextData encoding:NSUTF8StringEncoding];
[plaintextData resetBytesInRange:NSMakeRange(0, plaintextData.length)];
if (messageIndex)
{
*messageIndex = message_index;
}
return plaintext;
}
#pragma mark OLMSerializable
/** Initializes from encrypted serialized data. Will throw error if invalid key or invalid base64. */
- (instancetype) initWithSerializedData:(NSString *)serializedData key:(NSData *)key error:(NSError *__autoreleasing *)error {
self = [self init];
if (!self) {
return nil;
}
NSParameterAssert(key.length > 0);
NSParameterAssert(serializedData.length > 0);
if (key.length == 0 || serializedData.length == 0) {
if (error) {
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"Bad length."}];
}
return nil;
}
NSMutableData *pickle = [serializedData dataUsingEncoding:NSUTF8StringEncoding].mutableCopy;
size_t result = olm_unpickle_inbound_group_session(session, key.bytes, key.length, pickle.mutableBytes, pickle.length);
if (result == olm_error()) {
const char *olm_error = olm_inbound_group_session_last_error(session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
if (error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
}
return nil;
}
return self;
}
/** Serializes and encrypts object data, outputs base64 blob */
- (NSString*) serializeDataWithKey:(NSData*)key error:(NSError**)error {
NSParameterAssert(key.length > 0);
size_t length = olm_pickle_inbound_group_session_length(session);
NSMutableData *pickled = [NSMutableData dataWithLength:length];
size_t result = olm_pickle_inbound_group_session(session, key.bytes, key.length, pickled.mutableBytes, pickled.length);
if (result == olm_error()) {
const char *olm_error = olm_inbound_group_session_last_error(session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
if (error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
}
return nil;
}
NSString *pickleString = [[NSString alloc] initWithData:pickled encoding:NSUTF8StringEncoding];
return pickleString;
}
#pragma mark NSSecureCoding
+ (BOOL) supportsSecureCoding {
return YES;
}
#pragma mark NSCoding
- (id)initWithCoder:(NSCoder *)decoder {
NSString *version = [decoder decodeObjectOfClass:[NSString class] forKey:@"version"];
NSError *error = nil;
if ([version isEqualToString:@"1"]) {
NSString *pickle = [decoder decodeObjectOfClass:[NSString class] forKey:@"pickle"];
NSData *key = [decoder decodeObjectOfClass:[NSData class] forKey:@"key"];
self = [self initWithSerializedData:pickle key:key error:&error];
}
NSParameterAssert(error == nil);
NSParameterAssert(self != nil);
if (!self) {
return nil;
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
NSData *key = [OLMUtility randomBytesOfLength:32];
NSError *error = nil;
NSString *pickle = [self serializeDataWithKey:key error:&error];
NSParameterAssert(pickle.length > 0 && error == nil);
[encoder encodeObject:pickle forKey:@"pickle"];
[encoder encodeObject:key forKey:@"key"];
[encoder encodeObject:@"1" forKey:@"version"];
}
@end

31
xcode/OLMKit/OLMKit.h Normal file
View file

@ -0,0 +1,31 @@
/*
Copyright 2016 Chris Ballinger
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <UIKit/UIKit.h>
//! Project version string for OLMKit, the same as libolm.
NSString *OLMKitVersionString();
// In this header, you should import all the public headers of your framework using statements like #import <OLMKit/PublicHeader.h>
#import <OLMKit/OLMAccount.h>
#import <OLMKit/OLMSession.h>
#import <OLMKit/OLMMessage.h>
#import <OLMKit/OLMUtility.h>
#import <OLMKit/OLMInboundGroupSession.h>
#import <OLMKit/OLMOutboundGroupSession.h>

29
xcode/OLMKit/OLMKit.m Normal file
View file

@ -0,0 +1,29 @@
/*
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "OLMKit.h"
#include "olm/olm.h"
NSString *OLMKitVersionString()
{
uint8_t major, minor, patch;
olm_get_library_version(&major, &minor, &patch);
return [NSString stringWithFormat:@"%tu.%tu.%tu", major, minor, patch];
}

38
xcode/OLMKit/OLMMessage.h Normal file
View file

@ -0,0 +1,38 @@
/*
Copyright 2016 Chris Ballinger
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <Foundation/Foundation.h>
/*
from olm.hh
static const size_t OLM_MESSAGE_TYPE_PRE_KEY = 0;
static const size_t OLM_MESSAGE_TYPE_MESSAGE = 1;
*/
typedef NS_ENUM(NSInteger, OLMMessageType) {
OLMMessageTypePreKey = 0,
OLMMessageTypeMessage = 1
};
@interface OLMMessage : NSObject
@property (nonatomic, copy, readonly, nonnull) NSString *ciphertext;
@property (readonly) OLMMessageType type;
- (nullable instancetype) initWithCiphertext:(nonnull NSString*)ciphertext type:(OLMMessageType)type;
@end

34
xcode/OLMKit/OLMMessage.m Normal file
View file

@ -0,0 +1,34 @@
/*
Copyright 2016 Chris Ballinger
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "OLMMessage.h"
@implementation OLMMessage
- (nullable instancetype) initWithCiphertext:(nonnull NSString*)ciphertext type:(OLMMessageType)type {
NSParameterAssert(ciphertext != nil);
self = [super init];
if (!self) {
return nil;
}
_ciphertext = [ciphertext copy];
_type = type;
return self;
}
@end

View file

@ -0,0 +1,32 @@
/*
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <Foundation/Foundation.h>
#import "OLMSerializable.h"
@interface OLMOutboundGroupSession : NSObject <OLMSerializable, NSSecureCoding>
- (instancetype) initOutboundGroupSession;
- (NSString*)sessionIdentifier;
- (NSUInteger)messageIndex;
- (NSString*)sessionKey;
/** UTF-8 plaintext -> base64 ciphertext */
- (NSString*)encryptMessage:(NSString*)message error:(NSError**)error;
@end

View file

@ -0,0 +1,220 @@
/*
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "OLMOutboundGroupSession.h"
#import "OLMUtility.h"
#include "olm/olm.h"
@interface OLMOutboundGroupSession ()
{
OlmOutboundGroupSession *session;
}
@end
@implementation OLMOutboundGroupSession
- (void)dealloc {
olm_clear_outbound_group_session(session);
free(session);
}
- (instancetype)init {
self = [super init];
if (self)
{
session = malloc(olm_outbound_group_session_size());
if (session) {
session = olm_outbound_group_session(session);
}
if (!session) {
return nil;
}
}
return self;
}
- (instancetype)initOutboundGroupSession {
self = [self init];
if (self) {
NSMutableData *random = [OLMUtility randomBytesOfLength:olm_init_outbound_group_session_random_length(session)];
size_t result = olm_init_outbound_group_session(session, random.mutableBytes, random.length);
[random resetBytesInRange:NSMakeRange(0, random.length)];
if (result == olm_error()) {
const char *error = olm_outbound_group_session_last_error(session);
NSLog(@"olm_init_outbound_group_session error: %s", error);
return nil;
}
}
return self;
}
- (NSString *)sessionIdentifier {
size_t length = olm_outbound_group_session_id_length(session);
NSMutableData *idData = [NSMutableData dataWithLength:length];
if (!idData) {
return nil;
}
size_t result = olm_outbound_group_session_id(session, idData.mutableBytes, idData.length);
if (result == olm_error()) {
const char *error = olm_outbound_group_session_last_error(session);
NSLog(@"olm_outbound_group_session_id error: %s", error);
return nil;
}
NSString *idString = [[NSString alloc] initWithData:idData encoding:NSUTF8StringEncoding];
return idString;
}
- (NSUInteger)messageIndex {
return olm_outbound_group_session_message_index(session);
}
- (NSString *)sessionKey {
size_t length = olm_outbound_group_session_key_length(session);
NSMutableData *sessionKeyData = [NSMutableData dataWithLength:length];
if (!sessionKeyData) {
return nil;
}
size_t result = olm_outbound_group_session_key(session, sessionKeyData.mutableBytes, sessionKeyData.length);
if (result == olm_error()) {
const char *error = olm_outbound_group_session_last_error(session);
NSLog(@"olm_outbound_group_session_key error: %s", error);
return nil;
}
NSString *sessionKey = [[NSString alloc] initWithData:sessionKeyData encoding:NSUTF8StringEncoding];
[sessionKeyData resetBytesInRange:NSMakeRange(0, sessionKeyData.length)];
return sessionKey;
}
- (NSString *)encryptMessage:(NSString *)message error:(NSError**)error {
NSData *plaintextData = [message dataUsingEncoding:NSUTF8StringEncoding];
size_t ciphertextLength = olm_group_encrypt_message_length(session, plaintextData.length);
NSMutableData *ciphertext = [NSMutableData dataWithLength:ciphertextLength];
if (!ciphertext) {
return nil;
}
size_t result = olm_group_encrypt(session, plaintextData.bytes, plaintextData.length, ciphertext.mutableBytes, ciphertext.length);
if (result == olm_error()) {
const char *olm_error = olm_outbound_group_session_last_error(session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
NSLog(@"olm_group_encrypt error: %@", errorString);
if (error && olm_error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain
code:0
userInfo:@{
NSLocalizedDescriptionKey: errorString,
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_group_encrypt error: %@", errorString]
}];
}
return nil;
}
return [[NSString alloc] initWithData:ciphertext encoding:NSUTF8StringEncoding];
}
#pragma mark OLMSerializable
/** Initializes from encrypted serialized data. Will throw error if invalid key or invalid base64. */
- (instancetype) initWithSerializedData:(NSString *)serializedData key:(NSData *)key error:(NSError *__autoreleasing *)error {
self = [self init];
if (!self) {
return nil;
}
NSParameterAssert(key.length > 0);
NSParameterAssert(serializedData.length > 0);
if (key.length == 0 || serializedData.length == 0) {
if (error) {
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"Bad length."}];
}
return nil;
}
NSMutableData *pickle = [serializedData dataUsingEncoding:NSUTF8StringEncoding].mutableCopy;
size_t result = olm_unpickle_outbound_group_session(session, key.bytes, key.length, pickle.mutableBytes, pickle.length);
if (result == olm_error()) {
const char *olm_error = olm_outbound_group_session_last_error(session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
if (error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
}
return nil;
}
return self;
}
/** Serializes and encrypts object data, outputs base64 blob */
- (NSString*) serializeDataWithKey:(NSData*)key error:(NSError**)error {
NSParameterAssert(key.length > 0);
size_t length = olm_pickle_outbound_group_session_length(session);
NSMutableData *pickled = [NSMutableData dataWithLength:length];
size_t result = olm_pickle_outbound_group_session(session, key.bytes, key.length, pickled.mutableBytes, pickled.length);
if (result == olm_error()) {
const char *olm_error = olm_outbound_group_session_last_error(session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
if (error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
}
return nil;
}
NSString *pickleString = [[NSString alloc] initWithData:pickled encoding:NSUTF8StringEncoding];
return pickleString;
}
#pragma mark NSSecureCoding
+ (BOOL) supportsSecureCoding {
return YES;
}
#pragma mark NSCoding
- (id)initWithCoder:(NSCoder *)decoder {
NSString *version = [decoder decodeObjectOfClass:[NSString class] forKey:@"version"];
NSError *error = nil;
if ([version isEqualToString:@"1"]) {
NSString *pickle = [decoder decodeObjectOfClass:[NSString class] forKey:@"pickle"];
NSData *key = [decoder decodeObjectOfClass:[NSData class] forKey:@"key"];
self = [self initWithSerializedData:pickle key:key error:&error];
}
NSParameterAssert(error == nil);
NSParameterAssert(self != nil);
if (!self) {
return nil;
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
NSData *key = [OLMUtility randomBytesOfLength:32];
NSError *error = nil;
NSString *pickle = [self serializeDataWithKey:key error:&error];
NSParameterAssert(pickle.length > 0 && error == nil);
[encoder encodeObject:pickle forKey:@"pickle"];
[encoder encodeObject:key forKey:@"key"];
[encoder encodeObject:@"1" forKey:@"version"];
}
@end

View file

@ -0,0 +1,29 @@
/*
Copyright 2016 Chris Ballinger
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <Foundation/Foundation.h>
@protocol OLMSerializable <NSObject>
/** Initializes from encrypted serialized data. Will throw error if invalid key or invalid base64. */
- (instancetype) initWithSerializedData:(NSString*)serializedData key:(NSData*)key error:(NSError**)error;
/** Serializes and encrypts object data, outputs base64 blob */
- (NSString*) serializeDataWithKey:(NSData*)key error:(NSError**)error;
@end

44
xcode/OLMKit/OLMSession.h Normal file
View file

@ -0,0 +1,44 @@
/*
Copyright 2016 Chris Ballinger
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <Foundation/Foundation.h>
#import "OLMSerializable.h"
#import "OLMAccount.h"
#import "OLMMessage.h"
@interface OLMSession : NSObject <OLMSerializable, NSSecureCoding>
- (instancetype) initOutboundSessionWithAccount:(OLMAccount*)account theirIdentityKey:(NSString*)theirIdentityKey theirOneTimeKey:(NSString*)theirOneTimeKey error:(NSError**)error;
- (instancetype) initInboundSessionWithAccount:(OLMAccount*)account oneTimeKeyMessage:(NSString*)oneTimeKeyMessage error:(NSError**)error;
- (instancetype) initInboundSessionWithAccount:(OLMAccount*)account theirIdentityKey:(NSString*)theirIdentityKey oneTimeKeyMessage:(NSString*)oneTimeKeyMessage error:(NSError**)error;
- (NSString*) sessionIdentifier;
- (BOOL) matchesInboundSession:(NSString*)oneTimeKeyMessage;
- (BOOL) matchesInboundSessionFrom:(NSString*)theirIdentityKey oneTimeKeyMessage:(NSString *)oneTimeKeyMessage;
/** UTF-8 plaintext -> base64 ciphertext */
- (OLMMessage*) encryptMessage:(NSString*)message error:(NSError**)error;
/** base64 ciphertext -> UTF-8 plaintext */
- (NSString*) decryptMessage:(OLMMessage*)message error:(NSError**)error;
@end

381
xcode/OLMKit/OLMSession.m Normal file
View file

@ -0,0 +1,381 @@
/*
Copyright 2016 Chris Ballinger
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "OLMSession.h"
#import "OLMUtility.h"
#import "OLMAccount_Private.h"
#import "OLMSession_Private.h"
#include "olm/olm.h"
@implementation OLMSession
- (void) dealloc {
olm_clear_session(_session);
free(_session);
}
- (BOOL) initializeSessionMemory {
size_t size = olm_session_size();
_session = malloc(size);
NSParameterAssert(_session != nil);
if (!_session) {
return NO;
}
_session = olm_session(_session);
NSParameterAssert(_session != nil);
if (!_session) {
return NO;
}
return YES;
}
- (instancetype) init {
self = [super init];
if (!self) {
return nil;
}
BOOL success = [self initializeSessionMemory];
if (!success) {
return nil;
}
return self;
}
- (instancetype) initWithAccount:(OLMAccount*)account {
self = [self init];
if (!self) {
return nil;
}
NSParameterAssert(account != nil && account.account != NULL);
if (account == nil || account.account == NULL) {
return nil;
}
_account = account;
return self;
}
- (instancetype) initOutboundSessionWithAccount:(OLMAccount*)account theirIdentityKey:(NSString*)theirIdentityKey theirOneTimeKey:(NSString*)theirOneTimeKey error:(NSError**)error {
self = [self initWithAccount:account];
if (!self) {
return nil;
}
NSMutableData *random = [OLMUtility randomBytesOfLength:olm_create_outbound_session_random_length(_session)];
NSData *idKey = [theirIdentityKey dataUsingEncoding:NSUTF8StringEncoding];
NSData *otKey = [theirOneTimeKey dataUsingEncoding:NSUTF8StringEncoding];
size_t result = olm_create_outbound_session(_session, account.account, idKey.bytes, idKey.length, otKey.bytes, otKey.length, random.mutableBytes, random.length);
[random resetBytesInRange:NSMakeRange(0, random.length)];
if (result == olm_error()) {
const char *olm_error = olm_session_last_error(_session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
NSLog(@"olm_create_outbound_session error: %@", errorString);
if (error && olm_error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain
code:0
userInfo:@{
NSLocalizedDescriptionKey: errorString,
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_create_outbound_session error: %@", errorString]
}];
}
return nil;
}
return self;
}
- (instancetype) initInboundSessionWithAccount:(OLMAccount*)account oneTimeKeyMessage:(NSString*)oneTimeKeyMessage error:(NSError**)error {
self = [self initWithAccount:account];
if (!self) {
return nil;
}
NSMutableData *otk = [NSMutableData dataWithData:[oneTimeKeyMessage dataUsingEncoding:NSUTF8StringEncoding]];
size_t result = olm_create_inbound_session(_session, account.account, otk.mutableBytes, oneTimeKeyMessage.length);
if (result == olm_error()) {
const char *olm_error = olm_session_last_error(_session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
NSLog(@"olm_create_inbound_session error: %@", errorString);
if (error && olm_error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain
code:0
userInfo:@{
NSLocalizedDescriptionKey: errorString,
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_create_inbound_session error: %@", errorString]
}];
}
return nil;
}
return self;
}
- (instancetype) initInboundSessionWithAccount:(OLMAccount*)account theirIdentityKey:(NSString*)theirIdentityKey oneTimeKeyMessage:(NSString*)oneTimeKeyMessage error:(NSError**)error {
self = [self initWithAccount:account];
if (!self) {
return nil;
}
NSData *idKey = [theirIdentityKey dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *otk = [NSMutableData dataWithData:[oneTimeKeyMessage dataUsingEncoding:NSUTF8StringEncoding]];
size_t result = olm_create_inbound_session_from(_session, account.account, idKey.bytes, idKey.length, otk.mutableBytes, otk.length);
if (result == olm_error()) {
const char *olm_error = olm_session_last_error(_session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
NSLog(@"olm_create_inbound_session_from error: %@", errorString);
if (error && olm_error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain
code:0
userInfo:@{
NSLocalizedDescriptionKey: errorString,
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_create_inbound_session_from error: %@", errorString]
}];
}
return nil;
}
return self;
}
- (NSString*) sessionIdentifier {
size_t length = olm_session_id_length(_session);
NSMutableData *idData = [NSMutableData dataWithLength:length];
if (!idData) {
return nil;
}
size_t result = olm_session_id(_session, idData.mutableBytes, idData.length);
if (result == olm_error()) {
const char *error = olm_session_last_error(_session);
NSLog(@"olm_session_id error: %s", error);
return nil;
}
NSString *idString = [[NSString alloc] initWithData:idData encoding:NSUTF8StringEncoding];
return idString;
}
- (BOOL)matchesInboundSession:(NSString *)oneTimeKeyMessage {
NSMutableData *otk = [NSMutableData dataWithData:[oneTimeKeyMessage dataUsingEncoding:NSUTF8StringEncoding]];
size_t result = olm_matches_inbound_session(_session, otk.mutableBytes, otk.length);
if (result == 1) {
return YES;
}
else {
if (result == olm_error()) {
const char *error = olm_session_last_error(_session);
NSLog(@"olm_matches_inbound_session error: %s", error);
}
return NO;
}
}
- (BOOL)matchesInboundSessionFrom:(NSString *)theirIdentityKey oneTimeKeyMessage:(NSString *)oneTimeKeyMessage {
NSData *idKey = [theirIdentityKey dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *otk = [NSMutableData dataWithData:[oneTimeKeyMessage dataUsingEncoding:NSUTF8StringEncoding]];
size_t result = olm_matches_inbound_session_from(_session,
idKey.bytes, idKey.length,
otk.mutableBytes, otk.length);
if (result == 1) {
return YES;
}
else {
if (result == olm_error()) {
const char *error = olm_session_last_error(_session);
NSLog(@"olm_matches_inbound_session error: %s", error);
}
return NO;
}
}
- (OLMMessage*) encryptMessage:(NSString*)message error:(NSError**)error {
size_t messageType = olm_encrypt_message_type(_session);
size_t randomLength = olm_encrypt_random_length(_session);
NSMutableData *random = [OLMUtility randomBytesOfLength:randomLength];
NSData *plaintextData = [message dataUsingEncoding:NSUTF8StringEncoding];
size_t ciphertextLength = olm_encrypt_message_length(_session, plaintextData.length);
NSMutableData *ciphertext = [NSMutableData dataWithLength:ciphertextLength];
if (!ciphertext) {
return nil;
}
size_t result = olm_encrypt(_session, plaintextData.bytes, plaintextData.length, random.mutableBytes, random.length, ciphertext.mutableBytes, ciphertext.length);
[random resetBytesInRange:NSMakeRange(0, random.length)];
if (result == olm_error()) {
const char *olm_error = olm_session_last_error(_session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
NSLog(@"olm_encrypt error: %@", errorString);
if (error && olm_error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain
code:0
userInfo:@{
NSLocalizedDescriptionKey: errorString,
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_encrypt error: %@", errorString]
}];
}
return nil;
}
NSString *ciphertextString = [[NSString alloc] initWithData:ciphertext encoding:NSUTF8StringEncoding];
OLMMessage *encryptedMessage = [[OLMMessage alloc] initWithCiphertext:ciphertextString type:messageType];
return encryptedMessage;
}
- (NSString*) decryptMessage:(OLMMessage*)message error:(NSError**)error {
NSParameterAssert(message != nil);
NSData *messageData = [message.ciphertext dataUsingEncoding:NSUTF8StringEncoding];
if (!messageData) {
return nil;
}
NSMutableData *mutMessage = messageData.mutableCopy;
size_t maxPlaintextLength = olm_decrypt_max_plaintext_length(_session, message.type, mutMessage.mutableBytes, mutMessage.length);
if (maxPlaintextLength == olm_error()) {
const char *olm_error = olm_session_last_error(_session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
NSLog(@"olm_decrypt_max_plaintext_length error: %@", errorString);
if (error && olm_error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain
code:0
userInfo:@{
NSLocalizedDescriptionKey: errorString,
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_decrypt_max_plaintext_length error: %@", errorString]
}];
}
return nil;
}
// message buffer is destroyed by olm_decrypt_max_plaintext_length
mutMessage = messageData.mutableCopy;
NSMutableData *plaintextData = [NSMutableData dataWithLength:maxPlaintextLength];
size_t plaintextLength = olm_decrypt(_session, message.type, mutMessage.mutableBytes, mutMessage.length, plaintextData.mutableBytes, plaintextData.length);
if (plaintextLength == olm_error()) {
const char *olm_error = olm_session_last_error(_session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
NSLog(@"olm_decrypt error: %@", errorString);
if (error && olm_error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain
code:0
userInfo:@{
NSLocalizedDescriptionKey: errorString,
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_decrypt error: %@", errorString]
}];
}
return nil;
}
plaintextData.length = plaintextLength;
NSString *plaintext = [[NSString alloc] initWithData:plaintextData encoding:NSUTF8StringEncoding];
[plaintextData resetBytesInRange:NSMakeRange(0, plaintextData.length)];
return plaintext;
}
#pragma mark OLMSerializable
/** Initializes from encrypted serialized data. Will throw error if invalid key or invalid base64. */
- (instancetype) initWithSerializedData:(NSString*)serializedData key:(NSData*)key error:(NSError**)error {
self = [self init];
if (!self) {
return nil;
}
NSParameterAssert(key.length > 0);
NSParameterAssert(serializedData.length > 0);
if (key.length == 0 || serializedData.length == 0) {
if (error) {
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"Bad length."}];
}
return nil;
}
NSMutableData *pickle = [serializedData dataUsingEncoding:NSUTF8StringEncoding].mutableCopy;
size_t result = olm_unpickle_session(_session, key.bytes, key.length, pickle.mutableBytes, pickle.length);
if (result == olm_error()) {
const char *olm_error = olm_session_last_error(_session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
if (error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
}
return nil;
}
return self;
}
/** Serializes and encrypts object data, outputs base64 blob */
- (NSString*) serializeDataWithKey:(NSData*)key error:(NSError**)error {
NSParameterAssert(key.length > 0);
size_t length = olm_pickle_session_length(_session);
NSMutableData *pickled = [NSMutableData dataWithLength:length];
size_t result = olm_pickle_session(_session, key.bytes, key.length, pickled.mutableBytes, pickled.length);
if (result == olm_error()) {
const char *olm_error = olm_session_last_error(_session);
NSString *errorString = [NSString stringWithUTF8String:olm_error];
if (error && errorString) {
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
}
return nil;
}
NSString *pickleString = [[NSString alloc] initWithData:pickled encoding:NSUTF8StringEncoding];
return pickleString;
}
#pragma mark NSSecureCoding
+ (BOOL) supportsSecureCoding {
return YES;
}
#pragma mark NSCoding
- (id)initWithCoder:(NSCoder *)decoder {
NSString *version = [decoder decodeObjectOfClass:[NSString class] forKey:@"version"];
NSError *error = nil;
if ([version isEqualToString:@"1"]) {
NSString *pickle = [decoder decodeObjectOfClass:[NSString class] forKey:@"pickle"];
NSData *key = [decoder decodeObjectOfClass:[NSData class] forKey:@"key"];
self = [self initWithSerializedData:pickle key:key error:&error];
}
NSParameterAssert(error == nil);
NSParameterAssert(self != nil);
if (!self) {
return nil;
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
NSData *key = [OLMUtility randomBytesOfLength:32];
NSError *error = nil;
NSString *pickle = [self serializeDataWithKey:key error:&error];
NSParameterAssert(pickle.length > 0 && error == nil);
[encoder encodeObject:pickle forKey:@"pickle"];
[encoder encodeObject:key forKey:@"key"];
[encoder encodeObject:@"1" forKey:@"version"];
}
@end

View file

@ -0,0 +1,26 @@
/*
Copyright 2016 Chris Ballinger
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "olm/olm.h"
@interface OLMSession()
@property (nonatomic) OlmSession *session;
@property (nonatomic, strong) OLMAccount *account;
@end

49
xcode/OLMKit/OLMUtility.h Normal file
View file

@ -0,0 +1,49 @@
/*
Copyright 2016 Chris Ballinger
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <Foundation/Foundation.h>
FOUNDATION_EXPORT NSString *const OLMErrorDomain;
@interface OLMUtility : NSObject
/**
Calculate the SHA-256 hash of the input and encodes it as base64.
@param message the message to hash.
@return the base64-encoded hash value.
*/
- (NSString*)sha256:(NSData*)message;
/**
Verify an ed25519 signature.
@param signature the base64-encoded signature to be checked.
@param key the ed25519 key.
@param message the message which was signed.
@param the result error if there is a problem with the verification.
If the key was too small then the message will be "OLM.INVALID_BASE64".
If the signature was invalid then the message will be "OLM.BAD_MESSAGE_MAC".
@return YES if valid.
*/
- (BOOL)verifyEd25519Signature:(NSString*)signature key:(NSString*)key message:(NSData*)message error:(NSError**)error;
+ (NSMutableData*) randomBytesOfLength:(NSUInteger)length;
@end

121
xcode/OLMKit/OLMUtility.m Normal file
View file

@ -0,0 +1,121 @@
/*
Copyright 2016 Chris Ballinger
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "OLMUtility.h"
#include "olm/olm.h"
NSString *const OLMErrorDomain = @"org.matrix.olm";
@interface OLMUtility()
@property (nonatomic) OlmUtility *utility;
@end
@implementation OLMUtility
- (void) dealloc {
olm_clear_utility(_utility);
free(_utility);
}
- (BOOL) initializeUtilityMemory {
size_t utilitySize = olm_utility_size();
_utility = malloc(utilitySize);
NSParameterAssert(_utility != nil);
if (!_utility) {
return NO;
}
_utility = olm_utility(_utility);
NSParameterAssert(_utility != nil);
if (!_utility) {
return NO;
}
return YES;
}
- (instancetype) init {
self = [super init];
if (!self) {
return nil;
}
BOOL success = [self initializeUtilityMemory];
if (!success) {
return nil;
}
return self;
}
- (NSString *)sha256:(NSData *)message {
size_t length = olm_sha256_length(_utility);
NSMutableData *shaData = [NSMutableData dataWithLength:length];
if (!shaData) {
return nil;
}
size_t result = olm_sha256(_utility, message.bytes, message.length, shaData.mutableBytes, shaData.length);
if (result == olm_error()) {
const char *error = olm_utility_last_error(_utility);
NSLog(@"olm_sha256 error: %s", error);
return nil;
}
NSString *sha = [[NSString alloc] initWithData:shaData encoding:NSUTF8StringEncoding];
return sha;
}
- (BOOL)verifyEd25519Signature:(NSString*)signature key:(NSString*)key message:(NSData*)message error:(NSError**)error {
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
NSData *signatureData = [signature dataUsingEncoding:NSUTF8StringEncoding];
size_t result = olm_ed25519_verify(_utility,
keyData.bytes, keyData.length,
message.bytes, message.length,
(void*)signatureData.bytes, signatureData.length
);
if (result == olm_error()) {
if (error) {
NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey: [NSString stringWithUTF8String:olm_utility_last_error(_utility)]};
// @TODO
*error = [[NSError alloc] initWithDomain:@"OLMKitErrorDomain" code:0 userInfo:userInfo];
}
return NO;
}
else {
return YES;
}
}
+ (NSMutableData*) randomBytesOfLength:(NSUInteger)length {
NSMutableData *randomData = [NSMutableData dataWithLength:length];
if (!randomData) {
return nil;
}
int result = SecRandomCopyBytes(kSecRandomDefault, randomData.length, randomData.mutableBytes);
if (result != 0) {
return nil;
}
return randomData;
}
@end

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View file

@ -0,0 +1,94 @@
/*
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <XCTest/XCTest.h>
#import <OLMKit/OLMKit.h>
#include "olm/olm.h"
@interface OLMKitGroupTests : XCTestCase
@end
@implementation OLMKitGroupTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testAliceAndBob {
NSError *error;
OLMOutboundGroupSession *aliceSession = [[OLMOutboundGroupSession alloc] initOutboundGroupSession];
XCTAssertGreaterThan(aliceSession.sessionIdentifier.length, 0);
XCTAssertGreaterThan(aliceSession.sessionKey.length, 0);
XCTAssertEqual(aliceSession.messageIndex, 0);
// Store the session key before starting encrypting
NSString *sessionKey = aliceSession.sessionKey;
NSString *message = @"Hello!";
NSString *aliceToBobMsg = [aliceSession encryptMessage:message error:&error];
XCTAssertEqual(aliceSession.messageIndex, 1);
XCTAssertGreaterThanOrEqual(aliceToBobMsg.length, 0);
XCTAssertNil(error);
OLMInboundGroupSession *bobSession = [[OLMInboundGroupSession alloc] initInboundGroupSessionWithSessionKey:sessionKey error:&error];
XCTAssertEqualObjects(aliceSession.sessionIdentifier, bobSession.sessionIdentifier);
XCTAssertNil(error);
NSUInteger messageIndex;
NSString *plaintext = [bobSession decryptMessage:aliceToBobMsg messageIndex:&messageIndex error:&error];
XCTAssertEqualObjects(message, plaintext);
XCTAssertEqual(messageIndex, 0);
XCTAssertNil(error);
}
- (void)testOutboundGroupSessionSerialization {
OLMOutboundGroupSession *aliceSession = [[OLMOutboundGroupSession alloc] initOutboundGroupSession];
NSData *aliceData = [NSKeyedArchiver archivedDataWithRootObject:aliceSession];
OLMOutboundGroupSession *aliceSession2 = [NSKeyedUnarchiver unarchiveObjectWithData:aliceData];
XCTAssertEqualObjects(aliceSession2.sessionKey, aliceSession.sessionKey);
XCTAssertEqualObjects(aliceSession2.sessionIdentifier, aliceSession.sessionIdentifier);
}
- (void)testInboundGroupSessionSerialization {
OLMOutboundGroupSession *aliceSession = [[OLMOutboundGroupSession alloc] initOutboundGroupSession];
OLMInboundGroupSession *bobSession = [[OLMInboundGroupSession alloc] initInboundGroupSessionWithSessionKey:aliceSession.sessionKey error:nil];
NSData *bobData = [NSKeyedArchiver archivedDataWithRootObject:bobSession];
OLMInboundGroupSession *bobSession2 = [NSKeyedUnarchiver unarchiveObjectWithData:bobData];
XCTAssertEqualObjects(bobSession2.sessionIdentifier, aliceSession.sessionIdentifier);
}
@end

View file

@ -0,0 +1,206 @@
/*
Copyright 2016 Chris Ballinger
Copyright 2016 OpenMarket Ltd
Copyright 2016 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <XCTest/XCTest.h>
#import <OLMKit/OLMKit.h>
@interface OLMKitTests : XCTestCase
@end
@implementation OLMKitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testAliceAndBob {
NSError *error;
OLMAccount *alice = [[OLMAccount alloc] initNewAccount];
OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
[bob generateOneTimeKeys:5];
NSDictionary *bobIdKeys = bob.identityKeys;
NSString *bobIdKey = bobIdKeys[@"curve25519"];
NSDictionary *bobOneTimeKeys = bob.oneTimeKeys;
NSParameterAssert(bobIdKey != nil);
NSParameterAssert(bobOneTimeKeys != nil);
__block NSString *bobOneTimeKey = nil;
NSDictionary *bobOtkCurve25519 = bobOneTimeKeys[@"curve25519"];
[bobOtkCurve25519 enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
bobOneTimeKey = obj;
}];
XCTAssert([bobOneTimeKey isKindOfClass:[NSString class]]);
OLMSession *aliceSession = [[OLMSession alloc] initOutboundSessionWithAccount:alice theirIdentityKey:bobIdKey theirOneTimeKey:bobOneTimeKey error:nil];
NSString *message = @"Hello!";
OLMMessage *aliceToBobMsg = [aliceSession encryptMessage:message error:&error];
XCTAssertNil(error);
OLMSession *bobSession = [[OLMSession alloc] initInboundSessionWithAccount:bob oneTimeKeyMessage:aliceToBobMsg.ciphertext error:nil];
NSString *plaintext = [bobSession decryptMessage:aliceToBobMsg error:&error];
XCTAssertEqualObjects(message, plaintext);
XCTAssertNil(error);
XCTAssert([bobSession matchesInboundSession:aliceToBobMsg.ciphertext]);
XCTAssertFalse([aliceSession matchesInboundSession:@"ARandomOtkMessage"]);
NSString *aliceIdKey = alice.identityKeys[@"curve25519"];
XCTAssert([bobSession matchesInboundSessionFrom:aliceIdKey oneTimeKeyMessage:aliceToBobMsg.ciphertext]);
XCTAssertFalse([bobSession matchesInboundSessionFrom:@"ARandomIdKey" oneTimeKeyMessage:aliceToBobMsg.ciphertext]);
XCTAssertFalse([bobSession matchesInboundSessionFrom:aliceIdKey oneTimeKeyMessage:@"ARandomOtkMessage"]);
BOOL success = [bob removeOneTimeKeysForSession:bobSession];
XCTAssertTrue(success);
}
- (void) testBackAndForth {
OLMAccount *alice = [[OLMAccount alloc] initNewAccount];
OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
[bob generateOneTimeKeys:1];
NSDictionary *bobIdKeys = bob.identityKeys;
NSString *bobIdKey = bobIdKeys[@"curve25519"];
NSDictionary *bobOneTimeKeys = bob.oneTimeKeys;
NSParameterAssert(bobIdKey != nil);
NSParameterAssert(bobOneTimeKeys != nil);
__block NSString *bobOneTimeKey = nil;
NSDictionary *bobOtkCurve25519 = bobOneTimeKeys[@"curve25519"];
[bobOtkCurve25519 enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
bobOneTimeKey = obj;
}];
XCTAssert([bobOneTimeKey isKindOfClass:[NSString class]]);
OLMSession *aliceSession = [[OLMSession alloc] initOutboundSessionWithAccount:alice theirIdentityKey:bobIdKey theirOneTimeKey:bobOneTimeKey error:nil];
NSString *message = @"Hello I'm Alice!";
OLMMessage *aliceToBobMsg = [aliceSession encryptMessage:message error:nil];
OLMSession *bobSession = [[OLMSession alloc] initInboundSessionWithAccount:bob oneTimeKeyMessage:aliceToBobMsg.ciphertext error:nil];
NSString *plaintext = [bobSession decryptMessage:aliceToBobMsg error:nil];
XCTAssertEqualObjects(message, plaintext);
BOOL success = [bob removeOneTimeKeysForSession:bobSession];
XCTAssertTrue(success);
NSString *msg1 = @"Hello I'm Bob!";
NSString *msg2 = @"Isn't life grand?";
NSString *msg3 = @"Let's go to the opera.";
OLMMessage *eMsg1 = [bobSession encryptMessage:msg1 error:nil];
OLMMessage *eMsg2 = [bobSession encryptMessage:msg2 error:nil];
OLMMessage *eMsg3 = [bobSession encryptMessage:msg3 error:nil];
NSString *dMsg1 = [aliceSession decryptMessage:eMsg1 error:nil];
NSString *dMsg2 = [aliceSession decryptMessage:eMsg2 error:nil];
NSString *dMsg3 = [aliceSession decryptMessage:eMsg3 error:nil];
XCTAssertEqualObjects(msg1, dMsg1);
XCTAssertEqualObjects(msg2, dMsg2);
XCTAssertEqualObjects(msg3, dMsg3);
}
- (void) testAccountSerialization {
OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
[bob generateOneTimeKeys:5];
NSDictionary *bobIdKeys = bob.identityKeys;
NSDictionary *bobOneTimeKeys = bob.oneTimeKeys;
NSData *bobData = [NSKeyedArchiver archivedDataWithRootObject:bob];
OLMAccount *bob2 = [NSKeyedUnarchiver unarchiveObjectWithData:bobData];
NSDictionary *bobIdKeys2 = bob2.identityKeys;
NSDictionary *bobOneTimeKeys2 = bob2.oneTimeKeys;
XCTAssertEqualObjects(bobIdKeys, bobIdKeys2);
XCTAssertEqualObjects(bobOneTimeKeys, bobOneTimeKeys2);
}
- (void) testSessionSerialization {
NSError *error;
OLMAccount *alice = [[OLMAccount alloc] initNewAccount];
OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
[bob generateOneTimeKeys:1];
NSDictionary *bobIdKeys = bob.identityKeys;
NSString *bobIdKey = bobIdKeys[@"curve25519"];
NSDictionary *bobOneTimeKeys = bob.oneTimeKeys;
NSParameterAssert(bobIdKey != nil);
NSParameterAssert(bobOneTimeKeys != nil);
__block NSString *bobOneTimeKey = nil;
NSDictionary *bobOtkCurve25519 = bobOneTimeKeys[@"curve25519"];
[bobOtkCurve25519 enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
bobOneTimeKey = obj;
}];
XCTAssert([bobOneTimeKey isKindOfClass:[NSString class]]);
OLMSession *aliceSession = [[OLMSession alloc] initOutboundSessionWithAccount:alice theirIdentityKey:bobIdKey theirOneTimeKey:bobOneTimeKey error:nil];
NSString *message = @"Hello I'm Alice!";
OLMMessage *aliceToBobMsg = [aliceSession encryptMessage:message error:&error];
XCTAssertNil(error);
OLMSession *bobSession = [[OLMSession alloc] initInboundSessionWithAccount:bob oneTimeKeyMessage:aliceToBobMsg.ciphertext error:nil];
NSString *plaintext = [bobSession decryptMessage:aliceToBobMsg error:nil];
XCTAssertEqualObjects(message, plaintext);
BOOL success = [bob removeOneTimeKeysForSession:bobSession];
XCTAssertTrue(success);
NSString *msg1 = @"Hello I'm Bob!";
NSString *msg2 = @"Isn't life grand?";
NSString *msg3 = @"Let's go to the opera.";
OLMMessage *eMsg1 = [bobSession encryptMessage:msg1 error:nil];
OLMMessage *eMsg2 = [bobSession encryptMessage:msg2 error:nil];
OLMMessage *eMsg3 = [bobSession encryptMessage:msg3 error:nil];
NSData *aliceData = [NSKeyedArchiver archivedDataWithRootObject:aliceSession];
OLMSession *alice2 = [NSKeyedUnarchiver unarchiveObjectWithData:aliceData];
NSString *dMsg1 = [alice2 decryptMessage:eMsg1 error:nil];
NSString *dMsg2 = [alice2 decryptMessage:eMsg2 error:nil];
NSString *dMsg3 = [alice2 decryptMessage:eMsg3 error:nil];
XCTAssertEqualObjects(msg1, dMsg1);
XCTAssertEqualObjects(msg2, dMsg2);
XCTAssertEqualObjects(msg3, dMsg3);
}
- (void)testEd25519Signing {
OLMUtility *olmUtility = [[OLMUtility alloc] init];
OLMAccount *alice = [[OLMAccount alloc] initNewAccount];
NSDictionary *aJSON = @{
@"key1": @"value1",
@"key2": @"value2"
};
NSData *message = [NSKeyedArchiver archivedDataWithRootObject:aJSON];
NSString *signature = [alice signMessage:message];
NSString *aliceEd25519Key = alice.identityKeys[@"ed25519"];
NSError *error;
BOOL result = [olmUtility verifyEd25519Signature:signature key:aliceEd25519Key message:message error:&error];
XCTAssert(result);
XCTAssertNil(error);
}
@end

7
xcode/Podfile Normal file
View file

@ -0,0 +1,7 @@
target "OLMKit" do
pod 'OLMKit', :path => '../OLMKit.podspec'
end
target "OLMKitTests" do
pod 'OLMKit', :path => '../OLMKit.podspec'
end

20
xcode/Podfile.lock Normal file
View file

@ -0,0 +1,20 @@
PODS:
- OLMKit (2.0.1):
- OLMKit/olmc (= 2.0.1)
- OLMKit/olmcpp (= 2.0.1)
- OLMKit/olmc (2.0.1)
- OLMKit/olmcpp (2.0.1)
DEPENDENCIES:
- OLMKit (from `../OLMKit.podspec`)
EXTERNAL SOURCES:
OLMKit:
:path: ../OLMKit.podspec
SPEC CHECKSUMS:
OLMKit: 12a35a69f92c7facdd50b559128d1b4a17857ba7
PODFILE CHECKSUM: 4e261dae61d833ec5585ced2473023b98909fd35
COCOAPODS: 1.1.1

26
xcode/README.rst Normal file
View file

@ -0,0 +1,26 @@
OLMKit
======
OLMKit exposes an Objective-C wrapper to libolm.
The original work by Chris Ballinger can be found at https://github.com/chrisballinger/OLMKit.
Installation
------------
You can embed OLMKit to your application project with CocoaPods. The pod for
the latest OLMKit release is::
pod 'OLMKit'
Development
-----------
Run `pod install` and open `OLMKit.xcworkspace`.
The project contains only tests files. The libolm and the Objective-C wrapper source files are loaded via the OLMKit CocoaPods pod.
To add a new source file, add it to the file system and run `pod update` to make CocoaPods insert it into OLMKit.xcworkspace.
Release
-------
See ../README.rst for the release of the CocoaPod.