Working single shot xchacha20poly1305 encryption and decryption in delegated flavour

This commit is contained in:
Ugljesa Jovanovic 2020-06-27 18:20:53 +02:00 committed by Ugljesa Jovanovic
parent 6228263978
commit e6f560ba8e
No known key found for this signature in database
GPG Key ID: 178E6DFCECCB0E0F
13 changed files with 66 additions and 48 deletions

View File

@ -5,6 +5,8 @@ package com.ionspin.kotlin.crypto.util
* ugljesa.jovanovic@ionspin.com * ugljesa.jovanovic@ionspin.com
* on 22-Jun-2020 * on 22-Jun-2020
*/ */
val _emit = IntArray(0)
fun UByteArray.overwriteWithZeroes() { fun UByteArray.overwriteWithZeroes() {
for (i in 0 until size) { for (i in 0 until size) {
this[i] = 0U this[i] = 0U
@ -15,4 +17,4 @@ fun UIntArray.overwriteWithZeroes() {
for (i in 0 until size) { for (i in 0 until size) {
this[i] = 0U this[i] = 0U
} }
} }

View File

@ -15,19 +15,16 @@ import com.ionspin.kotlin.crypto.keyderivation.ArgonResult
*/ */
object CryptoInitializerDelegated : CryptoInitializer { object CryptoInitializerDelegated : CryptoInitializer {
private var initialized = false
override suspend fun initialize() { override suspend fun initialize() {
Initializer.initialize() Initializer.initialize()
initialized = true
} }
fun initializeWithCallback(done: () -> Unit) { fun initializeWithCallback(done: () -> Unit) {
initialized = true
Initializer.initializeWithCallback(done) Initializer.initializeWithCallback(done)
} }
override fun isInitialized(): Boolean { override fun isInitialized(): Boolean {
return initialized return Initializer.isInitialized()
} }
} }

View File

@ -2,6 +2,7 @@ package com.ionspin.kotlin.crypto.authenticated
import com.ionspin.kotlin.crypto.CryptoInitializerDelegated import com.ionspin.kotlin.crypto.CryptoInitializerDelegated
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.hexColumsPrint
import com.ionspin.kotlin.crypto.util.testBlocking import com.ionspin.kotlin.crypto.util.testBlocking
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -18,10 +19,9 @@ class XChaCha20Poly1305Test {
@Test @Test
fun xChaCha20Poly1305() { fun xChaCha20Poly1305() = testBlocking {
testBlocking { CryptoInitializerDelegated.initialize()
CryptoInitializerDelegated.initialize()
}
assertTrue { assertTrue {
val message = ("Ladies and Gentlemen of the class of '99: If I could offer you " + 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() "only one tip for the future, sunscreen would be it.").encodeToUByteArray()
@ -62,9 +62,12 @@ class XChaCha20Poly1305Test {
0xcfU, 0x49U 0xcfU, 0x49U
) )
val encrypted = XChaCha20Poly1305Delegated.encrypt(key, nonce, message, additionalData) val encrypted = XChaCha20Poly1305Delegated.encrypt(key, nonce, message, additionalData)
// val decrypted = XChaCha20Poly1305Delegated.decrypt(key, nonce, encrypted, additionalData) encrypted.hexColumsPrint()
val decrypted = XChaCha20Poly1305Delegated.decrypt(key, nonce, encrypted, additionalData)
encrypted.contentEquals(expected) // && decrypted.contentEquals(message) println("Decrypted")
decrypted.hexColumsPrint()
println("----------")
encrypted.contentEquals(expected) && decrypted.contentEquals(message)
} }
assertTrue { assertTrue {
@ -91,9 +94,9 @@ class XChaCha20Poly1305Test {
0x84U, 0x6fU, 0xfcU, 0x75U, 0x31U, 0xbfU, 0x0cU, 0x2dU 0x84U, 0x6fU, 0xfcU, 0x75U, 0x31U, 0xbfU, 0x0cU, 0x2dU
) )
val encrypted = XChaCha20Poly1305Delegated.encrypt(key, nonce, message, additionalData) val encrypted = XChaCha20Poly1305Delegated.encrypt(key, nonce, message, additionalData)
// val decrypted = XChaCha20Poly1305Delegated.decrypt(key, nonce, encrypted, additionalData) val decrypted = XChaCha20Poly1305Delegated.decrypt(key, nonce, encrypted, additionalData)
encrypted.contentEquals(expected) // && decrypted.contentEquals(message) encrypted.contentEquals(expected) && decrypted.contentEquals(message)
} }

View File

@ -40,7 +40,8 @@ interface JsSodiumInterface {
fun crypto_hash_sha512_final(state: dynamic): Uint8Array fun crypto_hash_sha512_final(state: dynamic): Uint8Array
//XChaCha20Poly1305 //XChaCha20Poly1305
fun crypto_aead_xchacha20poly1305_ietf_encrypt(message: Uint8Array, additionalData: Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array fun crypto_aead_xchacha20poly1305_ietf_encrypt(message: Uint8Array, additionalData: Uint8Array, secretNonce: Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array
fun crypto_aead_xchacha20poly1305_ietf_decrypt(secretNonce: Uint8Array, ciphertext: Uint8Array, additionalData: Uint8Array, nonce: Uint8Array, key: Uint8Array) : Uint8Array
} }

View File

@ -8,10 +8,12 @@ import org.khronos.webgl.set
* Created by Ugljesa Jovanovic * Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com * ugljesa.jovanovic@ionspin.com
* on 25-Jun-2020 * on 25-Jun-2020
*
* TODO investigate using unsafe cast
*/ */
fun UByteArray.toUInt8Array() : Uint8Array { fun UByteArray.toUInt8Array() : Uint8Array {
val uint8Result = Uint8Array(toByteArray().toTypedArray()) val uint8Result = Uint8Array(toByteArray().toTypedArray())
console.log("Uint8: $uint8Result") // console.log("Uint8: $uint8Result")
return uint8Result return uint8Result
} }
@ -21,7 +23,7 @@ fun Uint8Array.toUByteArray() : UByteArray {
for (i in 0 until length) { for (i in 0 until length) {
result[i] = get(i).toUByte() result[i] = get(i).toUByte()
} }
console.log("UbyteArray: ${result.joinToString()}") // console.log("UbyteArray: ${result.joinToString()}")
return result return result
} }

View File

@ -3,6 +3,7 @@ package com.ionspin.kotlin.crypto.authenticated
import com.ionspin.kotlin.crypto.getSodium import com.ionspin.kotlin.crypto.getSodium
import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray import ext.libsodium.com.ionspin.kotlin.crypto.toUByteArray
import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array import ext.libsodium.com.ionspin.kotlin.crypto.toUInt8Array
import org.khronos.webgl.Uint8Array
/** /**
* Created by Ugljesa Jovanovic * Created by Ugljesa Jovanovic
@ -26,8 +27,9 @@ actual class XChaCha20Poly1305Delegated actual constructor(key: UByteArray, addi
val encrypted = getSodium().crypto_aead_xchacha20poly1305_ietf_encrypt( val encrypted = getSodium().crypto_aead_xchacha20poly1305_ietf_encrypt(
message.toUInt8Array(), message.toUInt8Array(),
additionalData.toUInt8Array(), additionalData.toUInt8Array(),
key.toUInt8Array(), Uint8Array(0),
nonce.toUInt8Array() nonce.toUInt8Array(),
key.toUInt8Array()
) )
return encrypted.toUByteArray() return encrypted.toUByteArray()
} }
@ -38,7 +40,14 @@ actual class XChaCha20Poly1305Delegated actual constructor(key: UByteArray, addi
ciphertext: UByteArray, ciphertext: UByteArray,
additionalData: UByteArray additionalData: UByteArray
): UByteArray { ): UByteArray {
TODO("not implemented yet") val decrypted = getSodium().crypto_aead_xchacha20poly1305_ietf_decrypt(
Uint8Array(0),
ciphertext.toUInt8Array(),
additionalData.toUInt8Array(),
nonce.toUInt8Array(),
key.toUInt8Array()
)
return decrypted.toUByteArray()
} }
} }

View File

@ -38,16 +38,15 @@ actual class XChaCha20Poly1305Delegated actual constructor(key: UByteArray, addi
ciphertext: UByteArray, ciphertext: UByteArray,
additionalData: UByteArray additionalData: UByteArray
): UByteArray { ): UByteArray {
val message = ByteArray(ciphertext.size - sodium.crypto_secretstream_xchacha20poly1305_abytes()) val message = ByteArray(ciphertext.size - 16)
SodiumJava().crypto_aead_xchacha20poly1305_ietf_encrypt( SodiumJava().crypto_aead_xchacha20poly1305_ietf_decrypt(
message, message,
longArrayOf(ciphertext.size.toLong()), longArrayOf(ciphertext.size.toLong()),
null,
ciphertext.toByteArray(), ciphertext.toByteArray(),
ciphertext.size.toLong(), ciphertext.size.toLong(),
additionalData.toByteArray(), additionalData.toByteArray(),
additionalData.size.toLong(), additionalData.size.toLong(),
null,
nonce.toByteArray(), nonce.toByteArray(),
key.toByteArray() key.toByteArray()

View File

@ -1,9 +1,7 @@
@file:Suppress("VARIABLE_IN_SINGLETON_WITHOUT_THREAD_LOCAL")
package com.ionspin.kotlin.crypto package com.ionspin.kotlin.crypto
import kotlinx.atomicfu.AtomicBoolean
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import libsodium.sodium_init import libsodium.sodium_init
import kotlin.native.concurrent.AtomicInt import kotlin.native.concurrent.AtomicInt
@ -29,4 +27,4 @@ actual object Initializer {
actual fun isInitialized(): Boolean { actual fun isInitialized(): Boolean {
return isPlatformInitialized.value != 0 return isPlatformInitialized.value != 0
} }
} }

View File

@ -5,6 +5,7 @@ import kotlinx.cinterop.convert
import kotlinx.cinterop.pin import kotlinx.cinterop.pin
import kotlinx.cinterop.toCValues import kotlinx.cinterop.toCValues
import libsodium.crypto_aead_xchacha20poly1305_IETF_ABYTES import libsodium.crypto_aead_xchacha20poly1305_IETF_ABYTES
import libsodium.crypto_aead_xchacha20poly1305_ietf_decrypt
import libsodium.crypto_aead_xchacha20poly1305_ietf_encrypt import libsodium.crypto_aead_xchacha20poly1305_ietf_encrypt
/** /**
@ -25,7 +26,7 @@ actual class XChaCha20Poly1305Delegated actual constructor(key: UByteArray, addi
val ciphertextPinned = ciphertext.pin() val ciphertextPinned = ciphertext.pin()
crypto_aead_xchacha20poly1305_ietf_encrypt( crypto_aead_xchacha20poly1305_ietf_encrypt(
ciphertextPinned.addressOf(0), ciphertextPinned.addressOf(0),
ciphertextLength.convert(), ulongArrayOf(ciphertextLength.convert()).toCValues(),
message.toCValues(), message.toCValues(),
message.size.convert(), message.size.convert(),
additionalData.toCValues(), additionalData.toCValues(),
@ -44,7 +45,22 @@ actual class XChaCha20Poly1305Delegated actual constructor(key: UByteArray, addi
ciphertext: UByteArray, ciphertext: UByteArray,
additionalData: UByteArray additionalData: UByteArray
): UByteArray { ): UByteArray {
TODO("not implemented yet") val messageLength = ciphertext.size - crypto_aead_xchacha20poly1305_IETF_ABYTES.toInt()
val message = UByteArray(messageLength)
val messagePinned = message.pin()
crypto_aead_xchacha20poly1305_ietf_decrypt(
messagePinned.addressOf(0),
ulongArrayOf(messageLength.convert()).toCValues(),
null,
ciphertext.toCValues(),
ciphertext.size.convert(),
additionalData.toCValues(),
additionalData.size.convert(),
nonce.toCValues(),
key.toCValues()
)
messagePinned.unpin()
return message
} }
} }

View File

@ -173,7 +173,6 @@ class XChaCha20Pure(key: UByteArray, nonce: UByteArray, initialCounter: UInt = 0
) )
keystreamRemainingCounter = 64 - remainingBytes keystreamRemainingCounter = 64 - remainingBytes
processedBytesSoFar += data.size processedBytesSoFar += data.size
state.overwriteWithZeroes()
return ciphertext return ciphertext
} }

View File

@ -1,6 +1,7 @@
package com.ionspin.kotlin.crypto.symmetric package com.ionspin.kotlin.crypto.symmetric
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.hexColumsPrint
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertTrue import kotlin.test.assertTrue
@ -239,9 +240,9 @@ class XChaCha20Test {
val firstChunk = xChaCha.xorWithKeystream(message.sliceArray(0 until 5)) val firstChunk = xChaCha.xorWithKeystream(message.sliceArray(0 until 5))
val secondChunk = xChaCha.xorWithKeystream(message.sliceArray(5 until 90)) val secondChunk = xChaCha.xorWithKeystream(message.sliceArray(5 until 90))
val thirdChunk = xChaCha.xorWithKeystream(message.sliceArray(90 until message.size)) val thirdChunk = xChaCha.xorWithKeystream(message.sliceArray(90 until message.size))
val result = firstChunk + secondChunk + thirdChunk
assertTrue { assertTrue {
(firstChunk + secondChunk + thirdChunk).contentEquals(expected) (result).contentEquals(expected)
} }
} }

View File

@ -1,13 +1,15 @@
package com.ionspin.kotlin.crypto.sample package com.ionspin.kotlin.crypto.sample
import com.ionspin.kotlin.crypto.Crypto import com.ionspin.kotlin.crypto.Crypto
import com.ionspin.kotlin.crypto.CryptoInitializerDelegated
import com.ionspin.kotlin.crypto.CryptoPrimitives
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.toHexString import com.ionspin.kotlin.crypto.util.toHexString
object Sample { object Sample {
fun runSample() { fun runSample() {
println("Initializing crypto library") println("Initializing crypto library")
Crypto.initializeWithCallback { CryptoInitializerDelegated.initializeWithCallback {
blake2b() blake2b()
} }
@ -16,11 +18,11 @@ object Sample {
fun blake2b() { fun blake2b() {
println("Blake2b updateable") println("Blake2b updateable")
val blake2bUpdateable = Crypto.Blake2b.updateable() val blake2bUpdateable = CryptoPrimitives.Blake2b.updateable()
blake2bUpdateable.update("test".encodeToUByteArray()) blake2bUpdateable.update("test".encodeToUByteArray())
println(blake2bUpdateable.digest().toHexString()) println(blake2bUpdateable.digest().toHexString())
println("Blake2b stateless") println("Blake2b stateless")
val statelessResult = Crypto.Blake2b.stateless("test".encodeToByteArray().toUByteArray()) val statelessResult = CryptoPrimitives.Blake2b.stateless("test".encodeToByteArray().toUByteArray())
println("Blake2b stateless: ${statelessResult.toHexString()}") println("Blake2b stateless: ${statelessResult.toHexString()}")
} }
} }

View File

@ -1,16 +1,5 @@
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bDelegated
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bStateless
import com.ionspin.kotlin.crypto.sample.Sample import com.ionspin.kotlin.crypto.sample.Sample
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import platform.posix.pthread_self
import platform.posix.sleep
import kotlin.native.concurrent.TransferMode
import kotlin.native.concurrent.Worker
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime
import kotlin.time.measureTime
@ExperimentalTime @ExperimentalTime