diff --git a/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt b/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt index 6694723..1934eb9 100644 --- a/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt +++ b/multiplatform-crypto-delegated/src/jsMain/kotlin/com/ionspin/kotlin/crypto/JsSodiumInterface.kt @@ -50,7 +50,7 @@ interface JsSodiumInterface { //decrypt fun crypto_secretstream_xchacha20poly1305_init_pull(header: Uint8Array, key: Uint8Array) : dynamic - fun crypto_secretstream_xchacha20poly1305_pull(state: dynamic, ciphertext: Uint8Array, additionalData: Uint8Array) : Uint8Array + fun crypto_secretstream_xchacha20poly1305_pull(state: dynamic, ciphertext: Uint8Array, additionalData: Uint8Array) : dynamic //util fun memzero(array: Uint8Array) diff --git a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/generichash/GenericHashing.kt b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/generichash/GenericHashing.kt index 85aac10..4d3373d 100644 --- a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/generichash/GenericHashing.kt +++ b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/com.ionspin.kotlin.crypto/generichash/GenericHashing.kt @@ -5,6 +5,22 @@ package com.ionspin.kotlin.crypto.generichash * ugljesa.jovanovic@ionspin.com * on 21-Aug-2020 */ + +data class GenericHashState(val hashLength: Int, val state: GenericHashStateInternal) + +expect class GenericHashStateInternal + expect object GenericHashing { + + + + fun genericHash(message : UByteArray, requestedHashLength: Int, key : UByteArray? = null) : UByteArray + + fun genericHashInit(requestedHashLength: Int, key : UByteArray? = null) : GenericHashState + fun genericHashUpdate(state: GenericHashState, messagePart : UByteArray) + fun genericHashFinal(state : GenericHashState) : UByteArray + } + + diff --git a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/generichash/GenericHashing.kt b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/generichash/GenericHashing.kt index 4d54d53..ac7f26e 100644 --- a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/generichash/GenericHashing.kt +++ b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/com/ionspin/kotlin/crypto/generichash/GenericHashing.kt @@ -3,17 +3,30 @@ package com.ionspin.kotlin.crypto.generichash import kotlinx.cinterop.addressOf import kotlinx.cinterop.convert import kotlinx.cinterop.pin +import kotlinx.cinterop.pointed +import kotlinx.cinterop.ptr +import kotlinx.cinterop.reinterpret import libsodium.crypto_generichash +import libsodium.crypto_generichash_final +import libsodium.crypto_generichash_init +import libsodium.crypto_generichash_state +import libsodium.crypto_generichash_update +import platform.posix.malloc /** * Created by Ugljesa Jovanovic * ugljesa.jovanovic@ionspin.com * on 21-Aug-2020 */ + +actual typealias GenericHashStateInternal = libsodium.crypto_generichash_blake2b_state + actual object GenericHashing { val _emitByte: Byte = 0 val _emitByteArray: ByteArray = ByteArray(0) + + actual fun genericHash(message: UByteArray, requestedHashLength: Int, key: UByteArray?) : UByteArray { val hash = UByteArray(requestedHashLength) val pinnedHash = hash.pin() @@ -32,4 +45,48 @@ actual object GenericHashing { pinnedMessage.unpin() return hash } + + actual fun genericHashInit( + requestedHashLength: Int, + key: UByteArray? + ): GenericHashState { + val stateAllocated = malloc(GenericHashStateInternal.size.convert()) + val statePointed = stateAllocated!!.reinterpret().pointed + val pinnedKey = key?.pin() + crypto_generichash_init( + statePointed.ptr, + pinnedKey?.addressOf(0), + (key?.size ?: 0).convert(), + requestedHashLength.convert() + ) + pinnedKey?.unpin() + return GenericHashState(requestedHashLength, statePointed) + } + + actual fun genericHashUpdate( + state: GenericHashState, + messagePart: UByteArray + ) { + val pinnedMessage = messagePart.pin() + crypto_generichash_update( + state.state.ptr, + pinnedMessage.addressOf(0), + messagePart.size.convert() + ) + pinnedMessage.unpin() + } + + actual fun genericHashFinal(state: GenericHashState): UByteArray { + val hashResult = UByteArray(state.hashLength) + val hashResultPinned = hashResult.pin() + crypto_generichash_final( + state.state.ptr, + hashResultPinned.addressOf(0), + state.hashLength.convert() + ) + hashResultPinned.unpin() + return hashResult + } + + } diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcPure.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcPure.kt index 94cbf76..ae9acbd 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcPure.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcPure.kt @@ -145,7 +145,8 @@ internal class AesCbcPure internal constructor(val aesKey: InternalAesKey, val m } /** - * Encrypt fed data and return it alongside the randomly chosen initialization vector + * Encrypt fed data and return it alongside the randomly chosen initialization vector. + * This also applies correct PKCS#7 padding * @return Encrypted data and initialization vector */ fun encrypt(): EncryptedDataAndInitializationVector { @@ -158,6 +159,8 @@ internal class AesCbcPure internal constructor(val aesKey: InternalAesKey, val m } else { output += consumeBlock(lastBlockPadded) } + } else { + output += consumeBlock(UByteArray(BLOCK_BYTES) { BLOCK_BYTES.toUByte()}) } return EncryptedDataAndInitializationVector( output.reversed().foldRight(UByteArray(0) { 0U }) { arrayOfUBytes, acc -> acc + arrayOfUBytes }, @@ -172,11 +175,10 @@ internal class AesCbcPure internal constructor(val aesKey: InternalAesKey, val m fun decrypt(): UByteArray { val removePaddingCount = output.last().last() - val removedPadding = if (removePaddingCount > 0U && removePaddingCount < 16U) { output.last().dropLast(removePaddingCount.toInt() and 0x7F) } else { - output.last().toList() + ubyteArrayOf() }.toUByteArray() val preparedOutput = (output.dropLast(1) + listOf(removedPadding)) //JS compiler freaks out here if we don't supply exact type @@ -238,4 +240,4 @@ data class EncryptedDataAndInitializationVector(val encryptedData : UByteArray, result = 31 * result + initializationVector.contentHashCode() return result } -} \ No newline at end of file +} diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrPure.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrPure.kt index e477d39..b9f4ff9 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrPure.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrPure.kt @@ -54,8 +54,8 @@ internal class AesCtrPure internal constructor(val aesKey: InternalAesKey, val m * Creates and returns AesCtr instance that can be fed data using [addData]. Once you have submitted all * data call [decrypt] */ - fun createDecryptor(aesKey : InternalAesKey) : AesCtrPure { - return AesCtrPure(aesKey, Mode.DECRYPT) + fun createDecryptor(aesKey : InternalAesKey, initialCounter: UByteArray) : AesCtrPure { + return AesCtrPure(aesKey, Mode.DECRYPT, initialCounter = initialCounter) } /** * Bulk encryption, returns encrypted data and a random initial counter @@ -68,8 +68,8 @@ internal class AesCtrPure internal constructor(val aesKey: InternalAesKey, val m /** * Bulk decryption, returns decrypted data */ - fun decrypt(aesKey: InternalAesKey, data: UByteArray, initialCounter: UByteArray? = null): UByteArray { - val aesCtr = AesCtrPure(aesKey, Mode.DECRYPT, initialCounter) + fun decrypt(aesKey: InternalAesKey, data: UByteArray, initialCounter: UByteArray): UByteArray { + val aesCtr = AesCtrPure(aesKey, Mode.DECRYPT, initialCounter = initialCounter) aesCtr.addData(data) return aesCtr.decrypt() } diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcTest.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcTest.kt index 8a6af88..7b86d77 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcTest.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcTest.kt @@ -35,7 +35,9 @@ class AesCbcTest { val key = "4278b840fb44aaa757c1bf04acbe1a3e" val iv = "57f02a5c5339daeb0a2908a06ac6393f" val plaintext = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5" - val expectedCipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7" + val expectedCipherText = "479c89ec14bc98994e62b2c705b5014e" + + "175bd7832e7e60a1e92aac568a861eb7" + + "fc2dc2f4a527ce39f79c56b31432c779" val aesCbc = AesCbcPure(InternalAesKey.Aes128Key(key), mode = Mode.ENCRYPT, initializationVector = iv.hexStringToUByteArray()) aesCbc.addData(plaintext.hexStringToUByteArray()) @@ -104,4 +106,4 @@ class AesCbcTest { -} \ No newline at end of file +}