Merge pull request #1 from ionspin/sample-continued

Migrate to own repo
This commit is contained in:
Ugljesa Jovanovic 2021-01-09 14:26:48 +00:00 committed by GitHub
commit 548305644c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
178 changed files with 634 additions and 14176 deletions

View File

@ -54,7 +54,6 @@ macPublishToSnapshot:
script:
- ./macBuild.sh
- ./macBuildAndPublishSnapshot-bindings.sh
- ./macBuildAndPublishSnapshot-delegated.sh
only:
- master
tags:
@ -69,7 +68,6 @@ buildWindows:
script:
- $env:CHERE_INVOKING = 'yes'
- C:\msys64\usr\bin\bash -lc "./windowsBuild-delegated.sh"
- C:\msys64\usr\bin\bash -lc "./windowsBuild-pure.sh"
tags:
- windowsX64
@ -78,7 +76,6 @@ windowsPublishToSnapshot:
script:
- $env:CHERE_INVOKING = 'yes'
- C:\msys64\usr\bin\bash -lc "./windowsBuildAndPublish-delegated.sh"
- C:\msys64\usr\bin\bash -lc "./windowsBuildAndPublish-pure.sh"
only:
- master
tags:

View File

@ -1,197 +0,0 @@
matrix:
include:
- os: linux
name: linux
language: java
jdk: openjdk12
env:
KBUILD=linux
JAVA_OPTS=-Xmx2g
#skip ./gradlew assemble that is normally invoked in installation step
install:
- sudo apt-get update
- sudo apt-get -y install automake
script:
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then bash ./linuxBuild.sh; fi'
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then bash ./linuxBuildAndPublish.sh; fi'
# OSX macos
- os: osx
name: osx-mac
osx_image: xcode11.4
language: java
jdk: openjdk12
install: true
env:
KBUILD=linux
JAVA_OPTS=-Xmx2g
script:
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then bash ./macBuild-mac.sh; fi'
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then bash ./macBuildAndPublish-mac.sh; fi'
# OSX ios
- os: osx
name: osx-ios
osx_image: xcode11.4
language: java
jdk: openjdk12
install: true
env:
KBUILD=linux
JAVA_OPTS=-Xmx2g
script:
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then bash ./macBuild-ios.sh; fi'
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then bash ./macBuildAndPublish-ios.sh; fi'
# OSX watchos
- os: osx
name: osx-watchos
osx_image: xcode11.4
language: java
jdk: openjdk12
install: true
env:
KBUILD=linux
JAVA_OPTS=-Xmx2g
script:
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then bash ./macBuild-watchos.sh; fi'
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then bash ./macBuildAndPublish-watchos.sh; fi'
# OSX tvos
- os: osx
name: osx-tvos
osx_image: xcode11.4
language: java
jdk: openjdk12
install: true
env:
KBUILD=linux
JAVA_OPTS=-Xmx2g
script:
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then bash ./macBuild-tvos.sh; fi'
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then bash ./macBuildAndPublish-tvos.sh; fi'
# OSX macos PURE
- os: osx
name: osx-mac-pure
osx_image: xcode11.4
language: java
jdk: openjdk12
install: true
env:
KBUILD=linux
JAVA_OPTS=-Xmx2g
script:
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then bash ./macBuild-pure-mac.sh; fi'
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then bash ./macBuildAndPublish-pure-mac.sh; fi'
# OSX ios PURE
- os: osx
name: osx-ios-pure
osx_image: xcode11.4
language: java
jdk: openjdk12
install: true
env:
KBUILD=linux
JAVA_OPTS=-Xmx2g
script:
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then bash ./macBuild-pure-ios.sh; fi'
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then bash ./macBuildAndPublish-pure-ios.sh; fi'
# OSX watchos PURE
- os: osx
name: osx-watchos-pure
osx_image: xcode11.4
language: java
jdk: openjdk12
install: true
env:
KBUILD=linux
JAVA_OPTS=-Xmx2g
script:
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then bash ./macBuild-pure-watchos.sh; fi'
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then bash ./macBuildAndPublish-pure-watchos.sh; fi'
# OSX tvos PURE
- os: osx
name: osx-tvos-pure
osx_image: xcode11.4
language: java
jdk: openjdk12
install: true
env:
KBUILD=linux
JAVA_OPTS=-Xmx2g
script:
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then bash ./macBuild-pure-tvos.sh; fi'
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then bash ./macBuildAndPublish-pure-tvos.sh; fi'
- os: windows
name: windows-pure
language: shell
jdk: openjdk12
env:
- GRAVIS="https://raw.githubusercontent.com/DanySK/Gravis-CI/master/"
- JAVA_OPTS=-Xmx2g
- JDK="adopt-openj9@1.11"
before_install:
- curl "${GRAVIS}.install-jdk-travis.sh" --output ~/.install-jdk-travis.sh
- source ~/.install-jdk-travis.sh
install: true
script:
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then $shell ./windowsBuild-pure.sh; fi'
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then ./windowsBuildAndPublish-pure.sh; fi'
- os: windows
name: windows-delegated
language: shell
jdk: openjdk12
env:
- GRAVIS="https://raw.githubusercontent.com/DanySK/Gravis-CI/master/"
- JAVA_OPTS=-Xmx2g
- JDK="adopt-openj9@1.11"
before_install:
- curl "${GRAVIS}.install-jdk-travis.sh" --output ~/.install-jdk-travis.sh
- source ~/.install-jdk-travis.sh
- |-
case $TRAVIS_OS_NAME in
windows)
[[ ! -f C:/tools/msys64/msys2_shell.cmd ]] && rm -rf C:/tools/msys64
choco uninstall -y mingw
choco upgrade --no-progress -y msys2 bazel
export msys2='cmd //C RefreshEnv.cmd '
export msys2+='& set MSYS=winsymlinks:nativestrict '
export msys2+='& C:\\tools\\msys64\\msys2_shell.cmd -defterm -no-start'
export shell="$msys2 -mingw64 -full-path -here -c \$\* --"
export msys2+=" -msys2 -c \$\* --"
$msys2 pacman --sync --noconfirm --needed \
autoconf \
automake \
mingw-w64-x86_64-libtool \
mingw-w64-x86_64-toolchain \
perl \
unzip
taskkill //IM gpg-agent.exe //F
export CPPFLAGS=-D__USE_MINGW_ANSI_STDIO=1
export PATH=/C/tools/msys64/mingw64/bin:$PATH
export GNU_MAKE=mingw32-make
export MAKE=mingw32-make
export AR=gcc-ar
export RANLIB=gcc-ranlib
export COVERITY_SCAN_BRANCH_PATTERN=disable_coverity_scan
;;
esac
- export GIT=git
- g++ --version
- $GNU_MAKE --version
- $GIT --version
install: true
before_cache:
- $msys2 pacman --sync --clean --noconfirm
script:
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then $shell ./windowsBuild-delegated.sh; fi'
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then $shell ./windowsBuildAndPublish-delegated.sh; fi'
cache:
directories:
- $HOME/.m2/
- $HOME/.gradle
- $HOME/.konan
- $HOME/AppData/Local/Temp/chocolatey
- /C/tools/msys64
branches:
only:
- master

View File

@ -1,5 +1,5 @@
[![pipeline status](https://gitlab.com/ionspin-github-ci/kotlin-multiplatform-crypto-ci/badges/master/pipeline.svg)](https://gitlab.com/ionspin-github-ci/kotlin-multiplatform-crypto-ci/-/commits/master)
[![pipeline status](https://gitlab.com/ionspin-github-ci/kotlin-multiplatform-libsodium/badges/master/pipeline.svg)](https://gitlab.com/ionspin-github-ci/kotlin-multiplatform-libsodium/-/commits/master)
![Danger: Experimental](https://camo.githubusercontent.com/275bc882f21b154b5537b9c123a171a30de9e6aa/68747470733a2f2f7261772e6769746875622e636f6d2f63727970746f7370686572652f63727970746f7370686572652f6d61737465722f696d616765732f6578706572696d656e74616c2e706e67)
@ -108,6 +108,7 @@ And here is the usage sample
The functions are mapped from libsodium to kotiln objects, so `crypto_secretstream_xchacha20poly1305_init_push` becomes
`SecretStream.xChaCha20Poly1305InitPush`
![Alt text](./doc/res/libsodium_api_mapping.svg)
At the moment you should refer to original libsodium documentation for instructions on how to use the library
@ -139,6 +140,7 @@ Currently supported native platforms:
- Android testing
- Fix browser testing, both locally and in CI/CD
- LobsodiumUtil `unpad` and `fromBase64` native implementations use a nasty hack to support shared native sourceset. The hack either needs to be removed and replaced with another solution or additional safeguards need to be added.
- Complete exposing libsodium constants

View File

@ -15,13 +15,13 @@
*/
object Versions {
val kotlinCoroutines = "1.3.9"
val kotlin = "1.4.10"
val kotlinSerialization = "1.0.0"
val kotlinCoroutines = "1.4.1"
val kotlin = "1.4.20"
val kotlinSerialization = "1.0.1"
val kotlinSerializationPlugin = "1.4.10"
val atomicfu = "0.14.3-M2-2-SNAPSHOT" //NOTE: my linux arm32 and arm64 build
val nodePlugin = "1.3.0"
val dokkaPlugin = "1.4.0-rc"
val dokkaPlugin = "1.4.0"
val taskTreePlugin = "1.5"
val kotlinBigNumVersion = "0.2.2"
val lazySodium = "4.3.1-SNAPSHOT"

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="297mm"
height="210mm"
viewBox="0 0 297 210"
version="1.1"
id="svg8"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
sodipodi:docname="libsodium_api_mapping.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.7"
inkscape:cx="554.56493"
inkscape:cy="538.66625"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
inkscape:window-width="1276"
inkscape:window-height="1396"
inkscape:window-x="3840"
inkscape:window-y="20"
inkscape:window-maximized="0" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<text
xml:space="preserve"
style="font-size:10.5833px;line-height:1.25;font-family:sans-serif;word-spacing:0px;stroke-width:0.264583"
x="9.5235968"
y="64.991554"
id="text12"><tspan
sodipodi:role="line"
id="tspan10"
x="9.5235968"
y="64.991554"
style="stroke-width:0.264583"><tspan
style="fill:#ff0000"
id="tspan18">crypto</tspan>_<tspan
style="fill:#008000"
id="tspan20">secretstream</tspan>_<tspan
style="fill:#0000ff"
id="tspan22">xchacha20poly1305</tspan>_<tspan
style="fill:#0000ff"
id="tspan28">init</tspan>_<tspan
style="fill:#0000ff"
id="tspan30">push</tspan></tspan></text>
<text
xml:space="preserve"
style="font-size:10.5833px;line-height:1.25;font-family:sans-serif;word-spacing:0px;stroke-width:0.264583"
x="47.202728"
y="94.062126"
id="text16"><tspan
sodipodi:role="line"
id="tspan14"
x="47.202728"
y="94.062126"
style="stroke-width:0.264583"><tspan
style="fill:#008000"
id="tspan34">SecretStream</tspan>.<tspan
style="fill:#0000ff"
id="tspan32">xChaCha20Poly1305InitPush</tspan></tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -15,10 +15,8 @@ fi
./makeLinuxArm64.sh
#now we can do the delegated build
cd ..
./gradlew multiplatform-crypto-delegated:build
#build libsodium bindings
./gradlew multiplatform-crypto-libsodium-bindings:build
#and finally pure build
./gradlew multiplatform-crypto:build
set +e

View File

@ -15,11 +15,9 @@ fi
./makeLinuxArm64.sh
#now we can do the delegated build
cd ..
./gradlew multiplatform-crypto-delegated:build
#build libsodium bindings
./gradlew multiplatform-crypto-libsodium-bindings:build
#and finally pure build
./gradlew multiplatform-crypto:build
./gradlew publishJvmPublicationToSnapshotRepository publishJsPublicationToSnapshotRepository \
publishKotlinMultiplatformPublicationToSnapshotRepository publishLinuxX64PublicationToSnapshotRepository \
publishLinuxArm64PublicationToSnapshotRepository publishMetadataPublicationToSnapshotRepository

View File

@ -8,10 +8,6 @@ cd sodiumWrapper
./makeIos.sh
#now we can do the delegated build of ios and macos libraries
cd ..
./gradlew multiplatform-crypto-delegated:iosArm32MainKlibrary multiplatform-crypto-delegated:iosArm32TestKlibrary \
multiplatform-crypto-delegated:iosArm64MainKlibrary multiplatform-crypto-delegated:iosArm64TestKlibrary \
multiplatform-crypto-delegated:iosX64MainKlibrary multiplatform-crypto-delegated:iosX64TestKlibrary
./gradlew multiplatform-crypto-delegated:iosX64Test
./gradlew multiplatform-crypto-libsodium-bindings:iosArm32MainKlibrary multiplatform-crypto-libsodium-bindings:iosArm32TestKlibrary \
multiplatform-crypto-libsodium-bindings:iosArm64MainKlibrary multiplatform-crypto-libsodium-bindings:iosArm64TestKlibrary \

View File

@ -8,9 +8,6 @@ cd sodiumWrapper
./makeIos.sh
#now we can do the delegated build of ios and macos libraries
cd ..
./gradlew multiplatform-crypto-delegated:macosX64MainKlibrary multiplatform-crypto-delegated:macosX64TestKlibrary
./gradlew multiplatform-crypto-delegated:macosX64Test
./gradlew multiplatform-crypto-libsodium-bindings:macosX64MainKlibrary multiplatform-crypto-libsodium-bindings:macosX64TestKlibrary
./gradlew multiplatform-crypto-libsodium-bindings:macosX64Test
set +e

View File

@ -1,9 +0,0 @@
set -e
#!/bin/sh
./gradlew multiplatform-crypto-api:build
./gradlew multiplatform-crypto:iosArm32MainKlibrary multiplatform-crypto:iosArm32TestKlibrary \
multiplatform-crypto:iosArm64MainKlibrary multiplatform-crypto:iosArm64TestKlibrary \
multiplatform-crypto:iosX64MainKlibrary multiplatform-crypto:iosX64TestKlibrary
./gradlew multiplatform-crypto:iosX64Test
set +e

View File

@ -1,7 +0,0 @@
set -e
#!/bin/sh
./gradlew multiplatform-crypto-api:build
./gradlew multiplatform-crypto:macosX64MainKlibrary multiplatform-crypto:macosX64TestKlibrary
./gradlew multiplatform-crypto:macosX64Test
set +e

View File

@ -1,7 +0,0 @@
set -e
#!/bin/sh
./gradlew multiplatform-crypto-api:build
./gradlew multiplatform-crypto:tvosArm64MainKlibrary multiplatform-crypto:tvosArm64TestKlibrary \
multiplatform-crypto:tvosX64MainKlibrary multiplatform-crypto:tvosX64TestKlibrary
./gradlew multiplatform-crypto:tvosX64Test
set +e

View File

@ -1,8 +0,0 @@
set -e
#!/bin/sh
./gradlew multiplatform-crypto-api:build
./gradlew multiplatform-crypto:watchosArm32MainKlibrary multiplatform-crypto:watchosArm32TestKlibrary \
multiplatform-crypto:watchosArm64MainKlibrary multiplatform-crypto:watchosArm64TestKlibrary \
multiplatform-crypto:watchosX86MainKlibrary multiplatform-crypto:watchosX86TestKlibrary
./gradlew multiplatform-crypto:watchosX86Test
set +e

View File

@ -7,9 +7,6 @@ cd sodiumWrapper
./makeTvos.sh
#now we can do the delegated build of ios and macos libraries
cd ..
./gradlew multiplatform-crypto-delegated:tvosArm64MainKlibrary multiplatform-crypto-delegated:tvosArm64TestKlibrary \
multiplatform-crypto-delegated:tvosX64MainKlibrary multiplatform-crypto-delegated:tvosX64TestKlibrary
./gradlew multiplatform-crypto-delegated:tvosX64Test
./gradlew multiplatform-crypto-libsodium-bindings:tvosArm64MainKlibrary multiplatform-crypto-libsodium-bindings:tvosArm64TestKlibrary \
multiplatform-crypto-libsodium-bindings:tvosX64MainKlibrary multiplatform-crypto-libsodium-bindings:tvosX64TestKlibrary

View File

@ -7,10 +7,6 @@ cd sodiumWrapper
./makeWatchos.sh
#now we can do the delegated build of ios and macos libraries
cd ..
./gradlew multiplatform-crypto-delegated:watchosArm32MainKlibrary multiplatform-crypto-delegated:watchosArm32TestKlibrary \
multiplatform-crypto-delegated:watchosArm64MainKlibrary multiplatform-crypto-delegated:watchosArm64TestKlibrary \
multiplatform-crypto-delegated:watchosX86MainKlibrary multiplatform-crypto-delegated:watchosX86TestKlibrary
./gradlew multiplatform-crypto-delegated:watchosX86Test
./gradlew multiplatform-crypto-libsodium-bindings:watchosArm32MainKlibrary multiplatform-crypto-libsodium-bindings:watchosArm32TestKlibrary \
multiplatform-crypto-libsodium-bindings:watchosArm64MainKlibrary multiplatform-crypto-libsodium-bindings:watchosArm64TestKlibrary \

View File

@ -8,9 +8,6 @@ cd sodiumWrapper
./makeIosWatchosTvos.sh
#now we can do the delegated build
cd ..
./gradlew multiplatform-crypto-delegated:build
#pure build
./gradlew multiplatform-crypto:build
#libsodium bindings
./gradlew multiplatform-crypto-libsodium-bindings:build
set +e

View File

@ -8,9 +8,6 @@ cd sodiumWrapper
./makeIos.sh
#now we can do the delegated build of ios and macos libraries
cd ..
./gradlew multiplatform-crypto-delegated:publishIosArm32PublicationToSnapshotRepository \
multiplatform-crypto-delegated:publishIosArm64PublicationToSnapshotRepository \
multiplatform-crypto-delegated:publishIosX64PublicationToSnapshotRepository
./gradlew multiplatform-crypto-libsodium-bindings:publishIosArm32PublicationToSnapshotRepository \
multiplatform-crypto-libsodium-bindings:publishIosArm64PublicationToSnapshotRepository \

View File

@ -7,7 +7,6 @@ cd sodiumWrapper
./makeMacosX86-64.sh
#now we can do the delegated build of ios and macos libraries
cd ..
./gradlew multiplatform-crypto-delegated:publishMacosX64PublicationToSnapshotRepository
./gradlew multiplatform-crypto-libsodium-bindings:publishMacosX64PublicationToSnapshotRepository
set +e

View File

@ -1,8 +0,0 @@
set -e
#!/bin/sh
#this will hopefully download all konan dependancies that we use in the build scripts
./gradlew multiplatform-crypto-api:build
./gradlew multiplatform-crypto:publishIosArm32PublicationToSnapshotRepository \
multiplatform-crypto:publishIosArm64PublicationToSnapshotRepository \
multiplatform-crypto:publishIosX64PublicationToSnapshotRepository
set +e

View File

@ -1,6 +0,0 @@
set -e
#!/bin/sh
#this will hopefully download all konan dependancies that we use in the build scripts
./gradlew multiplatform-crypto-api:build
./gradlew multiplatform-crypto:publishMacosX64PublicationToSnapshotRepository
set +e

View File

@ -1,8 +0,0 @@
set -e
#!/bin/sh
#this will hopefully download all konan dependancies that we use in the build scripts
./gradlew multiplatform-crypto-api:build
./gradlew multiplatform-crypto:publishTvosArm64PublicationToSnapshotRepository \
multiplatform-crypto:publishTvosX64PublicationToSnapshotRepository
set +e

View File

@ -1,8 +0,0 @@
set -e
#!/bin/sh
#this will hopefully download all konan dependancies that we use in the build scripts
./gradlew multiplatform-crypto-api:build
./gradlew multiplatform-crypto:publishWatchosArm32PublicationToSnapshotRepository \
multiplatform-crypto:publishWatchosArm64PublicationToSnapshotRepository \
multiplatform-crypto:publishWatchosX86PublicationToSnapshotRepository
set +e

View File

@ -1,8 +0,0 @@
set -e
#!/bin/sh
#this will hopefully download all konan dependancies that we use in the build scripts
./gradlew multiplatform-crypto-api:build
./gradlew multiplatform-crypto:publishTvosArm64PublicationToSnapshotRepository \
multiplatform-crypto:publishTvosX64PublicationToSnapshotRepository
set +e

View File

@ -7,9 +7,6 @@ cd sodiumWrapper
./makeWatchos.sh
#now we can do the delegated build of ios and macos libraries
cd ..
./gradlew multiplatform-crypto-delegated:publishWatchosArm32PublicationToSnapshotRepository \
multiplatform-crypto-delegated:publishWatchosArm64PublicationToSnapshotRepository \
multiplatform-crypto-delegated:publishWatchosX86PublicationToSnapshotRepository
./gradlew multiplatform-crypto-libsodium-bindings:publishWatchosArm32PublicationToSnapshotRepository \
multiplatform-crypto-libsodium-bindings:publishWatchosArm64PublicationToSnapshotRepository \

View File

@ -1,15 +0,0 @@
set -e
#!/bin/sh
./gradlew multiplatform-crypto-delegated:publishMacosX64PublicationToSnapshotRepository
./gradlew multiplatform-crypto-delegated:publishIosArm32PublicationToSnapshotRepository \
multiplatform-crypto-delegated:publishIosArm64PublicationToSnapshotRepository \
multiplatform-crypto-delegated:publishIosX64PublicationToSnapshotRepository
./gradlew multiplatform-crypto-delegated:publishWatchosArm32PublicationToSnapshotRepository \
multiplatform-crypto-delegated:publishWatchosArm64PublicationToSnapshotRepository \
multiplatform-crypto-delegated:publishWatchosX86PublicationToSnapshotRepository
./gradlew multiplatform-crypto-delegated:publishTvosArm64PublicationToSnapshotRepository \
multiplatform-crypto-delegated:publishTvosX64PublicationToSnapshotRepository
set +e

View File

@ -19,6 +19,7 @@
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTest
import org.jetbrains.dokka.Platform
plugins {
kotlin(PluginsDeps.multiplatform)
@ -275,9 +276,9 @@ tasks {
dokkaJavadoc {
println("Dokka !")
dokkaSourceSets {
create("commonMain") {
displayName = "common"
platform = "common"
named("commonMain") {
displayName.set("common")
platform.set(Platform.common)
}
}

View File

@ -1,697 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*
*/
@file:Suppress("UnstableApiUsage")
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTest
plugins {
kotlin(PluginsDeps.multiplatform)
id(PluginsDeps.mavenPublish)
id(PluginsDeps.signing)
id(PluginsDeps.node) version Versions.nodePlugin
id(PluginsDeps.dokka)
id(PluginsDeps.taskTree) version Versions.taskTreePlugin
}
val sonatypeStaging = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
val sonatypeSnapshots = "https://oss.sonatype.org/content/repositories/snapshots/"
val sonatypePassword: String? by project
val sonatypeUsername: String? by project
val sonatypePasswordEnv: String? = System.getenv()["SONATYPE_PASSWORD"]
val sonatypeUsernameEnv: String? = System.getenv()["SONATYPE_USERNAME"]
repositories {
mavenCentral()
jcenter()
}
group = ReleaseInfo.group
version = ReleaseInfo.version
val ideaActive = isInIdea()
println("Idea active: $ideaActive")
kotlin {
val hostOsName = getHostOsName()
runningOnLinuxx86_64 {
println("Configuring Linux X86-64 targets")
jvm()
js {
browser {
testTask {
isRunningInGitlabCi {
enabled = false //Until I sort out testing on travis
}
useKarma {
useChrome()
}
}
}
nodejs {
testTask {
useMocha() {
timeout = "10s"
}
}
}
}
linuxX64() {
compilations.getByName("main") {
val libsodiumCinterop by cinterops.creating {
defFile(project.file("src/nativeInterop/cinterop/libsodium.def"))
compilerOpts.add("-I${project.rootDir}/sodiumWrapper/static-linux-x86-64/include/")
}
kotlinOptions.freeCompilerArgs = listOf(
"-include-binary", "${project.rootDir}/sodiumWrapper/static-linux-x86-64/lib/libsodium.a"
)
}
binaries {
staticLib {
}
}
}
linuxArm64() {
binaries {
staticLib {
}
}
}
// Linux 32 is using target-sysroot-2-raspberrypi which is missing getrandom and explicit_bzero in stdlib
// so konanc can't build klib because getrandom missing will cause sodium_misuse()
// ld.lld: error: undefined symbol: explicit_bzero
// >>> referenced by utils.c
// >>> libsodium_la-utils.o:(sodium_memzero) in archive /tmp/included11051337748775083797/libsodium.a
//
// ld.lld: error: undefined symbol: getrandom
// >>> referenced by randombytes_sysrandom.c
// >>> libsodium_la-randombytes_sysrandom.o:(_randombytes_linux_getrandom) in archive /tmp/included11051337748775083797/libsodium.a
// linuxArm32Hfp() {
// binaries {
// staticLib {
// }
// }
// compilations.getByName("main") {
// val libsodiumCinterop by cinterops.creating {
// defFile(project.file("src/nativeInterop/cinterop/libsodium.def"))
// compilerOpts.add("-I${project.rootDir}/sodiumWrapper/static-arm32/include/")
// }
// kotlinOptions.freeCompilerArgs = listOf(
// "-include-binary", "${project.rootDir}/sodiumWrapper/static-arm32/lib/libsodium.a"
// )
// }
// }
}
runningOnLinuxArm64 {
println("Configuring Linux Arm 64 targets")
}
runningOnLinuxArm32 {
println("Configuring Linux Arm 32 targets")
}
runningOnMacos {
println("Configuring macos targets")
iosX64() {
binaries {
framework {
optimized = true
}
}
}
iosArm64() {
binaries {
framework {
optimized = true
}
}
}
iosArm32() {
binaries {
framework {
optimized = true
}
}
}
macosX64() {
binaries {
framework {
optimized = true
}
}
compilations.getByName("main") {
val libsodiumCinterop by cinterops.creating {
defFile(project.file("src/nativeInterop/cinterop/libsodium.def"))
compilerOpts.add("-I${project.rootDir}/sodiumWrapper/static-macos-x86-64/include")
}
kotlinOptions.freeCompilerArgs = listOf(
"-include-binary", "${project.rootDir}/sodiumWrapper/static-macos-x86-64/lib/libsodium.a"
)
}
}
tvosX64() {
binaries {
framework {
optimized = true
}
}
}
tvosArm64() {
binaries {
framework {
optimized = true
}
}
}
watchosArm64() {
binaries {
framework {
optimized = true
}
}
}
watchosArm32() {
binaries {
framework {
optimized = true
}
}
}
watchosX86() {
binaries {
framework {
optimized = true
}
}
}
}
runningOnWindows {
println("Configuring Mingw targets")
mingwX64() {
binaries {
staticLib {
optimized = true
}
}
compilations.getByName("main") {
val libsodiumCinterop by cinterops.creating {
defFile(project.file("src/nativeInterop/cinterop/libsodium.def"))
compilerOpts.add("-I${project.rootDir}/sodiumWrapper/static-mingw-x86-64/include")
}
kotlinOptions.freeCompilerArgs = listOf(
"-include-binary", "${project.rootDir}/sodiumWrapper/static-mingw-x86-64/lib/libsodium.a"
)
}
}
}
println(targets.names)
sourceSets {
val commonMain by getting {
dependencies {
implementation(kotlin(Deps.Common.stdLib))
implementation(kotlin(Deps.Common.test))
implementation(Deps.Common.kotlinBigNum)
api(project(Deps.Common.apiProject))
}
}
val commonTest by getting {
dependencies {
implementation(kotlin(Deps.Common.test))
implementation(kotlin(Deps.Common.testAnnotation))
}
}
val nativeDependencies = independentDependencyBlock {
}
val nativeMain by creating {
dependsOn(commonMain)
isRunningInIdea {
kotlin.setSrcDirs(emptySet<String>())
}
dependencies {
nativeDependencies(this)
}
}
val nativeTest by creating {
dependsOn(commonTest)
isRunningInIdea {
kotlin.setSrcDirs(emptySet<String>())
}
dependencies {
}
}
//Set up shared source sets
//linux, linuxArm32Hfp, linuxArm64
val linux64Bit = setOf(
"linuxX64"
)
val linuxArm64Bit = setOf(
"linuxArm64"
)
val linux32Bit = setOf(
"" // "linuxArm32Hfp"
)
//iosArm32, iosArm64, iosX64, macosX64, metadata, tvosArm64, tvosX64, watchosArm32, watchosArm64, watchosX86
val macos64Bit = setOf(
"macosX64"
)
val iosArm = setOf(
"iosArm64", "iosArm32"
)
val iosSimulator = setOf(
"iosX64"
)
val mingw64Bit = setOf(
"mingwX64"
)
val tvosArm = setOf(
"tvosArm64"
)
val tvosSimulator = setOf(
"tvosX64"
)
val watchosArm = setOf(
"watchosArm32", "watchosArm64"
)
val watchosSimulator = setOf(
"watchosX86"
)
targets.withType<KotlinNativeTarget> {
println("Target $name")
compilations.getByName("main") {
if (linux64Bit.contains(this@withType.name)) {
defaultSourceSet.dependsOn(nativeMain)
}
if (linuxArm64Bit.contains(this@withType.name)) {
defaultSourceSet.dependsOn(
createWorkaroundNativeMainSourceSet(
this@withType.name,
nativeDependencies
)
)
compilations.getByName("main") {
val libsodiumCinterop by cinterops.creating {
defFile(project.file("src/nativeInterop/cinterop/libsodium.def"))
compilerOpts.add("-I${project.rootDir}/sodiumWrapper/static-arm64/include/")
}
kotlinOptions.freeCompilerArgs = listOf(
"-include-binary", "${project.rootDir}/sodiumWrapper/static-arm64/lib/libsodium.a"
)
}
}
if (linux32Bit.contains(this@withType.name)) {
defaultSourceSet.dependsOn(createWorkaroundNativeMainSourceSet(this@withType.name, nativeDependencies))
}
if (macos64Bit.contains(this@withType.name)) {
defaultSourceSet.dependsOn(createWorkaroundNativeMainSourceSet(this@withType.name, nativeDependencies))
}
//All ioses share the same static library
if (iosArm.contains(this@withType.name)) {
defaultSourceSet.dependsOn(createWorkaroundNativeMainSourceSet(this@withType.name, nativeDependencies))
println("Setting ios cinterop for $this")
val libsodiumCinterop by cinterops.creating {
defFile(project.file("src/nativeInterop/cinterop/libsodium.def"))
compilerOpts.add("-I${project.rootDir}/sodiumWrapper/static-ios/include")
}
kotlinOptions.freeCompilerArgs = listOf(
"-include-binary", "${project.rootDir}/sodiumWrapper/static-ios/lib/libsodium.a"
)
}
if (iosSimulator.contains(this@withType.name)) {
defaultSourceSet.dependsOn(createWorkaroundNativeMainSourceSet(this@withType.name, nativeDependencies))
println("Setting ios cinterop for $this")
val libsodiumCinterop by cinterops.creating {
defFile(project.file("src/nativeInterop/cinterop/libsodium.def"))
compilerOpts.add("-I${project.rootDir}/sodiumWrapper/static-ios-simulators/include")
}
kotlinOptions.freeCompilerArgs = listOf(
"-include-binary", "${project.rootDir}/sodiumWrapper/static-ios-simulators/lib/libsodium.a"
)
}
if (tvosArm.contains(this@withType.name)) {
defaultSourceSet.dependsOn(createWorkaroundNativeMainSourceSet(this@withType.name, nativeDependencies))
println("Setting ios cinterop for $this")
val libsodiumCinterop by cinterops.creating {
defFile(project.file("src/nativeInterop/cinterop/libsodium.def"))
compilerOpts.add("-I${project.rootDir}/sodiumWrapper/static-tvos/include")
}
kotlinOptions.freeCompilerArgs = listOf(
"-include-binary", "${project.rootDir}/sodiumWrapper/static-tvos/lib/libsodium.a"
)
}
if (tvosSimulator.contains(this@withType.name)) {
defaultSourceSet.dependsOn(createWorkaroundNativeMainSourceSet(this@withType.name, nativeDependencies))
println("Setting ios cinterop for $this")
val libsodiumCinterop by cinterops.creating {
defFile(project.file("src/nativeInterop/cinterop/libsodium.def"))
compilerOpts.add("-I${project.rootDir}/sodiumWrapper/static-tvos-simulators/include")
}
kotlinOptions.freeCompilerArgs = listOf(
"-include-binary", "${project.rootDir}/sodiumWrapper/static-tvos-simulators/lib/libsodium.a"
)
}
if (watchosArm.contains(this@withType.name)) {
defaultSourceSet.dependsOn(createWorkaroundNativeMainSourceSet(this@withType.name, nativeDependencies))
println("Setting ios cinterop for $this")
val libsodiumCinterop by cinterops.creating {
defFile(project.file("src/nativeInterop/cinterop/libsodium.def"))
compilerOpts.add("-I${project.rootDir}/sodiumWrapper/static-watchos/include")
}
kotlinOptions.freeCompilerArgs = listOf(
"-include-binary", "${project.rootDir}/sodiumWrapper/static-watchos/lib/libsodium.a"
)
}
if (watchosSimulator.contains(this@withType.name)) {
defaultSourceSet.dependsOn(createWorkaroundNativeMainSourceSet(this@withType.name, nativeDependencies))
println("Setting ios cinterop for $this")
val libsodiumCinterop by cinterops.creating {
defFile(project.file("src/nativeInterop/cinterop/libsodium.def"))
compilerOpts.add("-I${project.rootDir}/sodiumWrapper/static-watchos-simulators/include")
}
kotlinOptions.freeCompilerArgs = listOf(
"-include-binary", "${project.rootDir}/sodiumWrapper/static-watchos-simulators/lib/libsodium.a"
)
}
}
compilations.getByName("test") {
println("Setting native test dep for $this@withType.name")
defaultSourceSet.dependsOn(nativeTest)
}
}
runningOnLinuxx86_64 {
println("Configuring Linux 64 Bit source sets")
val jvmMain by getting {
dependencies {
implementation(kotlin(Deps.Jvm.stdLib))
implementation(kotlin(Deps.Jvm.test))
implementation(kotlin(Deps.Jvm.testJUnit))
//lazysodium
implementation(Deps.Jvm.Delegated.lazysodium)
implementation(Deps.Jvm.Delegated.jna)
}
}
val jvmTest by getting {
dependencies {
implementation(kotlin(Deps.Jvm.test))
implementation(kotlin(Deps.Jvm.testJUnit))
implementation(kotlin(Deps.Jvm.reflection))
}
}
val jsMain by getting {
dependencies {
implementation(kotlin(Deps.Js.stdLib))
implementation(npm(Deps.Js.Npm.libsodiumWrappers.first, Deps.Js.Npm.libsodiumWrappers.second))
}
}
val jsTest by getting {
dependencies {
implementation(kotlin(Deps.Js.test))
implementation(npm(Deps.Js.Npm.libsodiumWrappers.first, Deps.Js.Npm.libsodiumWrappers.second))
}
}
val linuxX64Main by getting {
isRunningInIdea {
kotlin.srcDir("src/nativeMain/kotlin")
}
}
val linuxX64Test by getting {
dependsOn(nativeTest)
isRunningInIdea {
kotlin.srcDir("src/nativeTest/kotlin")
}
}
}
runningOnMacos {
println("Configuring Macos source sets")
val macosX64Main by getting {
dependsOn(nativeMain)
if (ideaActive) {
kotlin.srcDir("src/nativeMain/kotlin")
}
}
val macosX64Test by getting {
dependsOn(nativeTest)
if (ideaActive) {
kotlin.srcDir("src/nativeTest/kotlin")
}
}
val tvosX64Main by getting {
dependsOn(commonMain)
}
val tvosArm64Main by getting {
dependsOn(commonMain)
}
val watchosX86Main by getting {
dependsOn(commonMain)
}
val watchosArm64Main by getting {
dependsOn(commonMain)
}
val watchosArm32Main by getting {
dependsOn(commonMain)
}
}
if (hostOsName == "windows") {
val mingwX64Main by getting {
dependsOn(nativeMain)
if (ideaActive) {
kotlin.srcDir("src/nativeMain/kotlin")
}
}
val mingwX64Test by getting {
dependsOn(nativeTest)
if (ideaActive) {
kotlin.srcDir("src/nativeTest/kotlin")
}
}
}
all {
languageSettings.enableLanguageFeature("InlineClasses")
languageSettings.useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
languageSettings.useExperimentalAnnotation("kotlin.ExperimentalStdlibApi")
}
}
}
tasks {
create<Jar>("javadocJar") {
dependsOn(dokkaJavadoc)
archiveClassifier.set("javadoc")
from(dokkaJavadoc.get().outputDirectory)
}
dokkaJavadoc {
println("Dokka !")
dokkaSourceSets {
create("commonMain") {
displayName = "common"
platform = "common"
}
}
}
if (getHostOsName() == "linux" && getHostArchitecture() == "x86-64") {
val jvmTest by getting(Test::class) {
testLogging {
events("PASSED", "FAILED", "SKIPPED")
}
}
val linuxX64Test by getting(KotlinNativeTest::class) {
testLogging {
events("PASSED", "FAILED", "SKIPPED")
showStandardStreams = true
}
}
val jsNodeTest by getting(KotlinJsTest::class) {
testLogging {
events("PASSED", "FAILED", "SKIPPED")
// showStandardStreams = true
}
}
// val legacyjsNodeTest by getting(KotlinJsTest::class) {
//
// testLogging {
// events("PASSED", "FAILED", "SKIPPED")
// showStandardStreams = true
// }
// }
// val jsIrBrowserTest by getting(KotlinJsTest::class) {
// testLogging {
// events("PASSED", "FAILED", "SKIPPED")
// showStandardStreams = true
// }
// }
}
if (getHostOsName() == "windows") {
val mingwX64Test by getting(KotlinNativeTest::class) {
testLogging {
events("PASSED", "FAILED", "SKIPPED")
showStandardStreams = true
}
}
}
}
signing {
isRequired = false
sign(publishing.publications)
}
publishing {
publications.withType(MavenPublication::class) {
artifact(tasks["javadocJar"])
pom {
name.set("Kotlin Multiplatform Crypto")
description.set("Kotlin Multiplatform Crypto library")
url.set("https://github.com/ionspin/kotlin-multiplatform-crypto")
licenses {
license {
name.set("The Apache License, Version 2.0")
url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
}
}
developers {
developer {
id.set("ionspin")
name.set("Ugljesa Jovanovic")
email.set("opensource@ionspin.com")
}
}
scm {
url.set("https://github.com/ionspin/kotlin-multiplatform-crypto")
connection.set("scm:git:git://git@github.com:ionspin/kotlin-multiplatform-crypto.git")
developerConnection.set("scm:git:ssh://git@github.com:ionspin/kotlin-multiplatform-crypto.git")
}
}
}
repositories {
maven {
url = uri(sonatypeStaging)
credentials {
username = sonatypeUsername ?: sonatypeUsernameEnv ?: ""
password = sonatypePassword ?: sonatypePasswordEnv ?: ""
}
}
maven {
name = "snapshot"
url = uri(sonatypeSnapshots)
credentials {
username = sonatypeUsername ?: sonatypeUsernameEnv ?: ""
password = sonatypePassword ?: sonatypePasswordEnv ?: ""
}
}
}
}
//configurations.forEach {
//
// if (it.name == "linuxCompileKlibraries") {
// println("Configuration name: ${it.name}")
// it.attributes {
// this.keySet().forEach { key ->
// val attribute = getAttribute(key)
// println(" |-- Attribute $key ${attribute}")
// attribute(org.jetbrains.kotlin.gradle.plugin.ProjectLocalConfigurations.ATTRIBUTE, "publicZ")
// }
// }
// }
//}

View File

@ -1,26 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
package com.ionspin.kotlin.crypto
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 20-Jul-2019
*/
object Config {
const val DEBUG = false
}

View File

@ -1,216 +0,0 @@
package com.ionspin.kotlin.crypto
import com.ionspin.kotlin.crypto.authenticated.XChaCha20Poly1305Delegated
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bProperties
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bDelegated
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bDelegatedStateless
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bMultipart
import com.ionspin.kotlin.crypto.hash.sha.*
import com.ionspin.kotlin.crypto.keyderivation.ArgonResult
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 24-May-2020
*/
object CryptoInitializerDelegated : CryptoInitializer {
override suspend fun initialize() {
Initializer.initialize()
}
fun initializeWithCallback(done: () -> Unit) {
Initializer.initializeWithCallback(done)
}
override fun isInitialized(): Boolean {
return Initializer.isInitialized()
}
}
object CryptoPrimitives : PrimitivesApi {
object Blake2b {
fun updateable(key: UByteArray? = null, hashLength: Int = Blake2bProperties.MAX_HASH_BYTES): com.ionspin.kotlin.crypto.hash.blake2b.Blake2bMultipart {
checkInitialization()
return Blake2bDelegated(key, hashLength)
}
fun stateless(message: UByteArray, key: UByteArray = ubyteArrayOf(), hashLength: Int = Blake2bProperties.MAX_HASH_BYTES): UByteArray {
checkInitialization()
return Blake2bDelegatedStateless.digest(message, key, hashLength)
}
}
object Sha256 {
fun updateable(): com.ionspin.kotlin.crypto.hash.sha.Sha256 {
checkInitialization()
return Sha256Delegated()
}
fun stateless(message: UByteArray) : UByteArray{
checkInitialization()
return Sha256StatelessDelegated.digest(inputMessage = message)
}
}
object Sha512 {
fun updateable(): Sha512Multipart {
checkInitialization()
return Sha512Delegated()
}
fun stateless(message: UByteArray) : UByteArray {
checkInitialization()
return Sha512StatelessDelegated.digest(inputMessage = message)
}
}
private fun checkInitialization() {
if (!Initializer.isInitialized()) {
throw RuntimeException("Platform library not initialized, check if you called Initializer.initialize()")
}
}
override fun hashBlake2bMultipart(key: UByteArray?, hashLength: Int): Blake2bMultipart {
checkInitialization()
return Blake2bDelegated(key, hashLength)
}
override fun hashBlake2b(message: UByteArray, key: UByteArray, hashLength: Int): UByteArray {
checkInitialization()
return Blake2bDelegatedStateless.digest(message, key, hashLength)
}
override fun hashSha256Multipart(): com.ionspin.kotlin.crypto.hash.sha.Sha256 {
checkInitialization()
return Sha256Delegated()
}
override fun hashSha256(message: UByteArray): UByteArray {
checkInitialization()
return Sha256StatelessDelegated.digest(inputMessage = message)
}
override fun hashSha512Multipart(): com.ionspin.kotlin.crypto.hash.sha.Sha512Multipart {
checkInitialization()
return Sha512Delegated()
}
override fun hashSha512(message: UByteArray): UByteArray {
checkInitialization()
return Sha512StatelessDelegated.digest(inputMessage = message)
}
override fun deriveKey(
password: String,
salt: String?,
key: String,
associatedData: String,
parallelism: Int,
tagLength: Int,
memory: Int,
numberOfIterations: Int
): ArgonResult {
// return Argon2Delegated.derive(
// password,
// salt,
// key,
// associatedData,
// parallelism
// tagLength,
// memory,
// numberOfIterations
// )
TODO()
}
}
fun SymmetricKey.Companion.randomKey() : SymmetricKey {
return SymmetricKey(SRNG.getRandomBytes(32))
}
object Crypto {
object Hash : HashApi {
override fun hash(data: UByteArray, key : UByteArray) : HashedData {
return HashedData(Blake2bDelegatedStateless.digest(data, key))
}
override fun multipartHash(key: UByteArray?) : com.ionspin.kotlin.crypto.hash.MultipartHash {
return Blake2bDelegated(key)
}
}
object Encryption : EncryptionApi {
override fun encrypt(key: SymmetricKey, data : Encryptable<*>, associatedData : UByteArray) : EncryptedData {
if (key.value.size != 32) {
throw RuntimeException("Invalid key size! Required 32, supplied ${key.value.size}")
}
val nonce = SRNG.getRandomBytes(24)
return EncryptedData(XChaCha20Poly1305Delegated.encrypt(key.value, nonce, data.toEncryptableForm(), associatedData), nonce)
}
override fun <T: Encryptable<T>> decrypt(key: SymmetricKey, encryptedData : EncryptedData, associatedData: UByteArray, byteArrayDeserializer : (UByteArray) -> T) : T {
return byteArrayDeserializer(XChaCha20Poly1305Delegated.decrypt(key.value, encryptedData.nonce, encryptedData.ciphertext, associatedData))
}
override fun createMultipartEncryptor(key: SymmetricKey): MultipartAuthenticatedEncryption {
return MultipartAuthenticatedEncryptor(key)
}
override fun createMultipartDecryptor(key: SymmetricKey, header: MultipartEncryptionHeader) : MultipartAuthenticatedDecryption {
val decryptor = XChaCha20Poly1305Delegated()
decryptor.initializeForDecryption(key.value, header.nonce)
return MultipartAuthenticatedDecryptor(decryptor)
}
}
}
class MultipartAuthenticatedEncryptor internal constructor(val key : SymmetricKey) : MultipartAuthenticatedEncryption {
val header : MultipartEncryptionHeader
val primitive = XChaCha20Poly1305Delegated()
init {
header = MultipartEncryptionHeader(primitive.initializeForEncryption(key.value))
}
override fun startEncryption(): MultipartEncryptionHeader {
return header
}
override fun encryptPartialData(data: UByteArray, associatedData: UByteArray): EncryptedDataPart {
return EncryptedDataPart(primitive.encrypt(data, associatedData))
}
override fun cleanup() {
primitive.cleanup()
}
}
class MultipartAuthenticatedDecryptor internal constructor(val decryptor: XChaCha20Poly1305Delegated) : MultipartAuthenticatedDecryption {
override fun decryptPartialData(data: EncryptedDataPart, associatedData: UByteArray): DecryptedDataPart {
return DecryptedDataPart(decryptor.decrypt(data.data, associatedData))
}
override fun cleanup() {
decryptor.cleanup()
}
}
expect object Initializer {
fun isInitialized() : Boolean
suspend fun initialize()
fun initializeWithCallback(done: () -> (Unit))
}

View File

@ -1,12 +0,0 @@
package _multiplatform_crypto_delegated
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 24-May-2020
*/
//Workaround for https://youtrack.jetbrains.com/issue/KT-36878
val byteArray = byteArrayOf(0)
val byte = 0.toByte()
val longArray = longArrayOf(0)
val long = 0L

View File

@ -1,26 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
package com.ionspin.kotlin.crypto
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 21-Sep-2019
*/
expect object SRNG {
fun getRandomBytes(amount : Int) : UByteArray
}

View File

@ -1,24 +0,0 @@
package com.ionspin.kotlin.crypto.authenticated
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 14-Jun-2020
*/
expect class XChaCha20Poly1305Delegated internal constructor() {
internal constructor(key: UByteArray, testState : UByteArray, testHeader: UByteArray, isDecryptor: Boolean)
companion object {
fun encrypt(key: UByteArray, nonce: UByteArray, message: UByteArray, associatedData: UByteArray) : UByteArray
fun decrypt(key: UByteArray, nonce: UByteArray, ciphertext: UByteArray, associatedData: UByteArray) : UByteArray
}
fun initializeForEncryption(key: UByteArray) : UByteArray
fun initializeForDecryption(key: UByteArray, header: UByteArray)
fun encrypt(data: UByteArray, associatedData: UByteArray = ubyteArrayOf()) : UByteArray
fun decrypt(data: UByteArray, associatedData: UByteArray = ubyteArrayOf()) : UByteArray
fun cleanup()
}

View File

@ -1,31 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
package com.ionspin.kotlin.crypto.hash.blake2b
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 14-Jul-2019
*/
expect class Blake2bDelegated(key: UByteArray? = null, hashLength: Int = Blake2bProperties.MAX_HASH_BYTES) : Blake2bMultipart
expect object Blake2bDelegatedStateless : Blake2b

View File

@ -1,29 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
package com.ionspin.kotlin.crypto.hash.sha
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 17-Jul-2019
*/
expect class Sha256Delegated() : Sha256
expect object Sha256StatelessDelegated : StatelessSha256

View File

@ -1,29 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
package com.ionspin.kotlin.crypto.hash.sha
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 17-Jul-2019
*/
expect class Sha512Delegated() : Sha512Multipart
expect object Sha512StatelessDelegated : Sha512

View File

@ -1,10 +0,0 @@
package com.ionspin.kotlin.crypto.keyderivation.argon2
import com.ionspin.kotlin.crypto.keyderivation.KeyDerivationFunction
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 24-May-2020
*/
interface Argon2 : KeyDerivationFunction

View File

@ -1,34 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
package com.ionspin.kotlin.crypto.parallelization
import kotlin.time.ExperimentalTime
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 17-May-2020
*/
@ExperimentalTime
object Coroutines14 {
fun argonParallel() : Array<UByte> {
// val argon = Argon2()
// argon
println("Placeholder")
return emptyArray()
}
}

View File

@ -1,216 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
@file:Suppress("EXPERIMENTAL_API_USAGE")
package com.ionspin.kotlin.crypto.util
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 15-Jul-2019
*/
inline fun <reified T> Array<T>.chunked(sliceSize: Int): Array<Array<T>> {
val last = this.size % sliceSize
val hasLast = last != 0
val numberOfSlices = this.size / sliceSize
val result : MutableList<List<T>> = MutableList<List<T>>(0) { emptyList() }
for (i in 0 until numberOfSlices) {
result.add(this.slice(i * sliceSize until (i + 1) * sliceSize))
}
if (hasLast) {
result.add(this.slice(numberOfSlices * sliceSize until this.size))
}
return result.map { it.toTypedArray() }.toTypedArray()
}
infix fun UInt.rotateRight(places: Int): UInt {
return (this shr places) xor (this shl (32 - places))
}
infix fun ULong.rotateRight(places: Int): ULong {
return (this shr places) xor (this shl (64 - places))
}
infix fun Array<UByte>.xor(other : Array<UByte>) : Array<UByte> {
if (this.size != other.size) {
throw RuntimeException("Operands of different sizes are not supported yet")
}
return Array(this.size) { this[it] xor other[it] }
}
infix fun UByteArray.xor(other : UByteArray) : UByteArray {
if (this.size != other.size) {
throw RuntimeException("Operands of different sizes are not supported yet")
}
return UByteArray(this.size) { this[it] xor other[it] }
}
// UInt / Array utils
fun UInt.toBigEndianUByteArray() : Array<UByte> {
return Array<UByte> (4) {
((this shr (24 - (it * 8))) and 0xFFU).toUByte()
}
}
fun UInt.toLittleEndianTypedUByteArray() : Array<UByte> {
return Array<UByte> (4) {
((this shr (it * 8)) and 0xFFU).toUByte()
}
}
fun UInt.toLittleEndianUByteArray() : UByteArray {
return UByteArray (4) {
((this shr (it * 8)) and 0xFFU).toUByte()
}
}
// UInt / Array utils
fun ULong.toBigEndianUByteArray() : Array<UByte> {
return Array<UByte> (8) {
((this shr (56 - (it * 8))) and 0xFFU).toUByte()
}
}
fun ULong.toLittleEndianTypedUByteArray() : Array<UByte> {
return Array<UByte> (8) {
((this shr (it * 8)) and 0xFFU).toUByte()
}
}
fun ULong.toLittleEndianUByteArray() :UByteArray {
return UByteArray (8) {
((this shr (it * 8)) and 0xFFU).toUByte()
}
}
fun Array<UByte>.fromLittleEndianArrayToULong() : ULong {
if (this.size > 8) {
throw RuntimeException("ore than 8 bytes in input, potential overflow")
}
var ulong = this.foldIndexed(0UL) { index, acc, uByte -> acc or (uByte.toULong() shl (index * 8))}
return ulong
}
fun UByteArray.fromLittleEndianArrayToULong() : ULong {
if (this.size > 8) {
throw RuntimeException("ore than 8 bytes in input, potential overflow")
}
var ulong = this.foldIndexed(0UL) { index, acc, uByte -> acc or (uByte.toULong() shl (index * 8))}
return ulong
}
fun UByteArray.arrayChunked(sliceSize: Int): List<UByteArray> {
val last = this.size % sliceSize
val hasLast = last != 0
val numberOfSlices = this.size / sliceSize
val result : MutableList<UByteArray> = MutableList<UByteArray>(0) { ubyteArrayOf() }
for (i in 0 until numberOfSlices) {
result.add(this.sliceArray(i * sliceSize until (i + 1) * sliceSize))
}
if (hasLast) {
result.add(this.sliceArray(numberOfSlices * sliceSize until this.size))
}
return result
}
fun Array<UByte>.fromBigEndianArrayToULong() : ULong {
if (this.size > 8) {
throw RuntimeException("ore than 8 bytes in input, potential overflow")
}
var ulong = this.foldIndexed(0UL) {
index, acc, uByte ->
val res = acc or (uByte.toULong() shl (56 - (index * 8)))
res
}
return ulong
}
fun Array<UByte>.fromLittleEndianArrayToUInt() : UInt {
if (this.size > 4) {
throw RuntimeException("ore than 8 bytes in input, potential overflow")
}
var uint = this.foldIndexed(0U) { index, acc, uByte -> acc or (uByte.toUInt() shl (index * 8))}
return uint
}
fun UByteArray.fromLittleEndianArrayToUInt() : UInt {
if (this.size > 4) {
throw RuntimeException("ore than 8 bytes in input, potential overflow")
}
var uint = this.foldIndexed(0U) { index, acc, uByte -> acc or (uByte.toUInt() shl (index * 8))}
return uint
}
fun Array<UByte>.fromBigEndianArrayToUInt() : UInt {
if (this.size > 4) {
throw RuntimeException("ore than 8 bytes in input, potential overflow")
}
var uint = this.foldIndexed(0U) { index, acc, uByte -> acc or (uByte.toUInt() shl (24 - (index * 8))) }
return uint
}
operator fun UInt.plus(other : UByteArray) : UByteArray {
return this.toLittleEndianUByteArray() + other
}
//AES Flatten
fun Collection<UByteArray>.flattenToUByteArray(): UByteArray {
val result = UByteArray(sumBy { it.size })
var position = 0
for (element in this) {
element.forEach { uByte ->
result[position] = uByte
position++
}
}
return result
}

View File

@ -1,13 +0,0 @@
package com.ionspin.kotlin.crypto
import kotlin.test.Test
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 17-Jul-2020
*/
class DebugTest {
}

View File

@ -1,37 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
package com.ionspin.kotlin.crypto
import com.ionspin.kotlin.crypto.util.testBlocking
import kotlin.test.Test
import kotlin.test.assertTrue
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 21-Sep-2019
*/
class SRNGTest {
@Test
fun testSrng() = testBlocking {
CryptoInitializerDelegated.initialize()
//Just a sanity test, need to add better srng tests.
val randomBytes1 = SRNG.getRandomBytes(10)
val randomBytes2 = SRNG.getRandomBytes(10)
assertTrue { !randomBytes1.contentEquals(randomBytes2) }
}
}

View File

@ -1,240 +0,0 @@
package com.ionspin.kotlin.crypto.authenticated
import com.ionspin.kotlin.crypto.CryptoInitializerDelegated
import com.ionspin.kotlin.crypto.Initializer
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.hexColumsPrint
import com.ionspin.kotlin.crypto.util.testBlocking
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertFails
import kotlin.test.assertTrue
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 17-Jun-2020
*/
class XChaCha20Poly1305Test {
@Test
fun xChaCha20Poly1305() = testBlocking {
CryptoInitializerDelegated.initialize()
assertTrue {
val message = ("Ladies and Gentlemen of the class of '99: If I could offer you " +
"only one tip for the future, sunscreen would be it.").encodeToUByteArray()
val associatedData = ubyteArrayOf(
0x50U, 0x51U, 0x52U, 0x53U, 0xc0U, 0xc1U, 0xc2U, 0xc3U, 0xc4U, 0xc5U, 0xc6U, 0xc7U
)
val key = ubyteArrayOf(
0x80U, 0x81U, 0x82U, 0x83U, 0x84U, 0x85U, 0x86U, 0x87U,
0x88U, 0x89U, 0x8aU, 0x8bU, 0x8cU, 0x8dU, 0x8eU, 0x8fU,
0x90U, 0x91U, 0x92U, 0x93U, 0x94U, 0x95U, 0x96U, 0x97U,
0x98U, 0x99U, 0x9aU, 0x9bU, 0x9cU, 0x9dU, 0x9eU, 0x9fU,
)
val nonce = ubyteArrayOf(
0x40U, 0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U,
0x48U, 0x49U, 0x4aU, 0x4bU, 0x4cU, 0x4dU, 0x4eU, 0x4fU,
0x50U, 0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x57U,
)
val expected = ubyteArrayOf(
0xbdU, 0x6dU, 0x17U, 0x9dU, 0x3eU, 0x83U, 0xd4U, 0x3bU,
0x95U, 0x76U, 0x57U, 0x94U, 0x93U, 0xc0U, 0xe9U, 0x39U,
0x57U, 0x2aU, 0x17U, 0x00U, 0x25U, 0x2bU, 0xfaU, 0xccU,
0xbeU, 0xd2U, 0x90U, 0x2cU, 0x21U, 0x39U, 0x6cU, 0xbbU,
0x73U, 0x1cU, 0x7fU, 0x1bU, 0x0bU, 0x4aU, 0xa6U, 0x44U,
0x0bU, 0xf3U, 0xa8U, 0x2fU, 0x4eU, 0xdaU, 0x7eU, 0x39U,
0xaeU, 0x64U, 0xc6U, 0x70U, 0x8cU, 0x54U, 0xc2U, 0x16U,
0xcbU, 0x96U, 0xb7U, 0x2eU, 0x12U, 0x13U, 0xb4U, 0x52U,
0x2fU, 0x8cU, 0x9bU, 0xa4U, 0x0dU, 0xb5U, 0xd9U, 0x45U,
0xb1U, 0x1bU, 0x69U, 0xb9U, 0x82U, 0xc1U, 0xbbU, 0x9eU,
0x3fU, 0x3fU, 0xacU, 0x2bU, 0xc3U, 0x69U, 0x48U, 0x8fU,
0x76U, 0xb2U, 0x38U, 0x35U, 0x65U, 0xd3U, 0xffU, 0xf9U,
0x21U, 0xf9U, 0x66U, 0x4cU, 0x97U, 0x63U, 0x7dU, 0xa9U,
0x76U, 0x88U, 0x12U, 0xf6U, 0x15U, 0xc6U, 0x8bU, 0x13U,
0xb5U, 0x2eU, 0xc0U, 0x87U, 0x59U, 0x24U, 0xc1U, 0xc7U,
0x98U, 0x79U, 0x47U, 0xdeU, 0xafU, 0xd8U, 0x78U, 0x0aU,
0xcfU, 0x49U
)
val encrypted = XChaCha20Poly1305Delegated.encrypt(key, nonce, message, associatedData)
encrypted.hexColumsPrint()
val decrypted = XChaCha20Poly1305Delegated.decrypt(key, nonce, encrypted, associatedData)
println("Decrypted")
decrypted.hexColumsPrint()
println("----------")
encrypted.contentEquals(expected) && decrypted.contentEquals(message)
}
assertTrue {
val message = ubyteArrayOf(
0x00U
)
val associatedData = ubyteArrayOf(
0x00U
)
val key = ubyteArrayOf(
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
)
val nonce = ubyteArrayOf(
0x00U, 0x01U, 0x02U, 0x03U, 0x04U, 0x05U, 0x06U, 0x07U, 0x08U, 0x09U, 0x0aU, 0x0bU,
0x0cU, 0x0dU, 0x0eU, 0x0fU, 0x10U, 0x11U, 0x12U, 0x13U, 0x14U, 0x15U, 0x16U, 0x17U,
)
val expected = ubyteArrayOf(
0xbdU, 0x3bU, 0x8aU, 0xd7U, 0xa1U, 0x9dU, 0xe8U, 0xc4U, 0x55U,
0x84U, 0x6fU, 0xfcU, 0x75U, 0x31U, 0xbfU, 0x0cU, 0x2dU
)
val encrypted = XChaCha20Poly1305Delegated.encrypt(key, nonce, message, associatedData)
val decrypted = XChaCha20Poly1305Delegated.decrypt(key, nonce, encrypted, associatedData)
encrypted.contentEquals(expected) && decrypted.contentEquals(message)
}
}
@Ignore() //"Will fail because nonce is not a parameter any more"
@Test
fun updateableXChaCha20Poly1305() {
assertTrue {
val message = ("Ladies and Gentlemen of the class of '99: If I could offer you " +
"only one tip for the future, sunscreen would be it.").encodeToUByteArray()
val associatedData = ubyteArrayOf(
0x50U, 0x51U, 0x52U, 0x53U, 0xc0U, 0xc1U, 0xc2U, 0xc3U, 0xc4U, 0xc5U, 0xc6U, 0xc7U
)
val key = ubyteArrayOf(
0x80U, 0x81U, 0x82U, 0x83U, 0x84U, 0x85U, 0x86U, 0x87U,
0x88U, 0x89U, 0x8aU, 0x8bU, 0x8cU, 0x8dU, 0x8eU, 0x8fU,
0x90U, 0x91U, 0x92U, 0x93U, 0x94U, 0x95U, 0x96U, 0x97U,
0x98U, 0x99U, 0x9aU, 0x9bU, 0x9cU, 0x9dU, 0x9eU, 0x9fU,
)
val nonce = ubyteArrayOf(
0x40U, 0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U,
0x48U, 0x49U, 0x4aU, 0x4bU, 0x4cU, 0x4dU, 0x4eU, 0x4fU,
0x50U, 0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x57U,
)
val expected = ubyteArrayOf(
0xbdU, 0x6dU, 0x17U, 0x9dU, 0x3eU, 0x83U, 0xd4U, 0x3bU,
0x95U, 0x76U, 0x57U, 0x94U, 0x93U, 0xc0U, 0xe9U, 0x39U,
0x57U, 0x2aU, 0x17U, 0x00U, 0x25U, 0x2bU, 0xfaU, 0xccU,
0xbeU, 0xd2U, 0x90U, 0x2cU, 0x21U, 0x39U, 0x6cU, 0xbbU,
0x73U, 0x1cU, 0x7fU, 0x1bU, 0x0bU, 0x4aU, 0xa6U, 0x44U,
0x0bU, 0xf3U, 0xa8U, 0x2fU, 0x4eU, 0xdaU, 0x7eU, 0x39U,
0xaeU, 0x64U, 0xc6U, 0x70U, 0x8cU, 0x54U, 0xc2U, 0x16U,
0xcbU, 0x96U, 0xb7U, 0x2eU, 0x12U, 0x13U, 0xb4U, 0x52U,
0x2fU, 0x8cU, 0x9bU, 0xa4U, 0x0dU, 0xb5U, 0xd9U, 0x45U,
0xb1U, 0x1bU, 0x69U, 0xb9U, 0x82U, 0xc1U, 0xbbU, 0x9eU,
0x3fU, 0x3fU, 0xacU, 0x2bU, 0xc3U, 0x69U, 0x48U, 0x8fU,
0x76U, 0xb2U, 0x38U, 0x35U, 0x65U, 0xd3U, 0xffU, 0xf9U,
0x21U, 0xf9U, 0x66U, 0x4cU, 0x97U, 0x63U, 0x7dU, 0xa9U,
0x76U, 0x88U, 0x12U, 0xf6U, 0x15U, 0xc6U, 0x8bU, 0x13U,
0xb5U, 0x2eU, 0xc0U, 0x87U, 0x59U, 0x24U, 0xc1U, 0xc7U,
0x98U, 0x79U, 0x47U, 0xdeU, 0xafU, 0xd8U, 0x78U, 0x0aU,
0xcfU, 0x49U
)
// val xChaChaPoly = XChaCha20Poly1305Delegated(key, associatedData)
// val firstChunk = xChaChaPoly.encrypt(message)
// val finalChunk = xChaChaPoly.finishEncryption().first
// val result = firstChunk + finalChunk
// result.contentEquals(expected)
1 == 1
}
assertTrue {
val message = ubyteArrayOf(
0x00U
)
val associatedData = ubyteArrayOf(
0x00U
)
val key = ubyteArrayOf(
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
)
val nonce = ubyteArrayOf(
0x00U, 0x01U, 0x02U, 0x03U, 0x04U, 0x05U, 0x06U, 0x07U, 0x08U, 0x09U, 0x0aU, 0x0bU,
0x0cU, 0x0dU, 0x0eU, 0x0fU, 0x10U, 0x11U, 0x12U, 0x13U, 0x14U, 0x15U, 0x16U, 0x17U,
)
val expected = ubyteArrayOf(
0xbdU, 0x3bU, 0x8aU, 0xd7U, 0xa1U, 0x9dU, 0xe8U, 0xc4U, 0x55U,
0x84U, 0x6fU, 0xfcU, 0x75U, 0x31U, 0xbfU, 0x0cU, 0x2dU
)
// val xChaChaPoly = XChaCha20Poly1305Delegated(key, associatedData)
// val firstChunk = xChaChaPoly.encrypt(message)
// val finalChunk = xChaChaPoly.finishEncryption().first
// val result = firstChunk + finalChunk
// result.contentEquals(expected)
1 == 1
}
}
@Test
fun testStreamingImpl() = testBlocking {
Initializer.initialize()
val key = UByteArray(32) { 0U }
val state = ubyteArrayOf(
0x2DU, 0xDBU, 0xC7U, 0xB2U, 0x03U, 0xBCU, 0xC3U, 0x22U, 0xBDU, 0x0CU, 0xBAU, 0x82U, 0xADU, 0x77U, 0x79U, 0x44U,
0xE6U, 0x8FU, 0xA9U, 0x94U, 0x89U, 0xB1U, 0xDFU, 0xBEU, 0x00U, 0x9FU, 0x69U, 0xECU, 0x21U, 0x88U, 0x47U, 0x55U,
0x01U, 0x00U, 0x00U, 0x00U, 0xC5U, 0x55U, 0x06U, 0x38U, 0xEBU, 0xA3U, 0x12U, 0x7BU, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U,
)
val header = ubyteArrayOf(
0x49U, 0x62U, 0x22U, 0x03U, 0xB7U, 0x46U, 0x11U, 0x97U, 0x8FU, 0x46U, 0x4AU, 0x3BU, 0x2FU, 0x2AU, 0x81U, 0x03U,
0xC5U, 0x55U, 0x06U, 0x38U, 0xEBU, 0xA3U, 0x12U, 0x7BU,
)
val expected = ubyteArrayOf(
0xAFU, 0xD3U, 0x2DU, 0x59U, 0xB8U, 0xC4U, 0x66U, 0x2EU, 0x47U, 0x29U, 0xC6U, 0xF9U, 0x93U, 0x4BU, 0x09U, 0x27U,
0x24U, 0xDDU, 0xF3U, 0x05U, 0x48U, 0x94U, 0x67U, 0x10U, 0x00U, 0x21U, 0x85U, 0x22U, 0x96U, 0x3CU, 0xCEU, 0x8EU,
0xB7U, 0x53U, 0x9DU, 0x46U, 0xF5U, 0x3CU, 0x5EU, 0x48U, 0x9BU, 0x8CU, 0x13U, 0xB7U, 0x28U, 0x6BU, 0xB3U, 0x6CU,
0x3AU, 0x04U, 0xB7U, 0x25U, 0xB9U, 0x50U, 0x45U, 0x08U, 0x0BU, 0x89U, 0xA2U, 0x0FU, 0x70U, 0xCCU, 0x60U, 0x1BU,
0xC3U, 0x17U, 0x35U, 0x9FU, 0xAEU, 0x82U, 0x51U, 0x43U, 0x1BU, 0x9DU, 0x53U, 0x9EU, 0xE2U, 0xAFU, 0x20U, 0x1FU,
0xFDU, 0x03U, 0x59U, 0x11U, 0x51U, 0x9EU, 0xACU, 0x83U, 0xCDU, 0x78U, 0xD1U, 0xD0U, 0xE5U, 0xD7U, 0x0EU, 0x41U,
0xDEU, 0xFBU, 0x5CU, 0x7FU, 0x1CU, 0x26U, 0x32U, 0x2CU, 0x51U, 0xF6U, 0xEFU, 0xC6U, 0x34U, 0xC4U, 0xACU, 0x6CU,
0xE8U, 0xF9U, 0x4BU, 0xABU, 0xA3U,
)
val encryptor = XChaCha20Poly1305Delegated(key, state, header, false)
val decryptor = XChaCha20Poly1305Delegated(key, state, header, true)
val data = UByteArray(100) { 0U }
val result = encryptor.encrypt(data)
val decrypted = decryptor.decrypt(result)
println("Encrypted -----------")
result.hexColumsPrint()
println("Encrypted end -----------")
println("Decrypted -----------")
decrypted.hexColumsPrint()
println("Decrypted end -----------")
assertTrue {
expected.contentEquals(result) && decrypted.contentEquals(data)
}
val messedUpTag = result.copyOf()
messedUpTag[messedUpTag.size - 3] = 0U
messedUpTag[messedUpTag.size - 2] = 0U
messedUpTag[messedUpTag.size - 1] = 0U
assertFails {
val decryptorForWrongTag = XChaCha20Poly1305Delegated(key, state, header, true)
val plaintext = decryptorForWrongTag.decrypt(messedUpTag)
println("Decrypted with wrong tag -----------")
plaintext.hexColumsPrint()
println("Decrypted with wrong tag end -----------")
}
}
}

View File

@ -1,46 +0,0 @@
package com.ionspin.kotlin.crypto.hash.blake2b
import com.ionspin.kotlin.crypto.Crypto
import com.ionspin.kotlin.crypto.CryptoPrimitives
import com.ionspin.kotlin.crypto.Initializer
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.testBlocking
import com.ionspin.kotlin.crypto.util.toHexString
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertTrue
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 09-Jun-2020
*/
class Blake2bTest {
@Test
fun statelessSimpleTest() = testBlocking {
Initializer.initialize()
val expected = "a71079d42853dea26e453004338670a53814b78137ffbed07603a41d76a483aa9bc33b582f77d30a65e6f29a89" +
"6c0411f38312e1d66e0bf16386c86a89bea572"
val result = CryptoPrimitives.Blake2b.stateless("test".encodeToUByteArray()).toHexString()
// println("Result: $result")
assertTrue { result == expected }
}
//This is a bad test since it's not larger than one block
//but for now I'm testing that the platform library is being correctly called
@Test
fun updateableSimpleTest() = testBlocking {
Initializer.initialize()
val expected = "a71079d42853dea26e453004338670a53814b78137ffbed07603a41d76a483aa9bc33b582f77d30a65e6f29a89" +
"6c0411f38312e1d66e0bf16386c86a89bea572"
val blake2b = CryptoPrimitives.Blake2b.updateable()
blake2b.update("t".encodeToUByteArray())
blake2b.update(("est".encodeToUByteArray()))
val result = blake2b.digest().toHexString()
// println("Result: $result")
assertTrue { result == expected }
}
}

View File

@ -1,46 +0,0 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.ionspin.kotlin.crypto.Crypto
import com.ionspin.kotlin.crypto.CryptoPrimitives
import com.ionspin.kotlin.crypto.Initializer
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.testBlocking
import com.ionspin.kotlin.crypto.util.toHexString
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertTrue
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 07-Jun-2020
*/
class Sha256Test {
@BeforeTest
fun beforeTest() = testBlocking {
Initializer.initialize()
}
@Test
fun statelessSimpleTest() = testBlocking {
Initializer.initialize()
val expected = "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
val result = CryptoPrimitives.Sha256.stateless("test".encodeToUByteArray()).toHexString()
// println("Result: $result")
assertTrue { result == expected }
}
//This is a bad test since it's not larger than one block
//but for now I'm testing that the platform library is being correctly called
@Test
fun updateableSimpleTest() = testBlocking {
Initializer.initialize()
val expected = "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
val sha256 = CryptoPrimitives.Sha256.updateable()
sha256.update("t".encodeToUByteArray())
sha256.update(("est".encodeToUByteArray()))
val result = sha256.digest().toHexString()
// println("Result: $result")
assertTrue { result == expected }
}
}

View File

@ -1,48 +0,0 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.ionspin.kotlin.crypto.Crypto
import com.ionspin.kotlin.crypto.CryptoPrimitives
import com.ionspin.kotlin.crypto.Initializer
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.testBlocking
import com.ionspin.kotlin.crypto.util.toHexString
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertTrue
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 07-Jun-2020
*/
class Sha512Test {
@BeforeTest
fun beforeTest() = testBlocking {
Initializer.initialize()
}
@Test
fun statelessSimpleTest() = testBlocking {
Initializer.initialize()
val expected = "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67" +
"b143732c304cc5fa9ad8e6f57f50028a8ff"
val result = CryptoPrimitives.Sha512.stateless("test".encodeToUByteArray()).toHexString()
// println("Result: $result")
assertTrue { result == expected }
}
//This is a bad test since it's not larger than one block
//but for now I'm testing that the platform library is being correctly called
@Test
fun updateableSimpleTest() = testBlocking {
Initializer.initialize()
val expected = "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67" +
"b143732c304cc5fa9ad8e6f57f50028a8ff"
val sha512 = CryptoPrimitives.Sha512.updateable()
sha512.update("t".encodeToUByteArray())
sha512.update(("est".encodeToUByteArray()))
val result = sha512.digest().toHexString()
// println("Result: $result")
assertTrue { result == expected }
}
}

View File

@ -1,50 +0,0 @@
package com.ionspin.kotlin.crypto.highlevel
import com.ionspin.kotlin.crypto.Crypto
import com.ionspin.kotlin.crypto.Initializer
import com.ionspin.kotlin.crypto.SymmetricKey
import com.ionspin.kotlin.crypto.hash.decodeToString
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.hexColumsPrint
import com.ionspin.kotlin.crypto.util.testBlocking
import kotlin.test.Test
import kotlin.test.assertTrue
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 09-Jul-2020
*/
class EncryptionTest {
@Test
fun testMultipartEncryption() = testBlocking {
Initializer.initialize()
val plaintext = ("pUoR4JVXJUeMKNkt6ZGGzEdTo33ajNGXwXpivBKA0XKs8toGRYI9Eul4bELRDkaQDNhd4vZseEFU" +
"ojsAn3c9zIifIrMnydSivHVZ2pBtpAQwYoJhYmEsfE0tROGnOwFWyB9K6LRSv1gB3YqKR9VyM8mpRoUM3UCRRjyiX7bnKdCE1" +
"EiX0myiwcY1nUKTgB3keERWtMU07hX7bCtao5nRvDofSj3o3IInHRQh6opltr5asQwn4m1qn029QF").encodeToUByteArray()
val associatedData = "Additional data 1".encodeToUByteArray()
val keyValue = UByteArray(32) { it.toUByte() }
val key = SymmetricKey(keyValue)
val encryptor = Crypto.Encryption.createMultipartEncryptor(key)
val header = encryptor.startEncryption()
val ciphertext1 = encryptor.encryptPartialData(plaintext.sliceArray(0 until 100), associatedData)
val ciphertext2 = encryptor.encryptPartialData(plaintext.sliceArray(100 until 200))
val ciphertext3 = encryptor.encryptPartialData(plaintext.sliceArray(200 until 250))
//decrypt
val decryptor = Crypto.Encryption.createMultipartDecryptor(key, header)
val plaintext1 = decryptor.decryptPartialData(ciphertext1, associatedData)
val plaintext2 = decryptor.decryptPartialData(ciphertext2)
val plaintext3 = decryptor.decryptPartialData(ciphertext3)
val combinedPlaintext = plaintext1.data + plaintext2.data + plaintext3.data
assertTrue {
plaintext.contentEquals(combinedPlaintext)
}
encryptor.cleanup()
decryptor.cleanup()
}
}

View File

@ -1,37 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
package com.ionspin.kotlin.crypto.util
import kotlin.coroutines.Continuation
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.startCoroutine
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 20-Jul-2019
*/
fun testBlocking(block : suspend () -> Unit) {
val continuation = Continuation<Unit>(EmptyCoroutineContext) {
//Do nothing
if (it.isFailure) {
throw it.exceptionOrNull()!!
}
}
block.startCoroutine(continuation)
}

View File

@ -1,43 +0,0 @@
package com.ionspin.kotlin.crypto
import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumInterface
import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumLoader
/* 1.4-M1 has some weirdness with static/objects, or I'm misusing something, not sure */
lateinit var sodiumPointer : JsSodiumInterface
var sodiumLoaded: Boolean = false
fun getSodium() : JsSodiumInterface = sodiumPointer
//fun getSodiumAdvanced() : JsSodiumAdvancedInterface = js("sodiumPointer.libsodium")
fun setSodiumPointer(jsSodiumInterface: JsSodiumInterface) {
js("sodiumPointer = jsSodiumInterface")
}
fun getSodiumLoaded() : Boolean = sodiumLoaded
fun setSodiumLoaded(loaded: Boolean) {
js("sodiumLoaded = loaded")
}
actual object Initializer {
private var isPlatformInitialized = false
actual suspend fun initialize() {
JsSodiumLoader.load()
isPlatformInitialized = true
}
actual fun initializeWithCallback(done: () -> Unit) {
JsSodiumLoader.loadWithCallback {
isPlatformInitialized = true
done()
}
}
actual fun isInitialized(): Boolean {
return isPlatformInitialized
}
}

View File

@ -1,60 +0,0 @@
package ext.libsodium.com.ionspin.kotlin.crypto
import org.khronos.webgl.Uint8Array
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 27-May-2020
*/
interface JsSodiumInterface {
fun randombytes_buf(numberOfBytes: Int): Uint8Array
fun crypto_generichash(hashLength: Int, inputMessage: Uint8Array, key: Uint8Array,): Uint8Array
fun crypto_hash_sha256(message: Uint8Array): Uint8Array
fun crypto_hash_sha512(message: Uint8Array): Uint8Array
//Updateable
fun crypto_generichash_init(key : Uint8Array, hashLength: Int) : dynamic
fun crypto_generichash_update(state: dynamic, inputMessage: Uint8Array)
fun crypto_generichash_final(state: dynamic, hashLength: Int) : Uint8Array
fun crypto_hash_sha256_init() : dynamic
fun crypto_hash_sha256_update(state: dynamic, message: Uint8Array)
fun crypto_hash_sha256_final(state: dynamic): Uint8Array
fun crypto_hash_sha512_init() : dynamic
fun crypto_hash_sha512_update(state: dynamic, message: Uint8Array)
fun crypto_hash_sha512_final(state: dynamic): Uint8Array
//XChaCha20Poly1305
fun crypto_aead_xchacha20poly1305_ietf_encrypt(message: Uint8Array, associatedData: Uint8Array, secretNonce: Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array
fun crypto_aead_xchacha20poly1305_ietf_decrypt(secretNonce: Uint8Array, ciphertext: Uint8Array, associatedData: Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array
//XChaCha20Poly1305
//encrypt
fun crypto_secretstream_xchacha20poly1305_init_push(header: Uint8Array) : dynamic
fun crypto_secretstream_xchacha20poly1305_push(state: dynamic, message: Uint8Array, associatedData: Uint8Array, tag: UByte) : Uint8Array
//decrypt
fun crypto_secretstream_xchacha20poly1305_init_pull(header: Uint8Array, key: Uint8Array) : dynamic
fun crypto_secretstream_xchacha20poly1305_pull(state: dynamic, ciphertext: Uint8Array, associatedData: Uint8Array) : dynamic
//util
fun memzero(array: Uint8Array)
}

View File

@ -1,56 +0,0 @@
package ext.libsodium.com.ionspin.kotlin.crypto
import com.ionspin.kotlin.crypto.getSodiumLoaded
import com.ionspin.kotlin.crypto.setSodiumPointer
import com.ionspin.kotlin.crypto.sodiumLoaded
import ext.libsodium.*
import kotlin.coroutines.Continuation
import kotlin.coroutines.suspendCoroutine
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 27-May-2020
*/
object JsSodiumLoader {
class _EmitJsSodiumFunction {
init {
println(::crypto_generichash)
println(::crypto_hash_sha256)
println(::crypto_hash_sha512)
println(::crypto_hash_sha256_init)
}
}
fun storeSodium(promisedSodium: dynamic, continuation: Continuation<Unit>) {
setSodiumPointer(promisedSodium)
sodiumLoaded = true
continuation.resumeWith(Result.success(Unit))
}
suspend fun load() = suspendCoroutine<Unit> { continuation ->
console.log(getSodiumLoaded())
if (!getSodiumLoaded()) {
val libsodiumModule = js("\$module\$libsodium_wrappers_sumo")
_libsodiumPromise.then<dynamic> { storeSodium(libsodiumModule, continuation) }
} else {
continuation.resumeWith(Result.success(Unit))
}
}
fun loadWithCallback(doneCallback: () -> (Unit)) {
console.log(getSodiumLoaded())
if (!getSodiumLoaded()) {
val libsodiumModule = js("\$module\$libsodium_wrappers_sumo")
_libsodiumPromise.then<dynamic> {
setSodiumPointer(libsodiumModule)
sodiumLoaded = true
doneCallback.invoke()
}
} else {
doneCallback.invoke()
}
}
}

View File

@ -1,27 +0,0 @@
package ext.libsodium.com.ionspin.kotlin.crypto
import org.khronos.webgl.Uint8Array
import org.khronos.webgl.get
import org.khronos.webgl.set
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 25-Jun-2020
*
* TODO investigate using unsafe cast
*/
fun UByteArray.toUInt8Array() : Uint8Array {
val uint8Result = Uint8Array(toByteArray().toTypedArray())
return uint8Result
}
fun Uint8Array.toUByteArray() : UByteArray {
val result = UByteArray(length)
for (i in 0 until length) {
result[i] = get(i).toUByte()
}
return result
}

View File

@ -1,43 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
package com.ionspin.kotlin.crypto
import org.khronos.webgl.get
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 21-Sep-2019
*/
actual object SRNG {
var counter = 0
actual fun getRandomBytes(amount: Int): UByteArray {
val randomBytes = getSodium().randombytes_buf(amount)
val randomBytesUByteArray = UByteArray(amount) {
0U
}
for (i in 0 until amount) {
js("""
randomBytesUByteArray[i] = randomBytes[i]
""")
}
return randomBytesUByteArray
}
}

View File

@ -1,130 +0,0 @@
package com.ionspin.kotlin.crypto.authenticated
import com.ionspin.kotlin.crypto.InvalidTagException
import com.ionspin.kotlin.crypto.getSodium
import com.ionspin.kotlin.crypto.util.hexColumsPrint
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
import org.khronos.webgl.Uint8Array
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 25-Jun-2020
*/
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 14-Jun-2020
*/
actual class XChaCha20Poly1305Delegated internal actual constructor() {
actual companion object {
actual fun encrypt(
key: UByteArray,
nonce: UByteArray,
message: UByteArray,
associatedData: UByteArray
): UByteArray {
val encrypted = getSodium().crypto_aead_xchacha20poly1305_ietf_encrypt(
message.toUInt8Array(),
associatedData.toUInt8Array(),
Uint8Array(0),
nonce.toUInt8Array(),
key.toUInt8Array()
)
return encrypted.toUByteArray()
}
actual fun decrypt(
key: UByteArray,
nonce: UByteArray,
ciphertext: UByteArray,
associatedData: UByteArray
): UByteArray {
val decrypted = getSodium().crypto_aead_xchacha20poly1305_ietf_decrypt(
Uint8Array(0),
ciphertext.toUInt8Array(),
associatedData.toUInt8Array(),
nonce.toUInt8Array(),
key.toUInt8Array()
)
return decrypted.toUByteArray()
}
}
var state : dynamic = null
var isInitialized = false
var isEncryptor = false
actual fun initializeForEncryption(key: UByteArray) : UByteArray {
println("Initializaing for encryption")
val stateAndHeader = getSodium().crypto_secretstream_xchacha20poly1305_init_push(key.toUInt8Array())
state = stateAndHeader.state
val header = stateAndHeader.header as Uint8Array
console.log(state)
console.log(header)
println("Done initializaing for encryption")
isInitialized = true
isEncryptor = true
return header.toUByteArray()
}
actual fun initializeForDecryption(key: UByteArray, header: UByteArray) {
println("Initializing for decryption")
header.hexColumsPrint()
state = getSodium().crypto_secretstream_xchacha20poly1305_init_pull(header.toUInt8Array(), key.toUInt8Array())
console.log(state)
isInitialized = true
isEncryptor = false
}
internal actual constructor(
key: UByteArray,
testState: UByteArray,
testHeader: UByteArray,
isDecryptor: Boolean
) : this() {
state = getSodium().crypto_secretstream_xchacha20poly1305_init_pull(testHeader.toUInt8Array(), key.toUInt8Array())
console.log(state)
println("Done initializaing test state")
isInitialized = true
isEncryptor = !isDecryptor
}
actual fun encrypt(data: UByteArray, associatedData: UByteArray): UByteArray {
if (!isInitialized) {
throw RuntimeException("Not initalized!")
}
if (!isEncryptor) {
throw RuntimeException("Initialized as decryptor, attempted to use as encryptor")
}
val encrypted = getSodium().crypto_secretstream_xchacha20poly1305_push(state, data.toUInt8Array(), associatedData.toUInt8Array(), 0U)
return encrypted.toUByteArray()
}
actual fun decrypt(data: UByteArray, associatedData: UByteArray): UByteArray {
if (!isInitialized) {
throw RuntimeException("Not initalized!")
}
if (isEncryptor) {
throw RuntimeException("Initialized as encryptor, attempted to use as decryptor")
}
val decryptedWithTag = getSodium().crypto_secretstream_xchacha20poly1305_pull(state, data.toUInt8Array(), associatedData.toUInt8Array())
val decrypted = decryptedWithTag.message as Uint8Array
val validTag = decryptedWithTag.tag
if (validTag != 0U) {
println("Tag validation failed")
throw InvalidTagException()
}
return decrypted.toUByteArray()
}
actual fun cleanup() {
//TODO JS cleanup
}
}

View File

@ -1,60 +0,0 @@
package com.ionspin.kotlin.crypto.hash.blake2b
import com.ionspin.kotlin.crypto.getSodium
import org.khronos.webgl.Uint8Array
import org.khronos.webgl.get
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 14-Jul-2019
*/
actual class Blake2bDelegated actual constructor(key: UByteArray?, val hashLength: Int) : Blake2bMultipart {
override val MAX_HASH_BYTES: Int = 64
val state : dynamic
init {
state = getSodium().crypto_generichash_init(
Uint8Array(key?.toByteArray()?.toTypedArray() ?: arrayOf()),
hashLength
)
}
override fun update(data: UByteArray) {
getSodium().crypto_generichash_update(state, Uint8Array(data.toByteArray().toTypedArray()))
}
override fun digest(): UByteArray {
val hashed = getSodium().crypto_generichash_final(state, hashLength)
val hash = UByteArray(hashLength)
for (i in 0 until hashLength) {
hash[i] = hashed[i].toUByte()
}
return hash
}
}
actual object Blake2bDelegatedStateless : Blake2b {
override val MAX_HASH_BYTES: Int = 64
override fun digest(inputMessage: UByteArray, key: UByteArray, hashLength: Int): UByteArray {
val hashed = getSodium().crypto_generichash(hashLength,
Uint8Array(inputMessage.toByteArray().toTypedArray()),
Uint8Array(key.toByteArray().toTypedArray())
)
val hash = UByteArray(hashLength)
for (i in 0 until hashLength) {
hash[i] = hashed[i].toUByte()
}
return hash
}
}

View File

@ -1,49 +0,0 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.ionspin.kotlin.crypto.getSodium
import org.khronos.webgl.Uint8Array
import org.khronos.webgl.get
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 17-Jul-2019
*/
actual class Sha256Delegated : Sha256 {
val state : dynamic
init {
state = getSodium().crypto_hash_sha256_init()
}
override fun update(data: UByteArray) {
getSodium().crypto_hash_sha256_update(state, Uint8Array(data.toByteArray().toTypedArray()))
}
override fun digest(): UByteArray {
val hashed = getSodium().crypto_hash_sha256_final(state)
val hash = UByteArray(Sha256StatelessDelegated.MAX_HASH_BYTES)
console.log(hashed)
for (i in 0 until Sha256StatelessDelegated.MAX_HASH_BYTES) {
hash[i] = hashed[i].toUByte()
}
return hash
}
}
actual object Sha256StatelessDelegated : StatelessSha256 {
override fun digest(inputMessage: UByteArray): UByteArray {
val hashed = getSodium().crypto_hash_sha256(Uint8Array(inputMessage.toByteArray().toTypedArray()))
val hash = UByteArray(MAX_HASH_BYTES)
for (i in 0 until MAX_HASH_BYTES) {
hash[i] = hashed[i].toUByte()
}
return hash
}
}

View File

@ -1,47 +0,0 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.ionspin.kotlin.crypto.getSodium
import org.khronos.webgl.Uint8Array
import org.khronos.webgl.get
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 17-Jul-2019
*/
actual class Sha512Delegated : Sha512Multipart {
val state : dynamic
init {
state = getSodium().crypto_hash_sha512_init()
}
override fun update(data: UByteArray) {
getSodium().crypto_hash_sha512_update(state, Uint8Array(data.toByteArray().toTypedArray()))
}
override fun digest(): UByteArray {
val hashed = getSodium().crypto_hash_sha512_final(state)
val hash = UByteArray(Sha512StatelessDelegated.MAX_HASH_BYTES)
for (i in 0 until Sha512StatelessDelegated.MAX_HASH_BYTES) {
hash[i] = hashed[i].toUByte()
}
return hash
}
}
actual object Sha512StatelessDelegated : Sha512 {
override fun digest(inputMessage: UByteArray): UByteArray {
val hashed = getSodium().crypto_hash_sha512(Uint8Array(inputMessage.toByteArray().toTypedArray()))
val hash = UByteArray(Sha512StatelessDelegated.MAX_HASH_BYTES)
for (i in 0 until Sha512StatelessDelegated.MAX_HASH_BYTES) {
hash[i] = hashed[i].toUByte()
}
return hash
}
}

View File

@ -1,28 +0,0 @@
@file:JsModule("libsodium-wrappers-sumo")
@file:JsNonModule
package ext.libsodium
import org.khronos.webgl.Uint8Array
import kotlin.js.Promise
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 25-May-2020
*/
@JsName("ready")
external val _libsodiumPromise : Promise<dynamic>
external fun crypto_generichash(hashLength: Int, inputMessage: Uint8Array) : Uint8Array
external fun crypto_hash_sha256(message: Uint8Array) : Uint8Array
external fun crypto_hash_sha512(message: Uint8Array) : Uint8Array
external fun crypto_hash_sha256_init(): dynamic

View File

@ -1,52 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
package com.ionspin.kotlin.crypto
import com.ionspin.kotlin.crypto.util.testBlocking
import ext.libsodium.com.ionspin.kotlin.crypto.JsSodiumLoader
import kotlin.test.Test
import kotlin.test.assertTrue
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 05-Jan-2020
*/
class SRNGJsTest {
@Test
fun testJsSrng() = testBlocking {
JsSodiumLoader.load()
val bytes1 = SRNG.getRandomBytes(10)
val bytes2 = SRNG.getRandomBytes(10)
// println("BYTES1\n")
// bytes1.forEach {
// print(it.toString(16).padStart(2, '0'))
// }
// println("BYTES2\n")
// bytes2.forEach {
// print(it.toString(16).padStart(2, '0'))
// }
assertTrue {
!bytes1.contentEquals(bytes2) &&
bytes1.size == 10 &&
bytes2.size == 10
}
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
package com.ionspin.kotlin.crypto.util
//
//import kotlinx.coroutines.GlobalScope
//import kotlinx.coroutines.promise
//
//
///**
// * Created by Ugljesa Jovanovic
// * ugljesa.jovanovic@ionspin.com
// * on 20-Jul-2019
// */
//actual fun testBlocking(block: suspend ()-> Unit) : dynamic = GlobalScope.promise { block() }

View File

@ -1,25 +0,0 @@
package com.ionspin.kotlin.crypto
import com.goterl.lazycode.lazysodium.SodiumJava
actual object Initializer {
private var isPlatformInitialized = false
lateinit var sodium : SodiumJava
actual suspend fun initialize() {
sodium = SodiumJava()
isPlatformInitialized = true
}
actual fun initializeWithCallback(done: () -> Unit) {
sodium = SodiumJava()
isPlatformInitialized = true
done()
}
actual fun isInitialized(): Boolean {
return isPlatformInitialized
}
}

View File

@ -1,34 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
package com.ionspin.kotlin.crypto
import java.security.SecureRandom
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 21-Sep-2019
*/
actual object SRNG {
val secureRandom = SecureRandom()
actual fun getRandomBytes(amount: Int): UByteArray {
val byteArray = ByteArray(amount)
secureRandom.nextBytes(byteArray)
return byteArray.asUByteArray()
}
}

View File

@ -1,142 +0,0 @@
package com.ionspin.kotlin.crypto.authenticated
import com.goterl.lazycode.lazysodium.SodiumJava
import com.goterl.lazycode.lazysodium.interfaces.SecretStream
import com.ionspin.kotlin.crypto.InvalidTagException
import com.ionspin.kotlin.crypto.util.hexColumsPrint
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 14-Jun-2020
*/
actual class XChaCha20Poly1305Delegated internal actual constructor() {
actual companion object {
actual fun encrypt(
key: UByteArray,
nonce: UByteArray,
message: UByteArray,
associatedData: UByteArray
): UByteArray {
val ciphertext = ByteArray(message.size + 16)
SodiumJava().crypto_aead_xchacha20poly1305_ietf_encrypt(
ciphertext,
longArrayOf(ciphertext.size.toLong()),
message.toByteArray(),
message.size.toLong(),
associatedData.toByteArray(),
associatedData.size.toLong(),
null,
nonce.toByteArray(),
key.toByteArray()
)
return ciphertext.asUByteArray()
}
actual fun decrypt(
key: UByteArray,
nonce: UByteArray,
ciphertext: UByteArray,
associatedData: UByteArray
): UByteArray {
val message = ByteArray(ciphertext.size - 16)
SodiumJava().crypto_aead_xchacha20poly1305_ietf_decrypt(
message,
longArrayOf(ciphertext.size.toLong()),
null,
ciphertext.toByteArray(),
ciphertext.size.toLong(),
associatedData.toByteArray(),
associatedData.size.toLong(),
nonce.toByteArray(),
key.toByteArray()
)
return message.asUByteArray()
}
}
val state : SecretStream.State = SecretStream.State()
val sodium = SodiumJava()
var isInitialized = false
var isEncryptor = false
internal actual constructor(
key: UByteArray,
testState: UByteArray,
testHeader: UByteArray,
isDecryptor: Boolean
) : this() {
state.k = testState.sliceArray(0 until 32).toByteArray()
state.nonce = testState.sliceArray(32 until 44).toByteArray()
isInitialized = true
isEncryptor = !isDecryptor
}
actual fun initializeForEncryption(key: UByteArray) : UByteArray {
val header = UByteArray(24)
sodium.crypto_secretstream_xchacha20poly1305_init_push(state, header.asByteArray(), key.asByteArray())
isInitialized = true
isEncryptor = true
return header
}
actual fun initializeForDecryption(key: UByteArray, header: UByteArray) {
sodium.crypto_secretstream_xchacha20poly1305_init_pull(state, header.asByteArray(), key.asByteArray())
isInitialized = true
isEncryptor = false
}
actual fun encrypt(data: UByteArray, associatedData: UByteArray): UByteArray {
if (!isInitialized) {
throw RuntimeException("Not initalized!")
}
if (!isEncryptor) {
throw RuntimeException("Initialized as decryptor, attempted to use as encryptor")
}
val ciphertext = ByteArray(1 + data.size + 16)
sodium.crypto_secretstream_xchacha20poly1305_push(
state, ciphertext, null,
data.asByteArray(), data.size.toLong(),
associatedData.asByteArray(), associatedData.size.toLong(),
0
)
return ciphertext.asUByteArray()
}
actual fun decrypt(data: UByteArray, associatedData: UByteArray): UByteArray {
if (!isInitialized) {
throw RuntimeException("Not initalized!")
}
if (isEncryptor) {
throw RuntimeException("Initialized as encryptor, attempted to use as decryptor")
}
val plaintext = ByteArray(data.size - 17)
val validTag = sodium.crypto_secretstream_xchacha20poly1305_pull(
state, plaintext, null,
null,
data.asByteArray(),
(data.size).toLong(),
associatedData.asByteArray(),
associatedData.size.toLong()
)
if (validTag != 0) {
println("Tag validation failed")
throw InvalidTagException()
}
return plaintext.asUByteArray()
}
actual fun cleanup() {
sodium.sodium_memzero(state.k, 32)
sodium.sodium_memzero(state.nonce, 12)
}
}

View File

@ -1,40 +0,0 @@
package com.ionspin.kotlin.crypto.hash.blake2b
import com.ionspin.kotlin.crypto.Initializer.sodium
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 14-Jul-2019
*/
actual class Blake2bDelegated actual constructor(key: UByteArray?, val hashLength: Int) : Blake2bMultipart {
val state = ByteArray(sodium.crypto_generichash_statebytes())
init {
sodium.crypto_generichash_init(state,key?.toByteArray() ?: byteArrayOf(), key?.size ?: 0, hashLength)
}
override fun update(data: UByteArray) {
sodium.crypto_generichash_update(state, data.toByteArray(), data.size.toLong())
}
override fun digest(): UByteArray {
val hashed = ByteArray(hashLength)
sodium.crypto_generichash_final(state, hashed, hashLength)
return hashed.asUByteArray()
}
}
actual object Blake2bDelegatedStateless : Blake2b {
override fun digest(inputMessage: UByteArray, key: UByteArray, hashLength: Int): UByteArray {
val hashed = ByteArray(hashLength)
sodium.crypto_generichash(hashed, hashed.size, inputMessage.toByteArray(), inputMessage.size.toLong(), key.toByteArray(), key.size)
return hashed.asUByteArray()
}
}

View File

@ -1,41 +0,0 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.goterl.lazycode.lazysodium.interfaces.Hash
import com.ionspin.kotlin.crypto.Initializer.sodium
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 17-Jul-2019
*/
actual class Sha256Delegated actual constructor() : Sha256 {
val state = Hash.State256()
init {
sodium.crypto_hash_sha256_init(state)
}
override fun update(data: UByteArray) {
sodium.crypto_hash_sha256_update(state, data.toByteArray(), data.size.toLong())
}
override fun digest(): UByteArray {
val hashed = ByteArray(Sha256Properties.MAX_HASH_BYTES)
sodium.crypto_hash_sha256_final(state, hashed)
return hashed.asUByteArray()
}
}
actual object Sha256StatelessDelegated : StatelessSha256 {
override fun digest(inputMessage: UByteArray): UByteArray {
val hashed = ByteArray(Sha256Properties.MAX_HASH_BYTES)
sodium.crypto_hash_sha256(hashed, inputMessage.toByteArray(), inputMessage.size.toLong())
return hashed.asUByteArray()
}
}

View File

@ -1,40 +0,0 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.goterl.lazycode.lazysodium.interfaces.Hash
import com.ionspin.kotlin.crypto.Initializer
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 17-Jul-2019
*/
actual class Sha512Delegated : Sha512Multipart {
val state = Hash.State512()
init {
Initializer.sodium.crypto_hash_sha512_init(state)
}
override fun update(data: UByteArray) {
Initializer.sodium.crypto_hash_sha512_update(state, data.toByteArray(), data.size.toLong())
}
override fun digest(): UByteArray {
val hashed = ByteArray(Sha512Properties.MAX_HASH_BYTES)
Initializer.sodium.crypto_hash_sha512_final(state, hashed)
return hashed.asUByteArray()
}
}
actual object Sha512StatelessDelegated : Sha512 {
override fun digest(inputMessage: UByteArray): UByteArray {
val hashed = ByteArray(Sha512Properties.MAX_HASH_BYTES)
Initializer.sodium.crypto_hash_sha512(hashed, inputMessage.toByteArray(), inputMessage.size.toLong())
return hashed.asUByteArray()
}
}

View File

@ -1,34 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
package com.ionspin.kotlin.crypto.util
import kotlin.coroutines.Continuation
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.startCoroutine
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 20-Jul-2019
*/
//actual fun testBlocking(block: suspend () -> Unit) {
// val continuation = Continuation<Unit>(EmptyCoroutineContext) {
// println("Done")
// }
// block.startCoroutine(continuation)
//
//}

View File

@ -1,9 +0,0 @@
package com.ionspin.kotlin.crypto.hash.sha
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 07-Jun-2020
*/
import platform.posix.*
//import cin

View File

@ -1,44 +0,0 @@
//We'll handle SRNG through libsodium
///*
// * Copyright 2019 Ugljesa Jovanovic
// *
// * 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.
// */
//
//package com.ionspin.kotlin.crypto
//
//import kotlinx.cinterop.*
//import platform.windows.*
//
///**
// * Created by Ugljesa Jovanovic
// * ugljesa.jovanovic@ionspin.com
// * on 21-Sep-2019
// */
//actual object SRNG {
// private val advapi by lazy { LoadLibraryA("ADVAPI32.DLL")}
//
// private val advapiRandom by lazy {
// GetProcAddress(advapi, "SystemFunction036")?.reinterpret<CFunction<Function2<CPointer<ByteVar>, ULong, Int>>>() ?: error("Failed getting advapi random")
// }
//
// @Suppress("EXPERIMENTAL_UNSIGNED_LITERALS")
// actual fun getRandomBytes(amount: Int): UByteArray {
// memScoped {
// val randArray = allocArray<ByteVar>(amount)
// val pointer = randArray.getPointer(this)
// val status = advapiRandom(pointer.reinterpret(), amount.convert())
// return UByteArray(amount) { pointer[it].toUByte() }
// }
// }
//}

View File

@ -1,6 +0,0 @@
headers = sodium.h
headerFilter = sodium.h sodium/**
#staticLibraries = libsodium.a
#libraryPaths = sodiumWrapper/lib
#compilerOpts = -I./sodiumWrapper/include
linkerOpts =

View File

@ -1,30 +0,0 @@
@file:Suppress("VARIABLE_IN_SINGLETON_WITHOUT_THREAD_LOCAL")
package com.ionspin.kotlin.crypto
import libsodium.sodium_init
import kotlin.native.concurrent.AtomicInt
actual object Initializer {
private var isPlatformInitialized : AtomicInt = AtomicInt(0)
actual suspend fun initialize() {
if (isPlatformInitialized.compareAndSet(0, 1)) {
sodium_init()
}
}
actual fun initializeWithCallback(done: () -> Unit) {
if (isPlatformInitialized.compareAndSet(0, 1)) {
sodium_init()
}
done()
}
actual fun isInitialized(): Boolean {
return isPlatformInitialized.value != 0
}
}

View File

@ -1,40 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
package com.ionspin.kotlin.crypto
import kotlinx.cinterop.*
import libsodium.randombytes_buf
import platform.posix.*
//import libsod
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 21-Sep-2019
*/
actual object SRNG {
@Suppress("EXPERIMENTAL_UNSIGNED_LITERALS")
actual fun getRandomBytes(amount: Int): UByteArray {
memScoped {
val array = allocArray<UByteVar>(amount)
randombytes_buf(array, amount.convert())
return UByteArray(amount) {
array[it]
}
}
}
}

View File

@ -1,164 +0,0 @@
package com.ionspin.kotlin.crypto.authenticated
import com.ionspin.kotlin.bignum.integer.util.hexColumsPrint
import com.ionspin.kotlin.crypto.InvalidTagException
import com.ionspin.kotlin.crypto.util.toPtr
import kotlinx.cinterop.*
import libsodium.*
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 14-Jun-2020
*/
actual class XChaCha20Poly1305Delegated internal actual constructor() {
actual companion object {
actual fun encrypt(
key: UByteArray,
nonce: UByteArray,
message: UByteArray,
associatedData: UByteArray
): UByteArray {
val ciphertextLength = message.size + crypto_aead_xchacha20poly1305_IETF_ABYTES.toInt()
val ciphertext = UByteArray(ciphertextLength)
val ciphertextPinned = ciphertext.pin()
crypto_aead_xchacha20poly1305_ietf_encrypt(
ciphertextPinned.toPtr(),
ulongArrayOf(ciphertextLength.convert()).toCValues(),
message.toCValues(),
message.size.convert(),
associatedData.toCValues(),
associatedData.size.convert(),
null,
nonce.toCValues(),
key.toCValues()
)
ciphertextPinned.unpin()
return ciphertext
}
actual fun decrypt(
key: UByteArray,
nonce: UByteArray,
ciphertext: UByteArray,
associatedData: UByteArray
): UByteArray {
val messageLength = ciphertext.size - crypto_aead_xchacha20poly1305_IETF_ABYTES.toInt()
val message = UByteArray(messageLength)
val messagePinned = message.pin()
crypto_aead_xchacha20poly1305_ietf_decrypt(
messagePinned.toPtr(),
ulongArrayOf(messageLength.convert()).toCValues(),
null,
ciphertext.toCValues(),
ciphertext.size.convert(),
associatedData.toCValues(),
associatedData.size.convert(),
nonce.toCValues(),
key.toCValues()
)
messagePinned.unpin()
return message
}
}
var state =
sodium_malloc(crypto_secretstream_xchacha20poly1305_state.size.convert())!!
.reinterpret<crypto_secretstream_xchacha20poly1305_state>()
.pointed
val header = UByteArray(crypto_secretstream_xchacha20poly1305_HEADERBYTES.toInt()) { 0U }
var isInitialized = false
var isEncryptor = false
actual internal constructor(
key: UByteArray,
testState: UByteArray,
testHeader: UByteArray,
isDecryptor: Boolean
) : this() {
val pointer = state.ptr.reinterpret<UByteVar>()
for (i in 0 until crypto_secretstream_xchacha20poly1305_state.size.toInt()) {
pointer[i] = testState[i]
}
println("state after setting-----------")
state.ptr.readBytes(crypto_secretstream_xchacha20poly1305_state.size.toInt()).asUByteArray().hexColumsPrint()
println("state after setting-----------")
println("header after setting-----------")
testHeader.copyInto(header)
header.hexColumsPrint()
println("header after setting-----------")
isInitialized = true
isEncryptor = !isDecryptor
}
actual fun initializeForEncryption(key: UByteArray) : UByteArray {
val pinnedHeader = header.pin()
crypto_secretstream_xchacha20poly1305_init_push(state.ptr, pinnedHeader.toPtr(), key.toCValues())
println("state-----------")
state.ptr.readBytes(crypto_secretstream_xchacha20poly1305_state.size.toInt()).asUByteArray().hexColumsPrint()
println("state-----------")
println("--------header-----------")
header.hexColumsPrint()
println("--------header-----------")
pinnedHeader.unpin()
return header
}
actual fun initializeForDecryption(key: UByteArray, header: UByteArray) {
crypto_secretstream_xchacha20poly1305_init_pull(state.ptr, header.toCValues(), key.toCValues())
}
actual fun encrypt(data: UByteArray, associatedData: UByteArray): UByteArray {
val ciphertextWithTag = UByteArray(data.size + crypto_secretstream_xchacha20poly1305_ABYTES.toInt())
val ciphertextWithTagPinned = ciphertextWithTag.pin()
crypto_secretstream_xchacha20poly1305_push(
state.ptr,
ciphertextWithTagPinned.toPtr(),
null,
data.toCValues(),
data.size.convert(),
associatedData.toCValues(),
associatedData.size.convert(),
0U,
)
println("Encrypt partial")
ciphertextWithTag.hexColumsPrint()
println("Encrypt partial end")
ciphertextWithTagPinned.unpin()
return ciphertextWithTag
}
actual fun decrypt(data: UByteArray, associatedData: UByteArray): UByteArray {
val plaintext = UByteArray(data.size - crypto_secretstream_xchacha20poly1305_ABYTES.toInt())
val plaintextPinned = plaintext.pin()
val validTag = crypto_secretstream_xchacha20poly1305_pull(
state.ptr,
plaintextPinned.toPtr(),
null,
null,
data.toCValues(),
data.size.convert(),
associatedData.toCValues(),
associatedData.size.convert()
)
plaintextPinned.unpin()
println("tag: $validTag")
if (validTag != 0) {
println("Tag validation failed")
throw InvalidTagException()
}
return plaintext
}
actual fun cleanup() {
sodium_free(state.ptr)
}
}

View File

@ -1,61 +0,0 @@
package com.ionspin.kotlin.crypto.hash.blake2b
import com.ionspin.kotlin.crypto.util.toHexString
import com.ionspin.kotlin.crypto.util.toPtr
import kotlinx.cinterop.*
import libsodium.*
import platform.posix.free
import platform.posix.malloc
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 14-Jul-2019
*/
actual class Blake2bDelegated actual constructor(key: UByteArray?, hashLength: Int) : Blake2bMultipart {
override val MAX_HASH_BYTES: Int = 64
val requestedHashLength : Int
val state : crypto_generichash_state
init {
requestedHashLength = hashLength
val allocated = malloc(crypto_generichash_state.size.convert())!!
state = allocated.reinterpret<crypto_generichash_state>().pointed
crypto_generichash_init(state.ptr, key?.run { this.toCValues() }, key?.size?.convert() ?: 0UL.convert(), hashLength.convert())
}
override fun update(data: UByteArray) {
crypto_generichash_update(state.ptr, data.toCValues(), data.size.convert())
}
override fun digest(): UByteArray {
val hashResult = UByteArray(requestedHashLength)
val hashResultPinned = hashResult.pin()
crypto_generichash_final(state.ptr, hashResultPinned.toPtr(), requestedHashLength.convert())
free(state.ptr)
return hashResult
}
}
@Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
actual object Blake2bDelegatedStateless : Blake2b {
override fun digest(inputMessage: UByteArray, key: UByteArray, hashLength: Int): UByteArray {
val hashResult = UByteArray(MAX_HASH_BYTES)
val hashResultPinned = hashResult.pin()
crypto_generichash(
hashResultPinned.toPtr(),
hashLength.convert(),
inputMessage.toCValues(),
inputMessage.size.convert(),
key.toCValues(),
key.size.convert()
)
hashResultPinned.unpin()
return hashResult
}
}

View File

@ -1,55 +0,0 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bDelegatedStateless
import com.ionspin.kotlin.crypto.util.toPtr
import kotlinx.cinterop.*
import libsodium.*
import platform.posix.free
import platform.posix.malloc
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 17-Jul-2019
*/
actual class Sha256Delegated : Sha256 {
val state : crypto_hash_sha256_state
init {
val allocated = sodium_malloc(crypto_hash_sha256_state.size.convert())!!
state = allocated.reinterpret<crypto_hash_sha256_state>().pointed
crypto_hash_sha256_init(state.ptr)
}
override fun update(data: UByteArray) {
crypto_hash_sha256_update(state.ptr, data.toCValues(), data.size.convert())
}
override fun digest(): UByteArray {
val hashResult = UByteArray(Sha256Properties.MAX_HASH_BYTES)
val hashResultPinned = hashResult.pin()
crypto_hash_sha256_final(state.ptr, hashResultPinned.toPtr())
sodium_free(state.ptr)
return hashResult
}
}
actual object Sha256StatelessDelegated : StatelessSha256 {
override fun digest(inputMessage: UByteArray): UByteArray {
val hashResult = UByteArray(MAX_HASH_BYTES)
val hashResultPinned = hashResult.pin()
crypto_hash_sha256(hashResultPinned.toPtr(), inputMessage.toCValues(), inputMessage.size.convert())
hashResultPinned.unpin()
return hashResult
}
}

View File

@ -1,50 +0,0 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.ionspin.kotlin.crypto.util.toPtr
import kotlinx.cinterop.*
import libsodium.*
import platform.posix.free
import platform.posix.malloc
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 17-Jul-2019
*/
actual class Sha512Delegated : Sha512Multipart {
val state : crypto_hash_sha512_state
init {
val allocated = malloc(crypto_hash_sha512_state.size.convert())!!
state = allocated.reinterpret<crypto_hash_sha512_state>().pointed
crypto_hash_sha512_init(state.ptr)
}
override fun update(data: UByteArray) {
crypto_hash_sha512_update(state.ptr, data.toCValues(), data.size.convert())
}
override fun digest(): UByteArray {
val hashResult = UByteArray(Sha512Properties.MAX_HASH_BYTES)
val hashResultPinned = hashResult.pin()
crypto_hash_sha512_final(state.ptr, hashResultPinned.toPtr())
free(state.ptr)
return hashResult
}
}
actual object Sha512StatelessDelegated : Sha512 {
override fun digest(inputMessage: UByteArray): UByteArray {
val hashResult = UByteArray(Sha512StatelessDelegated.MAX_HASH_BYTES)
val hashResultPinned = hashResult.pin()
crypto_hash_sha512(hashResultPinned.toPtr(), inputMessage.toCValues(), inputMessage.size.convert())
hashResultPinned.unpin()
return hashResult
}
}

View File

@ -1,13 +0,0 @@
package com.ionspin.kotlin.crypto.util
import kotlinx.cinterop.CPointer
import kotlinx.cinterop.Pinned
import kotlinx.cinterop.UByteVar
import kotlinx.cinterop.addressOf
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 27-Aug-2020
*/
fun Pinned<UByteArray>.toPtr() : CPointer<UByteVar> = addressOf(0)

View File

@ -1,77 +0,0 @@
package com.ionspin.kotlin.crypto
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.toHexString
import com.ionspin.kotlin.crypto.util.toPtr
import kotlinx.cinterop.*
import libsodium.*
import platform.posix.free
import platform.posix.malloc
import kotlin.test.Ignore
import kotlin.test.Test
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 13-Jul-2020
*/
class HelperTest {
@Ignore //Just used for debugging pure implementation
@Test
fun longSha256() {
for (target in 0L until 10L) {
generateForRounds256(target)
}
for (target in 0L until 16_777_216L step 1_000_000L) {
generateForRounds256(target)
}
generateForRounds256(16_777_216L)
}
fun generateForRounds256(target: Long) {
val updateValue =
"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno".encodeToUByteArray().toCValues()
val state = malloc(crypto_hash_sha256_state.size.convert())!!
.reinterpret<crypto_hash_sha256_state>()
crypto_hash_sha256_init(state)
for (i in 0 until target) {
crypto_hash_sha256_update(state, updateValue, updateValue.size.convert())
}
val result = UByteArray(32)
val resultPinned = result.pin()
crypto_hash_sha256_final(state, resultPinned.toPtr())
println("$target to \"${result.toHexString()}\",")
free(state)
}
@Ignore //Just used for debugging pure implementation
@Test
fun longSha512() {
for (target in 0L until 10L) {
generateForRounds512(target)
}
for (target in 0L until 16_777_216L step 1_000_000L) {
generateForRounds512(target)
}
generateForRounds512(16_777_216L)
}
fun generateForRounds512(target: Long) {
println("Wut")
val updateValue =
"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno".encodeToUByteArray().toCValues()
val state = malloc(crypto_hash_sha512_state.size.convert())!!
.reinterpret<crypto_hash_sha512_state>()
crypto_hash_sha512_init(state)
for (i in 0 until target) {
crypto_hash_sha512_update(state, updateValue, updateValue.size.convert())
}
val result = UByteArray(32)
val resultPinned = result.pin()
crypto_hash_sha512_final(state, resultPinned.toPtr())
println("$target to \"${result.toHexString()}\",")
free(state)
}
}

View File

@ -1,27 +0,0 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* 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.
*/
//package com.ionspin.kotlin.crypto.util
//
//import kotlinx.coroutines.CoroutineScope
//import kotlinx.coroutines.runBlocking
//
///**
// * Created by Ugljesa Jovanovic
// * ugljesa.jovanovic@ionspin.com
// * on 20-Jul-2019
// */
//actual fun testBlocking(block: suspend () -> Unit) = runBlocking { block() }

View File

@ -20,6 +20,8 @@
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTest
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.jetbrains.dokka.Platform
plugins {
kotlin(PluginsDeps.multiplatform)
@ -593,18 +595,43 @@ tasks {
dokkaJavadoc {
println("Dokka !")
dokkaSourceSets {
create("commonMain") {
displayName = "common"
platform = "common"
named("commonMain") {
displayName.set("common")
platform.set(Platform.common)
}
}
}
dokkaHtml {
println("Dokka Html!")
dokkaSourceSets {
named("commonMain") {
// displayName.set("common")
// platform.set(Platform.common)
moduleDisplayName.set("Kotlin Multiplatform Libsodium Bindings")
includes.from(
"src/commonMain/kotlin/com.ionspin.kotlin.crypto/aead/Aead.md",
"src/commonMain/kotlin/com.ionspin.kotlin.crypto/auth/Auth.md",
"src/commonMain/kotlin/com.ionspin.kotlin.crypto/box/Box.md",
"src/commonMain/kotlin/com.ionspin.kotlin.crypto/CryptoModule.md")
displayName.set("Kotlin multiplatform")
}
configureEach {
if (name != "commonMain") {
suppress.set(true)
}
}
}
}
if (getHostOsName() == "linux" && getHostArchitecture() == "x86-64") {
val jvmTest by getting(Test::class) {
testLogging {
events("PASSED", "FAILED", "SKIPPED")
exceptionFormat = TestExceptionFormat.FULL
showStandardStreams = true
showStackTraces = true
}
}
@ -612,14 +639,18 @@ tasks {
testLogging {
events("PASSED", "FAILED", "SKIPPED")
exceptionFormat = TestExceptionFormat.FULL
showStandardStreams = true
showStackTraces = true
}
}
val jsNodeTest by getting(KotlinJsTest::class) {
testLogging {
events("PASSED", "FAILED", "SKIPPED")
// showStandardStreams = true
exceptionFormat = TestExceptionFormat.FULL
showStandardStreams = true
showStackTraces = true
}
}

View File

@ -0,0 +1,10 @@
# Module Kotlin Multiplatform Libsodium Bindings
### What
Kotlin Multiplatform Libsodium Bindings is a library providing kotlin idiomatic API to libsodium implementations on various platforms
### Why
To provide easy to use cryptographic library, based on a well-known and audited libsodium library. T
### How
By using built from source libsodium to provide native implementations, LazySodium (JNA wrapper around libsodium) to provide
JVM and Android implementations and libsodium.js to provide node and browser implementation

View File

@ -0,0 +1,28 @@
# Package com.ionspin.kotlin.crypto.aead
## Authenticated encryption with associated data
This is a form of symmetric encryption, that assures both confidentiality and authenticity of the data to be encrypted as well
as associated data that will not be encrypted.
In general, it works like this:
Inputs:
- Message to encrypt and authenticate
- Key to use for encryption
- **Unique** nonce
- Additional data that is not encrypted but also authenticated
Simplified encryption algorithm:
1. Encrypt a message with key and nonce
1. Apply MAC algorithm to encrypted message + unencrypted associated data to generate authentication data (tag)
1. Send the encrypted data + associated data + authentication data + nonce
Simplified decryption algorithm:
1. Apply MAC algorithm to encrypted message + unencrypted associated data to generate authentication data
1. If the generated authenticated data, and the received authentication data match, proceed, otherwise sound the alarm and stop.
1. Decrypt the encrypted data
1. Return the decrypted data and associated data to the user

View File

@ -22,13 +22,52 @@ val crypto_aead_chacha20poly1305_KEYBYTES = 32
val crypto_aead_chacha20poly1305_NPUBBYTES = 8
val crypto_aead_chacha20poly1305_ABYTES = 16
/**
* A data class wrapping returned encrypted data and and tag from aead encrypt functions.
*/
data class AeadEncryptedDataAndTag(val data: UByteArray, val tag: UByteArray)
class AeadCorrupedOrTamperedDataException() : RuntimeException("MAC validation failed. Data is corrupted or tampered with.")
/**
* An exception thrown when tag generated from received data and key doesn't match the received tag
*/
class AeadCorrupedOrTamperedDataException() :
RuntimeException("Tag (authentication data) validation failed. Data is corrupted or tampered with.")
/**
* This is a form of symmetric encryption, that assures both confidentiality and authenticity of the data to be encrypted as well
as associated data that will not be encrypted.
*
* Offered here are three implementations of (x)ChaCha20-Poly1305 construction:
* - ChaCha20Poly1305 - uses 64bit nonce, safe to encrypt
* - ChaCha20Poly1305-IETF - uses 96bit nonce (standardised by [RFC8439](https://tools.ietf.org/html/rfc8439)
* - XChaCha20Poly1305 - uses 192bit nonce - recommended choice
*
* The only difference is the size of the nonce, and how is the nonce used.
*
* (x)ChaCha20 is a streaming cipher develop by Daniel J. Bernstein. He is also the author of Poly1305 a fast Message
* Authentication Code system
*
* Libsodium offers two additional variants for each of the aforementioned variants:
* - Combined
* - Detached
*
* Combined mode returns encrypted data and tag as one UByteArray, while detached mode returns them as separate UByteArrays.
* To be kotlin idiomatic we are returning detached tag and encrypted data inside a wrapper data class [AeadEncryptedDataAndTag]
*
* Also provided are key generation convenience functions for each variant. (Which is in practice the same, since the keys
* same length for each variant)
*/
expect object AuthenticatedEncryptionWithAssociatedData {
// X - Ietf
/**
* Encrypt the message and return encrypted data and tag using xChaChaPoly1305 (192 bit nonce)
*
* @param message message to encrypt
* @param associatedData associated data the won't be encrypted, but will be authenticated
* @param nonce a **unique** nonce
* @param key secret key
* @return encrypted data and tag (in that order)
*/
fun xChaCha20Poly1305IetfEncrypt(
message: UByteArray,
associatedData: UByteArray,
@ -36,13 +75,34 @@ expect object AuthenticatedEncryptionWithAssociatedData {
key: UByteArray
): UByteArray
/**
* Check if authentication data (tag) is correct, then decrypt the message and return decrypted data.
* Using xChaChaPoly1305 (192 bit nonce)
*
* @param ciphertextAndTag message to decrypt
* @param associatedData associated data the won't be encrypted, but will be authenticated
* @param nonce a nonce used to encrypt the message
* @param key secret key
* @return decrypted data
* @throws AeadCorrupedOrTamperedDataException if authentication data (tag) cannot be verified
*/
fun xChaCha20Poly1305IetfDecrypt(
ciphertext: UByteArray,
ciphertextAndTag: UByteArray,
associatedData: UByteArray,
nonce: UByteArray,
key: UByteArray
): UByteArray
/**
* Encrypt the message and return encrypted data and tag using xChaChaPoly1305 (192 bit nonce) as
* separate arrays (but wrapped inside [AeadEncryptedDataAndTag])
*
* @param message message to encrypt
* @param associatedData associated data the won't be encrypted, but will be authenticated
* @param nonce a **unique** nonce
* @param key secret key
* @return encrypted data and tag wrapped inside [AeadEncryptedDataAndTag] data class instance
*/
fun xChaCha20Poly1305IetfEncryptDetached(
message: UByteArray,
associatedData: UByteArray,
@ -50,6 +110,18 @@ expect object AuthenticatedEncryptionWithAssociatedData {
key: UByteArray
): AeadEncryptedDataAndTag
/**
* Check if authentication data (tag) is correct, then decrypt the message and return decrypted data.
* Using xChaChaPoly1305 (192 bit nonce)
*
* @param ciphertext message to decrypt
* @param tag authenticatoin data (tag)
* @param associatedData associated data the won't be encrypted, but will be authenticated
* @param nonce a nonce used to encrypt the message
* @param key secret key
* @return decrypted data
* @throws AeadCorrupedOrTamperedDataException if authentication data (tag) cannot be verified
*/
fun xChaCha20Poly1305IetfDecryptDetached(
ciphertext: UByteArray,
tag: UByteArray,
@ -59,21 +131,48 @@ expect object AuthenticatedEncryptionWithAssociatedData {
): UByteArray
// Ietf
/**
* Encrypt the message and return encrypted data and tag using ChaChaPoly1305-IETF (96 bit nonce)
*
* @param message message to encrypt
* @param associatedData associated data the won't be encrypted, but will be authenticated
* @param nonce a **unique** nonce
* @param key secret key
* @return encrypted data and tag (in that order)
*/
fun chaCha20Poly1305IetfEncrypt(
message: UByteArray,
associatedData: UByteArray,
nonce: UByteArray,
key: UByteArray
): UByteArray
/**
* Check if authentication data (tag) is correct, then decrypt the message and return decrypted data.
* Using ChaChaPoly1305-IETF (96 bit nonce)
*
* @param ciphertextAndTag message to decrypt
* @param associatedData associated data the won't be encrypted, but will be authenticated
* @param nonce a nonce used to encrypt the message
* @param key secret key
* @return decrypted data
* @throws AeadCorrupedOrTamperedDataException if authentication data (tag) cannot be verified
*/
fun chaCha20Poly1305IetfDecrypt(
ciphertext: UByteArray,
ciphertextAndTag: UByteArray,
associatedData: UByteArray,
nonce: UByteArray,
key: UByteArray
): UByteArray
/**
* Encrypt the message and return encrypted data and tag using ChaChaPoly1305-IETF (96 bit nonce) as
* separate arrays (but wrapped inside [AeadEncryptedDataAndTag])
*
* @param message message to encrypt
* @param associatedData associated data the won't be encrypted, but will be authenticated
* @param nonce a **unique** nonce
* @param key secret key
* @return encrypted data and tag wrapped inside [AeadEncryptedDataAndTag] data class instance
*/
fun chaCha20Poly1305IetfEncryptDetached(
message: UByteArray,
associatedData: UByteArray,
@ -81,6 +180,18 @@ expect object AuthenticatedEncryptionWithAssociatedData {
key: UByteArray
): AeadEncryptedDataAndTag
/**
* Check if authentication data (tag) is correct, then decrypt the message and return decrypted data.
* Using xChaChaPoly1305 (96 bit nonce)
*
* @param ciphertext message to decrypt
* @param tag authenticatoin data (tag)
* @param associatedData associated data the won't be encrypted, but will be authenticated
* @param nonce a nonce used to encrypt the message
* @param key secret key
* @return decrypted data
* @throws AeadCorrupedOrTamperedDataException if authentication data (tag) cannot be verified
*/
fun chaCha20Poly1305IetfDecryptDetached(
ciphertext: UByteArray,
tag: UByteArray,
@ -90,28 +201,66 @@ expect object AuthenticatedEncryptionWithAssociatedData {
): UByteArray
// Original chacha20poly1305
/**
* Encrypt the message and return encrypted data and tag using ChaChaPoly1305 (64 bit nonce)
*
* @param message message to encrypt
* @param associatedData associated data the won't be encrypted, but will be authenticated
* @param nonce a **unique** nonce
* @param key secret key
* @return encrypted data and tag (in that order)
*/
fun chaCha20Poly1305Encrypt(
message: UByteArray,
associatedData: UByteArray,
nonce: UByteArray,
key: UByteArray
): UByteArray
/**
* Check if authentication data (tag) is correct, then decrypt the message and return decrypted data.
* Using ChaChaPoly1305 (64 bit nonce)
*
* @param ciphertextAndTag message to decrypt
* @param associatedData associated data the won't be encrypted, but will be authenticated
* @param nonce a nonce used to encrypt the message
* @param key secret key
* @return decrypted data
* @throws AeadCorrupedOrTamperedDataException if authentication data (tag) cannot be verified
*/
fun chaCha20Poly1305Decrypt(
ciphertext: UByteArray,
ciphertextAndTag: UByteArray,
associatedData: UByteArray,
nonce: UByteArray,
key: UByteArray
): UByteArray
/**
* Encrypt the message and return encrypted data and tag using ChaChaPoly1305 (64 bit nonce) as
* separate arrays (but wrapped inside [AeadEncryptedDataAndTag])
*
* @param message message to encrypt
* @param associatedData associated data the won't be encrypted, but will be authenticated
* @param nonce a **unique** nonce
* @param key secret key
* @return encrypted data and tag wrapped inside [AeadEncryptedDataAndTag] data class instance
*/
fun chaCha20Poly1305EncryptDetached(
message: UByteArray,
associatedData: UByteArray,
nonce: UByteArray,
key: UByteArray
): AeadEncryptedDataAndTag
/**
* Check if authentication data (tag) is correct, then decrypt the message and return decrypted data.
* Using xChaChaPoly1305 (64 bit nonce)
*
* @param ciphertext message to decrypt
* @param tag authenticatoin data (tag)
* @param associatedData associated data the won't be encrypted, but will be authenticated
* @param nonce a nonce used to encrypt the message
* @param key secret key
* @return decrypted data
* @throws AeadCorrupedOrTamperedDataException if authentication data (tag) cannot be verified
*/
fun chaCha20Poly1305DecryptDetached(
ciphertext: UByteArray,
tag: UByteArray,
@ -120,9 +269,20 @@ expect object AuthenticatedEncryptionWithAssociatedData {
key: UByteArray
): UByteArray
fun xChaCha20Poly1305IetfKeygen() : UByteArray
fun chaCha20Poly1305IetfKeygen() : UByteArray
fun chaCha20Poly1305Keygen() : UByteArray
/**
* Generate a random 32byte key for use with xChaCha20Poly1305
* @return secret key
*/
fun xChaCha20Poly1305IetfKeygen(): UByteArray
/**
* Generate a random 32 byte key for use with ChaCha20Poly1305-IETF
* @return secret key
*/
fun chaCha20Poly1305IetfKeygen(): UByteArray
/**
* Generate a random 32 byte key for use with ChaCha20Poly1305
* @return secret key
*/
fun chaCha20Poly1305Keygen(): UByteArray
}

View File

@ -19,18 +19,60 @@ val crypto_auth_hmacsha256_BYTES = 32
val crypto_auth_hmacsha512_KEYBYTES = 32
val crypto_auth_hmacsha512_BYTES = 64
/**
* Authentication is a process of generating authentication data (tag) for a certain message. Its purpose is to assure
* that the data hasn't been corrupted or tampered with during the transport.
*
* We support 3 variants:
* - without suffix - HMAC-SHA512-256 (HMAC SHA512 with just the first 256 bits used)
* - *HmacSha256 - HMAC-SHA256
* - *HmacSha512 - HMAC-SHA512
*
* Each variant supports three operations:
* - keygen - generate appropriate key for MAC function
* - auth - generate the authentication data (tag/mac)
* - verify - verify that the authenticatoin data (tag/mac) is correct
*/
expect object Auth {
/**
* Generate a secret key, meant to be used with auth function.
*/
fun authKeygen() : UByteArray
/**
* Generate a HMAC-SHA512-256 authentication data - Message Authentication Code - tag
*/
fun auth(message: UByteArray, key: UByteArray) : UByteArray
fun authVerify(mac: UByteArray, message: UByteArray, key: UByteArray) : Boolean
/**
* Verify that given message, secret key and tag, a newly calculated tag matches the received HMAC-SHA512-256 tag.
*/
fun authVerify(tag: UByteArray, message: UByteArray, key: UByteArray) : Boolean
/**
* Generate a secret key, meant to be used with auth function.
*/
fun authHmacSha256Keygen() : UByteArray
/**
* Generate a HMAC-SHA256 authentication data - Message Authentication Code - tag
*/
fun authHmacSha256(message: UByteArray, key: UByteArray) : UByteArray
fun authHmacSha256Verify(mac: UByteArray, message: UByteArray, key: UByteArray) : Boolean
/**
* Verify that given message, secret key and tag, a newly calculated tag matches the received HMAC-SHA256 tag.
*/
fun authHmacSha256Verify(tag: UByteArray, message: UByteArray, key: UByteArray) : Boolean
/**
* Generate a secret key, meant to be used with auth function.
*/
fun authHmacSha512Keygen() : UByteArray
/**
* Generate a HMAC-SHA512 authentication data - Message Authentication Code - tag
*/
fun authHmacSha512(message: UByteArray, key: UByteArray) : UByteArray
fun authHmacSha512Verify(mac: UByteArray, message: UByteArray, key: UByteArray) : Boolean
/**
* Verify that given message, secret key and tag, a newly calculated tag matches the received HMAC-SHA512 tag.
*/
fun authHmacSha512Verify(tag: UByteArray, message: UByteArray, key: UByteArray) : Boolean
}

View File

@ -0,0 +1,21 @@
# Package com.ionspin.kotlin.crypto.auth
## Authentication
Authentication is a process of generating authentication data (tag) for a certain message. Its purpose is to assure
that the data hasn't been corrupted or tampered with during the transport.
In general, it works like this:
Inputs:
- Message to authenticate
- Key to use for authentication
Sending side algorithm:
1. Apply MAC to message
1. Send the message + authentication data (tag)
Receiving side:
1. Apply the MAC to the received message
1. If the generated authenticated data (tag), and the received authentication data (received tag) match, proceed, otherwise sound the alarm and stop.
1. Return the message to the user

View File

@ -19,6 +19,9 @@ data class BoxEncryptedDataAndTag(val ciphertext: UByteArray, val tag: UByteArra
class BoxCorruptedOrTamperedDataException() : RuntimeException("MAC validation failed. Data is corrupted or tampered with.")
/**
* Box API uses public-key (asymmetric) encryption to
*/
expect object Box {
/**
* The crypto_box_keypair() function randomly generates a secret key and a corresponding public key.
@ -87,4 +90,4 @@ expect object Box {
fun sealOpen(ciphertext: UByteArray, recipientsPublicKey: UByteArray, recipientsSecretKey: UByteArray) : UByteArray
}
}

View File

@ -0,0 +1,31 @@
# Package com.ionspin.kotlin.crypto.box
## Box API - Asymmetric/Public-key authenticated encryption
Public key encryption is a system that relies on a pair of keys to establish secure communication.
A simplified overview of communication between Bob and Alice using public-key encryption:
#### Key exchange
1. Alice creates 2 keys, one public, one private (public key is actually calculated from the private key)
1. Bob creates 2 keys, one public, one private
1. Alice sends her **public** key to Bob
1. Bob does the same and sends his **public** key to Alice
#### Encryption
Alice wants to establish a secure communication channel with Bob, they already exchanged public keys in previous steps.
1. Alice uses Bobs **private** key to encrypt a *secret value* (Usually just a key for symmetric encryption)
1. Alice sends encrypted data to Bob
1. Bob is the only one who has the matching private key, and can decrypt the data
1. Bob and Alice now posses the same *secret value* and can start communicating (i.e. by using XChaCha20Poly1305
symmetric encryption and using the *secret value* as the symmetric key)
Bob would do the same if he wanted to initiate the secure communication.
This set of functions also contains another use case called `sealed boxes` in libsodium.
Sealed box is designed to anonymously send a message to a recipient. Libsodium documentation explains it as follows:
> A message is encrypted using an ephemeral key pair, whose secret part is destroyed right after the encryption process.
Without knowing the secret key used for a given message, the sender cannot decrypt its own message later. And without additional data, a message cannot be correlated with the identity of its sender.

View File

@ -21,14 +21,34 @@ data class GenericHashState(val hashLength: Int, val internalState: GenericHashS
expect object GenericHash {
/**
* Request computing a hash of message, with a specific hash length and optional key. The specific hash length can be
* between [crypto_generichash_blake2b_BYTES_MIN] and [crypto_generichash_blake2b_BYTES_MAX]. If the key is provided
* it needs the hash will be different for each different key.
*/
fun genericHash(message : UByteArray, requestedHashLength: Int = crypto_generichash_BYTES, key : UByteArray? = null) : UByteArray
fun genericHash(message : UByteArray, requestedHashLength: Int, key : UByteArray? = null) : UByteArray
/**
* Prepare a Generic Hash State object that will be used to compute hash of data with arbitrary length. Secific hash length
* can be requested
*/
fun genericHashInit(requestedHashLength: Int = crypto_generichash_BYTES, key : UByteArray? = null) : GenericHashState
fun genericHashInit(requestedHashLength: Int, key : UByteArray? = null) : GenericHashState
/**
* Feed another chunk of message to the updateable hash object
*/
fun genericHashUpdate(state: GenericHashState, messagePart : UByteArray)
/**
* Feed the last chunk of message to the updateable hash object. This returns the actual hash.
*/
fun genericHashFinal(state : GenericHashState) : UByteArray
/**
* Generate a key of length [crypto_generichash_blake2b_KEYBYTES] that can be used with the generic hash funciton
*/
fun genericHashKeygen() : UByteArray
// ---- Not present in LazySodium nor libsodium.js
// fun blake2b(message : UByteArray, requestedHashLength: Int, key : UByteArray? = null) : UByteArray
//

View File

@ -0,0 +1,23 @@
# Package com.ionspin.kotlin.crypto.generichash
## Generic hash
Generic hash package provides a easy to use hashing API that computes fixed-length fingerprint for an arbitrary long message.
In this case hashing is a process of mapping a set of input bytes to a fixed length (32 bytes) output. Loosely speaking
hash function should be practically irreversible and resistant to collisions (a case where two different inputs result in a same output)
Some examples of hash function usage:
- Verifying data integrity, i.e. downloading a file and it's hash and then recalculating the hash of the downloaded
file to verify that it hasn't changed
- Creating unique identifiers to index long data
- Password verification, i.e. server stores just the hash of the users password and then when user wants to log in, they send
the password, which server then hashes and compares to the stored hash. This way in case of breach of server security cleartext
passwords are not revealed. With that said **DONT USE GENERIC HASH FOR PASSWORD HASHING**. Use PasswordHash funcitons.
Underneath this set of functions uses BLAKE2b secure hash function, Here is what Libsodium documentation says about it
>The crypto_generichash_* function set is implemented using BLAKE2b, a simple, standardized (RFC 7693) secure hash
>function that is as strong as SHA-3 but faster than SHA-1 and MD5.
>Unlike MD5, SHA-1 and SHA-256, this function is safe against hash length extension attacks.
>BLAKE2b is not suitable for hashing passwords. For this purpose, use the crypto_pwhash API documented
>in the Password Hashing section.

View File

@ -9,10 +9,14 @@ fun String.hexStringToUByteArray() : UByteArray {
return this.chunked(2).map { it.toUByte(16) }.toUByteArray()
}
fun String.encodeToUByteArray() : UByteArray{
fun String.encodeToUByteArray() : UByteArray{
return encodeToByteArray().asUByteArray()
}
fun UByteArray.decodeFromUByteArray() : String {
return asByteArray().decodeToString()
}
fun UByteArray.toHexString() : String {
return this.joinToString(separator = "") {
if (it <= 0x0FU) {

View File

@ -26,7 +26,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
}
actual fun xChaCha20Poly1305IetfDecrypt(
ciphertext: UByteArray,
ciphertextAndTag: UByteArray,
associatedData: UByteArray,
nonce: UByteArray,
key: UByteArray
@ -34,7 +34,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
try {
return getSodium().crypto_aead_xchacha20poly1305_ietf_decrypt(
null,
ciphertext.toUInt8Array(),
ciphertextAndTag.toUInt8Array(),
associatedData.toUInt8Array(),
nonce.toUInt8Array(),
key.toUInt8Array()
@ -100,7 +100,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
}
actual fun chaCha20Poly1305IetfDecrypt(
ciphertext: UByteArray,
ciphertextAndTag: UByteArray,
associatedData: UByteArray,
nonce: UByteArray,
key: UByteArray
@ -108,7 +108,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
try {
return getSodium().crypto_aead_chacha20poly1305_ietf_decrypt(
null,
ciphertext.toUInt8Array(),
ciphertextAndTag.toUInt8Array(),
associatedData.toUInt8Array(),
nonce.toUInt8Array(),
key.toUInt8Array()
@ -174,7 +174,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
}
actual fun chaCha20Poly1305Decrypt(
ciphertext: UByteArray,
ciphertextAndTag: UByteArray,
associatedData: UByteArray,
nonce: UByteArray,
key: UByteArray
@ -182,7 +182,7 @@ actual object AuthenticatedEncryptionWithAssociatedData {
try {
return getSodium().crypto_aead_chacha20poly1305_decrypt(
null,
ciphertext.toUInt8Array(),
ciphertextAndTag.toUInt8Array(),
associatedData.toUInt8Array(),
nonce.toUInt8Array(),
key.toUInt8Array()

View File

@ -3,7 +3,6 @@ package com.ionspin.kotlin.crypto.auth
import com.ionspin.kotlin.crypto.getSodium
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
import org.khronos.webgl.Uint8Array
actual object Auth {
actual fun authKeygen(): UByteArray {
@ -18,9 +17,9 @@ actual object Auth {
}
actual fun authVerify(mac: UByteArray, message: UByteArray, key: UByteArray): Boolean {
actual fun authVerify(tag: UByteArray, message: UByteArray, key: UByteArray): Boolean {
return getSodium().crypto_auth_verify(
mac.toUInt8Array(),
tag.toUInt8Array(),
message.toUInt8Array(),
key.toUInt8Array()
)
@ -38,12 +37,12 @@ actual object Auth {
}
actual fun authHmacSha256Verify(
mac: UByteArray,
tag: UByteArray,
message: UByteArray,
key: UByteArray
): Boolean {
return getSodium().crypto_auth_hmacsha256_verify(
mac.toUInt8Array(),
tag.toUInt8Array(),
message.toUInt8Array(),
key.toUInt8Array()
)
@ -61,12 +60,12 @@ actual object Auth {
}
actual fun authHmacSha512Verify(
mac: UByteArray,
tag: UByteArray,
message: UByteArray,
key: UByteArray
): Boolean {
return getSodium().crypto_auth_hmacsha512_verify(
mac.toUInt8Array(),
tag.toUInt8Array(),
message.toUInt8Array(),
key.toUInt8Array()
)

View File

@ -29,18 +29,18 @@ actual object AuthenticatedEncryptionWithAssociatedData {
}
actual fun xChaCha20Poly1305IetfDecrypt(
ciphertext: UByteArray,
ciphertextAndTag: UByteArray,
associatedData: UByteArray,
nonce: UByteArray,
key: UByteArray
): UByteArray {
val message = UByteArray(ciphertext.size - crypto_aead_xchacha20poly1305_ietf_ABYTES)
val message = UByteArray(ciphertextAndTag.size - crypto_aead_xchacha20poly1305_ietf_ABYTES)
val validationResult = sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
message.asByteArray(),
null,
null,
ciphertext.asByteArray(),
ciphertext.size.toLong(),
ciphertextAndTag.asByteArray(),
ciphertextAndTag.size.toLong(),
associatedData.asByteArray(),
associatedData.size.toLong(),
nonce.asByteArray(),
@ -122,18 +122,18 @@ actual object AuthenticatedEncryptionWithAssociatedData {
}
actual fun chaCha20Poly1305IetfDecrypt(
ciphertext: UByteArray,
ciphertextAndTag: UByteArray,
associatedData: UByteArray,
nonce: UByteArray,
key: UByteArray
): UByteArray {
val message = UByteArray(ciphertext.size - crypto_aead_chacha20poly1305_ietf_ABYTES)
val message = UByteArray(ciphertextAndTag.size - crypto_aead_chacha20poly1305_ietf_ABYTES)
val validationResult = sodium.crypto_aead_chacha20poly1305_ietf_decrypt(
message.asByteArray(),
null,
null,
ciphertext.asByteArray(),
ciphertext.size.toLong(),
ciphertextAndTag.asByteArray(),
ciphertextAndTag.size.toLong(),
associatedData.asByteArray(),
associatedData.size.toLong(),
nonce.asByteArray(),
@ -215,18 +215,18 @@ actual object AuthenticatedEncryptionWithAssociatedData {
}
actual fun chaCha20Poly1305Decrypt(
ciphertext: UByteArray,
ciphertextAndTag: UByteArray,
associatedData: UByteArray,
nonce: UByteArray,
key: UByteArray
): UByteArray {
val message = UByteArray(ciphertext.size - crypto_aead_chacha20poly1305_ABYTES)
val message = UByteArray(ciphertextAndTag.size - crypto_aead_chacha20poly1305_ABYTES)
val validationResult = sodium.crypto_aead_chacha20poly1305_decrypt(
message.asByteArray(),
null,
null,
ciphertext.asByteArray(),
ciphertext.size.toLong(),
ciphertextAndTag.asByteArray(),
ciphertextAndTag.size.toLong(),
associatedData.asByteArray(),
associatedData.size.toLong(),
nonce.asByteArray(),

Some files were not shown because too many files have changed in this diff Show More