Fixed some of the errors spotted in various aes implementation while doing cryptopals challenge, anyways they were unused. Added multipart generic hash (blake2b) native implementation
This commit is contained in:
parent
231a84af67
commit
6f38a01195
@ -50,7 +50,7 @@ interface JsSodiumInterface {
|
|||||||
|
|
||||||
//decrypt
|
//decrypt
|
||||||
fun crypto_secretstream_xchacha20poly1305_init_pull(header: Uint8Array, key: Uint8Array) : dynamic
|
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
|
//util
|
||||||
fun memzero(array: Uint8Array)
|
fun memzero(array: Uint8Array)
|
||||||
|
@ -5,6 +5,22 @@ package com.ionspin.kotlin.crypto.generichash
|
|||||||
* ugljesa.jovanovic@ionspin.com
|
* ugljesa.jovanovic@ionspin.com
|
||||||
* on 21-Aug-2020
|
* on 21-Aug-2020
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
data class GenericHashState(val hashLength: Int, val state: GenericHashStateInternal)
|
||||||
|
|
||||||
|
expect class GenericHashStateInternal
|
||||||
|
|
||||||
expect object GenericHashing {
|
expect object GenericHashing {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun genericHash(message : UByteArray, requestedHashLength: Int, key : UByteArray? = null) : UByteArray
|
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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,17 +3,30 @@ package com.ionspin.kotlin.crypto.generichash
|
|||||||
import kotlinx.cinterop.addressOf
|
import kotlinx.cinterop.addressOf
|
||||||
import kotlinx.cinterop.convert
|
import kotlinx.cinterop.convert
|
||||||
import kotlinx.cinterop.pin
|
import kotlinx.cinterop.pin
|
||||||
|
import kotlinx.cinterop.pointed
|
||||||
|
import kotlinx.cinterop.ptr
|
||||||
|
import kotlinx.cinterop.reinterpret
|
||||||
import libsodium.crypto_generichash
|
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
|
* Created by Ugljesa Jovanovic
|
||||||
* ugljesa.jovanovic@ionspin.com
|
* ugljesa.jovanovic@ionspin.com
|
||||||
* on 21-Aug-2020
|
* on 21-Aug-2020
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
actual typealias GenericHashStateInternal = libsodium.crypto_generichash_blake2b_state
|
||||||
|
|
||||||
actual object GenericHashing {
|
actual object GenericHashing {
|
||||||
val _emitByte: Byte = 0
|
val _emitByte: Byte = 0
|
||||||
val _emitByteArray: ByteArray = ByteArray(0)
|
val _emitByteArray: ByteArray = ByteArray(0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
actual fun genericHash(message: UByteArray, requestedHashLength: Int, key: UByteArray?) : UByteArray {
|
actual fun genericHash(message: UByteArray, requestedHashLength: Int, key: UByteArray?) : UByteArray {
|
||||||
val hash = UByteArray(requestedHashLength)
|
val hash = UByteArray(requestedHashLength)
|
||||||
val pinnedHash = hash.pin()
|
val pinnedHash = hash.pin()
|
||||||
@ -32,4 +45,48 @@ actual object GenericHashing {
|
|||||||
pinnedMessage.unpin()
|
pinnedMessage.unpin()
|
||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actual fun genericHashInit(
|
||||||
|
requestedHashLength: Int,
|
||||||
|
key: UByteArray?
|
||||||
|
): GenericHashState {
|
||||||
|
val stateAllocated = malloc(GenericHashStateInternal.size.convert())
|
||||||
|
val statePointed = stateAllocated!!.reinterpret<GenericHashStateInternal>().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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
* @return Encrypted data and initialization vector
|
||||||
*/
|
*/
|
||||||
fun encrypt(): EncryptedDataAndInitializationVector {
|
fun encrypt(): EncryptedDataAndInitializationVector {
|
||||||
@ -158,6 +159,8 @@ internal class AesCbcPure internal constructor(val aesKey: InternalAesKey, val m
|
|||||||
} else {
|
} else {
|
||||||
output += consumeBlock(lastBlockPadded)
|
output += consumeBlock(lastBlockPadded)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
output += consumeBlock(UByteArray(BLOCK_BYTES) { BLOCK_BYTES.toUByte()})
|
||||||
}
|
}
|
||||||
return EncryptedDataAndInitializationVector(
|
return EncryptedDataAndInitializationVector(
|
||||||
output.reversed().foldRight(UByteArray(0) { 0U }) { arrayOfUBytes, acc -> acc + arrayOfUBytes },
|
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 {
|
fun decrypt(): UByteArray {
|
||||||
val removePaddingCount = output.last().last()
|
val removePaddingCount = output.last().last()
|
||||||
|
|
||||||
|
|
||||||
val removedPadding = if (removePaddingCount > 0U && removePaddingCount < 16U) {
|
val removedPadding = if (removePaddingCount > 0U && removePaddingCount < 16U) {
|
||||||
output.last().dropLast(removePaddingCount.toInt() and 0x7F)
|
output.last().dropLast(removePaddingCount.toInt() and 0x7F)
|
||||||
} else {
|
} else {
|
||||||
output.last().toList()
|
ubyteArrayOf()
|
||||||
}.toUByteArray()
|
}.toUByteArray()
|
||||||
val preparedOutput = (output.dropLast(1) + listOf(removedPadding))
|
val preparedOutput = (output.dropLast(1) + listOf(removedPadding))
|
||||||
//JS compiler freaks out here if we don't supply exact type
|
//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()
|
result = 31 * result + initializationVector.contentHashCode()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
* Creates and returns AesCtr instance that can be fed data using [addData]. Once you have submitted all
|
||||||
* data call [decrypt]
|
* data call [decrypt]
|
||||||
*/
|
*/
|
||||||
fun createDecryptor(aesKey : InternalAesKey) : AesCtrPure {
|
fun createDecryptor(aesKey : InternalAesKey, initialCounter: UByteArray) : AesCtrPure {
|
||||||
return AesCtrPure(aesKey, Mode.DECRYPT)
|
return AesCtrPure(aesKey, Mode.DECRYPT, initialCounter = initialCounter)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Bulk encryption, returns encrypted data and a random initial counter
|
* 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
|
* Bulk decryption, returns decrypted data
|
||||||
*/
|
*/
|
||||||
fun decrypt(aesKey: InternalAesKey, data: UByteArray, initialCounter: UByteArray? = null): UByteArray {
|
fun decrypt(aesKey: InternalAesKey, data: UByteArray, initialCounter: UByteArray): UByteArray {
|
||||||
val aesCtr = AesCtrPure(aesKey, Mode.DECRYPT, initialCounter)
|
val aesCtr = AesCtrPure(aesKey, Mode.DECRYPT, initialCounter = initialCounter)
|
||||||
aesCtr.addData(data)
|
aesCtr.addData(data)
|
||||||
return aesCtr.decrypt()
|
return aesCtr.decrypt()
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,9 @@ class AesCbcTest {
|
|||||||
val key = "4278b840fb44aaa757c1bf04acbe1a3e"
|
val key = "4278b840fb44aaa757c1bf04acbe1a3e"
|
||||||
val iv = "57f02a5c5339daeb0a2908a06ac6393f"
|
val iv = "57f02a5c5339daeb0a2908a06ac6393f"
|
||||||
val plaintext = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
val plaintext = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
||||||
val expectedCipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7"
|
val expectedCipherText = "479c89ec14bc98994e62b2c705b5014e" +
|
||||||
|
"175bd7832e7e60a1e92aac568a861eb7" +
|
||||||
|
"fc2dc2f4a527ce39f79c56b31432c779"
|
||||||
val aesCbc =
|
val aesCbc =
|
||||||
AesCbcPure(InternalAesKey.Aes128Key(key), mode = Mode.ENCRYPT, initializationVector = iv.hexStringToUByteArray())
|
AesCbcPure(InternalAesKey.Aes128Key(key), mode = Mode.ENCRYPT, initializationVector = iv.hexStringToUByteArray())
|
||||||
aesCbc.addData(plaintext.hexStringToUByteArray())
|
aesCbc.addData(plaintext.hexStringToUByteArray())
|
||||||
@ -104,4 +106,4 @@ class AesCbcTest {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user