From 7ce350825eeb4f92089b01dbe1cbe054f049662d Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Sat, 23 May 2020 18:38:50 +0200 Subject: [PATCH] A bit of cleanup, a bit of profiling --- .../kotlin/crypto/hash/blake2b/Blake2b.kt | 1 - .../crypto/keyderivation/argon2/Argon2.kt | 10 ++--- .../keyderivation/argon2/Argon2Utils.kt | 43 ++----------------- .../keyderivation/argon2/ArgonMatrix.kt | 7 +-- .../com/ionspin/kotlin/crypto/ReadmeTest.kt | 26 ++++++----- .../kotlin/crypto/hash/argon/Argon2Test.kt | 10 +++-- 6 files changed, 35 insertions(+), 62 deletions(-) diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2b.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2b.kt index 214172e..c78c038 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2b.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/hash/blake2b/Blake2b.kt @@ -134,7 +134,6 @@ class Blake2b(val key: UByteArray? = null, val hashLength: Int = 64) : Updatable v[13] = v[13] xor (offsetCounter shr BITS_IN_WORD).ulongValue() if (finalBlock) { -// v[14] = v[14] xor 0xFFFFFFFFFFFFFFFFUL v[14] = v[14].inv() } diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2.kt index 3ba7598..444ce02 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2.kt @@ -23,7 +23,7 @@ import com.ionspin.kotlin.crypto.SRNG import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b import com.ionspin.kotlin.crypto.keyderivation.KeyDerivationFunction import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.argonBlake2bArbitraryLenghtHash -import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.inplaceCompressionFunctionG +import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.compressionFunctionG import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.validateArgonParameters import com.ionspin.kotlin.crypto.util.* @@ -161,7 +161,7 @@ class Argon2( ): ArgonBlockPointer { //Calculate first pass val zeroesBlock = ArgonBlock() - val firstPass = inplaceCompressionFunctionG( + val firstPass = compressionFunctionG( zeroesBlock.getBlockPointer(), ArgonBlock(iteration.toULong().toLittleEndianUByteArray() + lane.toULong().toLittleEndianUByteArray() + @@ -175,7 +175,7 @@ class Argon2( addressBlock, false ) - val secondPass = inplaceCompressionFunctionG( + val secondPass = compressionFunctionG( zeroesBlock.getBlockPointer(), firstPass, firstPass, @@ -330,7 +330,7 @@ class Argon2( accPointer.xorInplaceWith(matrix.getBlockPointer(i, columnCount - 1)) } //Hash the xored last blocks - val hash = argonBlake2bArbitraryLenghtHash(acc.getAsUByteArray(), tagLength) + val hash = argonBlake2bArbitraryLenghtHash(acc.storage, tagLength) matrix.clearMatrix() return hash @@ -391,7 +391,7 @@ class Argon2( ) matrix.setBlockAt(lane, column, - inplaceCompressionFunctionG( + compressionFunctionG( matrix.getBlockPointer(lane, previousColumn), matrix.getBlockPointer(l,z), matrix.getBlockPointer(lane,column), diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Utils.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Utils.kt index 73691c9..7bcf23f 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Utils.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/Argon2Utils.kt @@ -38,6 +38,7 @@ object Argon2Utils { const val R3 = 16 const val R4 = 63 + //Based on Blake2b mix internal fun inplaceMixRound(v : ULongArray) : ULongArray{ mix(v, 0, 4, 8, 12) mix(v, 1, 5, 9, 13) @@ -47,38 +48,7 @@ object Argon2Utils { mix(v, 1, 6, 11, 12) mix(v, 2, 7, 8, 13) mix(v, 3, 4, 9, 14) - return v //Just for chaining, array is already mixed - } - - //based on Blake2b mixRound - internal fun mixRound(input: UByteArray): Array { - var v = input.arrayChunked(8).map { it.fromLittleEndianArrayToULong() }.toTypedArray() - v = mix(v, 0, 4, 8, 12) - v = mix(v, 1, 5, 9, 13) - v = mix(v, 2, 6, 10, 14) - v = mix(v, 3, 7, 11, 15) - v = mix(v, 0, 5, 10, 15) - v = mix(v, 1, 6, 11, 12) - v = mix(v, 2, 7, 8, 13) - v = mix(v, 3, 4, 9, 14) - return v - } - - private fun inPlaceMix(v: UByteArray, a: Int, b: Int, c: Int, d: Int) { - - } - - //Based on Blake2b mix - private fun mix(v: Array, a: Int, b: Int, c: Int, d: Int): Array { - v[a] = (v[a] + v[b] + 2U * (v[a] and 0xFFFFFFFFUL) * (v[b] and 0xFFFFFFFFUL)) - v[d] = (v[d] xor v[a]) rotateRight R1 - v[c] = (v[c] + v[d] + 2U * (v[c] and 0xFFFFFFFFUL) * (v[d] and 0xFFFFFFFFUL)) - v[b] = (v[b] xor v[c]) rotateRight R2 - v[a] = (v[a] + v[b] + 2U * (v[a] and 0xFFFFFFFFUL) * (v[b] and 0xFFFFFFFFUL)) - v[d] = (v[d] xor v[a]) rotateRight R3 - v[c] = (v[c] + v[d] + 2U * (v[c] and 0xFFFFFFFFUL) * (v[d] and 0xFFFFFFFFUL)) - v[b] = (v[b] xor v[c]) rotateRight R4 - return v + return v //Just for chaining, array is mixed in place } //Based on Blake2b mix @@ -102,14 +72,9 @@ object Argon2Utils { return result } - private fun copyIntoGBlockColumn(gBlock: UByteArray, columnPosition: Int, columnData: UByteArray) { - for (i in 0..7) { - val column = columnData.copyOfRange(i * 16, i * 16 + 16) - column.copyInto(gBlock, i * 128 + columnPosition * 16) - } - } - internal fun inplaceCompressionFunctionG( + + internal fun compressionFunctionG( previousBlock: ArgonBlockPointer, referenceBlock: ArgonBlockPointer, currentBlock: ArgonBlockPointer, diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/ArgonMatrix.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/ArgonMatrix.kt index 98ba1d8..f663888 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/ArgonMatrix.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/argon2/ArgonMatrix.kt @@ -18,6 +18,8 @@ package com.ionspin.kotlin.crypto.keyderivation.argon2 +import com.ionspin.kotlin.crypto.util.xor + /** * Represents a pointer to a Argon2 Block, this abstracts what the backing structure is, a Argon 2 Matrix or * or a UByteArray block @@ -34,7 +36,7 @@ interface ArgonBlockPointer { operator fun set(blockPosition: Int, value: UByte) infix fun xorInplaceWith(other: ArgonBlockPointer) : ArgonBlockPointer { - (0 until 1024).forEach { + for (it in 0 until 1024) { this[it] = this[it] xor other[it] } return this //For chaining @@ -171,7 +173,6 @@ fun ArgonBlockPointer.getUIntFromPosition(positionInBlock: Int) : UInt { } fun setBlockAt(rowPosition: Int, columnPosition: Int, blockValue: UByteArray) { - println("Expensive set") blockValue.copyInto( storage, getBlockStartPositionPointer(rowPosition, columnPosition) @@ -271,7 +272,7 @@ inline class ArgonBlock internal constructor(internal val storage: UByteArray) { } override fun getAsUByteArray(): UByteArray { - return storageBlock.storage.slice(blockStartPosition until blockStartPosition + 1024).toUByteArray() + return storageBlock.storage } } diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt index aee8655..5267924 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/ReadmeTest.kt @@ -21,9 +21,12 @@ import com.ionspin.kotlin.crypto.hash.sha.Sha256 import com.ionspin.kotlin.crypto.hash.sha.Sha512 import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2 import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonType +import com.ionspin.kotlin.crypto.util.testBlocking import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue +import kotlin.time.ExperimentalTime +import kotlin.time.measureTime /** * Created by Ugljesa Jovanovic @@ -127,25 +130,28 @@ class ReadmeTest { } + @ExperimentalTime @Test - fun argon2StringExample() { + fun argon2StringExample() = testBlocking { val argon2Instance = Argon2( password = "Password", salt = "RandomSalt", - parallelism = 4, + parallelism = 1, tagLength = 64U, - requestedMemorySize = 32U, //Travis build on mac fails with higher values - numberOfIterations = 4, + requestedMemorySize = 4096U, //Travis build on mac fails with higher values + numberOfIterations = 100, key = "", associatedData = "", argonType = ArgonType.Argon2id ) - val tag = argon2Instance.derive() - val tagString = tag.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "") - val expectedTagString = "ca134003c9f9f76ca8869359c1d9065603ec54ac30f5158f06af647cacaef2c1c3e" + - "c71e81960278c0596febc64125acbbe5959146db1c128199a1b7cb38982a9" - println("Tag: ${tagString}") - assertEquals(tagString, expectedTagString) + val time = measureTime { + val tag = argon2Instance.derive() + val tagString = tag.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "") + val expectedTagString = "27c61b6538ef9f4a1250f8712cac09fc4329969295f9440249437d38c1617a005c2702d76a8a59e4cda2dfba48e1132261dacdfd31296945906992ea32f1d06e" + println("Tag: ${tagString}") + assertEquals(tagString, expectedTagString) + } + println("Time $time") } diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2Test.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2Test.kt index 228adce..f513b7d 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2Test.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/argon/Argon2Test.kt @@ -20,6 +20,7 @@ package com.ionspin.kotlin.crypto.hash.argon import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonBlock +import com.ionspin.kotlin.crypto.util.fromLittleEndianArrayToULong import kotlin.random.Random import kotlin.random.nextUBytes import kotlin.test.Test @@ -75,9 +76,10 @@ class Argon2Test { 6500029010075826286U, 16957672821843227543U ) - val result = Argon2Utils.mixRound(input) + val preparedInput = input.chunked(8).map { it.toTypedArray().fromLittleEndianArrayToULong() }.toULongArray() + val result = Argon2Utils.inplaceMixRound(preparedInput) assertTrue { - expected.contentEquals(result) + expected.contentEquals(result.toTypedArray()) } } @@ -246,7 +248,7 @@ class Argon2Test { val randomBlock1 = ArgonBlock(randomBlockAsArray).getBlockPointer() val randomBlock2 = ArgonBlock(randomBlockAsArray2).getBlockPointer() val randomBlock3 = ArgonBlock(randomBlockAsArray3).getBlockPointer() - val resultWithoutXorAndAllocations = Argon2Utils.inplaceCompressionFunctionG(randomBlock1, randomBlock2, randomBlock3, false) + val resultWithoutXorAndAllocations = Argon2Utils.compressionFunctionG(randomBlock1, randomBlock2, randomBlock3, false) assertTrue { expectedWithoutXor.contentEquals(resultWithoutXorAndAllocations.getAsUByteArray()) } @@ -391,7 +393,7 @@ class Argon2Test { val randomBlock1 = ArgonBlock(randomBlockAsArray).getBlockPointer() val randomBlock2 = ArgonBlock(randomBlockAsArray2).getBlockPointer() val randomBlock3 = ArgonBlock(randomBlockAsArray3).getBlockPointer() - val resultWithoutXorAndAllocations = Argon2Utils.inplaceCompressionFunctionG(randomBlock1, randomBlock2, randomBlock3, true) + val resultWithoutXorAndAllocations = Argon2Utils.compressionFunctionG(randomBlock1, randomBlock2, randomBlock3, true) assertTrue { expectedWithXor.contentEquals(resultWithoutXorAndAllocations.getAsUByteArray()) }