diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/Argon2Template.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/Argon2Template.kt deleted file mode 100644 index 9b0c1e5..0000000 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/Argon2Template.kt +++ /dev/null @@ -1,717 +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.keyderivation - -import com.ionspin.kotlin.bignum.integer.toBigInteger -import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b -import com.ionspin.kotlin.crypto.util.* - -/** - * - * Further resources and examples of implementation: - * https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03 - * https://en.wikipedia.org/wiki/Argon2 - * https://www.cryptolux.org/images/0/0d/Argon2.pdf - * https://github.com/LoupVaillant/Monocypher/blob/master/src/monocypher.c - * https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_pwhash/argon2/argon2.c - * - * Created by Ugljesa Jovanovic - * ugljesa.jovanovic@ionspin.com - * on 08-Jan-2020 - * - */ -@ExperimentalStdlibApi -@ExperimentalUnsignedTypes -class Argon2Template internal constructor( - val password: Array, - val salt: Array, - val parallelism: UInt, - val tagLength: UInt, - val memorySize: UInt, - val numberOfIterations: UInt, - val versionNumber: UInt, - val key: Array, - val associatedData: Array, - val type: ArgonType -) { - enum class ArgonType(val typeId: Int) { - Argon2d(0), Argon2i(1), Argon2id(2) - } - - data class Argon2StreamGContext( - val block: Array, - val passNumber: Int, - val sliceNumber: Int, - val blockCount: UInt, - val numberOfIterations: UInt, - val counter: UInt, - val type: ArgonType - ) { - - } - - - @ExperimentalStdlibApi - companion object { - - fun Array.xor(target: Array, other: Array) { - if (this.size != other.size || this.size != target.size) { - throw RuntimeException("Invalid array sizes, this ${this.size}, other ${other.size}") - } - target.mapIndexed { index, _ -> this[index] xor other[index] } - } - - - fun argonBlake2bArbitraryLenghtHash(input: Array, length: UInt): Array { - if (length <= 64U) { - return Blake2b.digest(inputMessage = length + input, hashLength = length.toInt()) - } - //We can cast to int because UInt even if MAX_VALUE divided by 32 is guaranteed not to overflow - val numberOf64ByteBlocks = (1U + ((length - 1U) / 32U) - 2U).toInt() // equivalent to ceil(length/32) - 2 - val v = Array>(numberOf64ByteBlocks) { emptyArray() } - v[0] = Blake2b.digest(length + input) - for (i in 1 until numberOf64ByteBlocks) { - v[i] = Blake2b.digest(v[i - 1]) - } - val remainingPartOfInput = length.toInt() - numberOf64ByteBlocks * 32 - val vLast = Blake2b.digest(v[numberOf64ByteBlocks - 1], hashLength = remainingPartOfInput) - val concat = - (v.map { it.copyOfRange(0, 32) }) - .plus(listOf(vLast)) - .foldRight(emptyArray()) { arrayOfUBytes, acc -> arrayOfUBytes + acc } - - return concat - } - - - fun compressionFunctionG( - previousBlock: Array, - referenceBlock: Array, - currentBlock: Array, - xorWithCurrentBlock: Boolean - ): Array { - val r = referenceBlock xor previousBlock -// println("R = X xor Y") -// r.hexColumsPrint(16) -// val r = Array(1024) { 0U } // view as 8x8 matrix of 16 byte registers -// x.forEachIndexed { index, it -> r[index] = it xor y[index] } // R = X xor Y - val q = Array(1024) { 0U } - val z = Array(1024) { 0U } - // Do the argon/blake2b mixing on rows - for (i in 0..7) { - val startOfRow = (i * 8 * 16) - val endOfRow = startOfRow + (8 * 16) - val rowToMix = r.copyOfRange(startOfRow, endOfRow) - mixRound(rowToMix) - .map { it.toLittleEndianUByteArray() } - .flatMap { it.asIterable() } - .toTypedArray() - .copyInto(q, startOfRow) - } -// println("---- Q -----") -// q.hexColumsPrint(16) - // Do the argon/blake2b mixing on columns - for (i in 0..7) { - copyIntoGBlockColumn( - z, - i, - mixRound(extractColumnFromGBlock(q, i)) - .map { it.toLittleEndianUByteArray() } - .flatMap { it.asIterable() } - .toTypedArray() - ) - } -// println("---- Z -----") -// z.hexColumsPrint(16) - val final = if (xorWithCurrentBlock) { -// println("Z xor R xor CURRENT") - (z xor r) xor currentBlock - } else { -// println("Z xor R") - z xor r - } - -// final.hexColumsPrint(16) - return final - } - - private fun extractColumnFromGBlock(gBlock: Array, columnPosition: Int): Array { - val result = Array(128) { 0U } - for (i in 0..7) { - gBlock.copyOfRange(i * 128 + (columnPosition * 16), i * 128 + (columnPosition * 16) + 16) - .copyInto(result, i * 16) - } - return result - } - - private fun copyIntoGBlockColumn(gBlock: Array, columnPosition: Int, columnData: Array) { - for (i in 0..7) { - val column = columnData.copyOfRange(i * 16, i * 16 + 16) - column.copyInto(gBlock, i * 128 + columnPosition * 16) - } - } - - - //based on Blake2b mixRound - internal fun mixRound(input: Array): Array { - var v = input.chunked(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 - - } - - const val R1 = 32 - const val R2 = 24 - const val R3 = 16 - const val R4 = 63 - - //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 - } - - private fun computeIndexes( - indexContext: IndexContext, - matrix: Array>> - ): Pair { - val block = indexContext.indexMatrix - val parallelism = indexContext.parallelism - val pass = indexContext.pass - val lane = indexContext.lane - val column = indexContext.column - val blockCount = indexContext.blockCount - val iterationCount = indexContext.iterationCount - val type = indexContext.type - val laneCounter = indexContext.laneCounter - - var counter = laneCounter - val sliceNumber = column / 4 - val sliceLength = blockCount / 4U - - val (j1, j2) = when (type) { - ArgonType.Argon2i -> { - val firstPass = compressionFunctionG( - Array(1024) { 0U }, - pass.toULong().toLittleEndianUByteArray() + - lane.toULong().toLittleEndianUByteArray() + - sliceNumber.toULong().toLittleEndianUByteArray() + - blockCount.toULong().toLittleEndianUByteArray() + - iterationCount.toULong().toLittleEndianUByteArray() + - type.typeId.toULong().toLittleEndianUByteArray() + - counter.toUInt().toLittleEndianUByteArray() + - Array(968) { 0U }, - emptyArray(), - false - ) - val secondPass = compressionFunctionG( - firstPass, - pass.toULong().toLittleEndianUByteArray() + - lane.toULong().toLittleEndianUByteArray() + - sliceNumber.toULong().toLittleEndianUByteArray() + - blockCount.toULong().toLittleEndianUByteArray() + - iterationCount.toULong().toLittleEndianUByteArray() + - type.typeId.toULong().toLittleEndianUByteArray() + - counter.toUInt().toLittleEndianUByteArray() + - Array(968) { 0U }, - emptyArray(), - false - ) - secondPass.hexColumsPrint() - Pair(1U, 1U) - } - ArgonType.Argon2d -> { - Pair( - (matrix[laneCounter][column - 1].sliceArray(0..3).fromLittleEndianArrayToUInt()), - (matrix[laneCounter][column - 1].sliceArray(4..7).fromLittleEndianArrayToUInt()) - ) - } - ArgonType.Argon2id -> { - Pair(1U, 1U) - } - } - - val l = if (pass == 0L && sliceNumber == 0) { - 2U - } else { - j2 % parallelism - } - -// val availableIndices = if () - - - return Pair(1, 1) - - } - - data class IndexContext( - val indexMatrix: Array, - val parallelism: UInt, - val pass: Long, - val lane: Int, - val column: Int, - val blockCount: UInt, - val iterationCount: UInt, - val type: ArgonType, - val laneCounter: Int - ) - - private fun computeIndexNew( - matrix: Array>>, - lane: Int, - column: Int, - columnCount: Int, - parallelism: Int, - iteration: Int, - slice: Int, - argonType: ArgonType - ): Pair { - val (j1, j2) = when (argonType) { - ArgonType.Argon2d -> { - val previousBlock = if (column == 0) { - matrix[lane][columnCount - 1] //Get last block in the SAME lane - } else { - matrix[lane][column - 1] - } - val first32Bit = previousBlock.sliceArray(0 until 4).fromLittleEndianArrayToUInt() - val second32Bit = previousBlock.sliceArray(4 until 8).fromLittleEndianArrayToUInt() - Pair(first32Bit, second32Bit) - } - ArgonType.Argon2i -> TODO() - ArgonType.Argon2id -> TODO() - } - - - //If this is first iteration and first slice, block is taken from the current lane - val l = if (iteration == 0 && slice == 0) { - lane - } else { - (j2.toBigInteger() % parallelism).intValue() - - } - - //From Argon 2 2020 draft - - // The set W contains the indices that can be referenced according to - // the following rules: - // 1. If l is the current lane, then W includes the indices of all - // blocks in the last SL - 1 = 3 segments computed and finished, as - // well as the blocks computed in the current segment in the current - // pass excluding B[i][j-1]. - // - // 2. If l is not the current lane, then W includes the indices of all - // blocks in the last SL - 1 = 3 segments computed and finished in - // lane l. If B[i][j] is the first block of a segment, then the - // very last index from W is excluded. - val segmentIndex = column - (slice * (columnCount / 4)) - val referenceAreaSize = if (iteration == 0) { - if (slice == 0) { - //All indices except the previous - (column % (columnCount / 4)) - 1 - } else { - if (lane == l) { - //Same lane - column - 1 - } else { - slice * (columnCount / 4) + if (column % (columnCount / 4) == 0) { // Check if column is first block of the SEGMENT - -1 - } else { - 0 - } - } - } - } else { - if (lane == l) { - columnCount - (columnCount / 4) + (column % (columnCount / 4) - 1) - } else { - columnCount - (columnCount / 4) + if (column % (columnCount / 4) == 0) { - -1 - } else { - 0 - } - } - } - - val x = (j1.toULong() * j1) shr 32 - val y = (referenceAreaSize.toULong() * x) shr 32 - val z = referenceAreaSize.toULong() - 1U - y - - val startPosition = if (iteration == 0) { - 0 - } else { - if (slice == 3) { - 0 - } else { - (slice + 1) * (columnCount / 4) //TODO replace all of these with segment length when consolidating variables - } - } - if ((startPosition + z.toInt()) % columnCount == -1) { - println("Debug") - } - val absolutePosition = (startPosition + z.toInt()) % columnCount - - return Pair(l, absolutePosition) - } - - data class ArgonContext( - val password: Array, - val salt: Array, - val parallelism: UInt, - val tagLength: UInt, - val memorySize: UInt, - val numberOfIterations: UInt, - val versionNumber: UInt, - val key: Array, - val associatedData: Array, - val type: ArgonType - ) - - data class ArgonInternalContext( - val matrix: Array>>, - val blockCount: UInt, - val columnCount: Int, - val segmentLength: Int - ) - - data class SegmentPosition( - val iteration: Int, - val lane: Int, - val slice: Int - ) - - internal fun derive( - password: Array, - salt: Array, - parallelism: UInt, - tagLength: UInt, - memorySize: UInt, - numberOfIterations: UInt, - versionNumber: UInt, - key: Array, - associatedData: Array, - type: ArgonType - ): Array { - val argonContext = ArgonContext( - password = password, - salt = salt, - parallelism = parallelism, - tagLength = tagLength, - memorySize = memorySize, - numberOfIterations = numberOfIterations, - versionNumber = versionNumber, - key = key, - associatedData = associatedData, - type = type - ) - - println("H0 Input") - val toDigest = - parallelism.toLittleEndianUByteArray() + tagLength.toLittleEndianUByteArray() + memorySize.toLittleEndianUByteArray() + - numberOfIterations.toLittleEndianUByteArray() + versionNumber.toLittleEndianUByteArray() + type.typeId.toUInt() - .toLittleEndianUByteArray() + - password.size.toUInt().toLittleEndianUByteArray() + password + - salt.size.toUInt().toLittleEndianUByteArray() + salt + - key.size.toUInt().toLittleEndianUByteArray() + key + - associatedData.size.toUInt().toLittleEndianUByteArray() + associatedData - toDigest.hexColumsPrint(16) - println("Marker H0 Input end") - val h0 = Blake2b.digest( - parallelism.toLittleEndianUByteArray() + tagLength.toLittleEndianUByteArray() + memorySize.toLittleEndianUByteArray() + - numberOfIterations.toLittleEndianUByteArray() + versionNumber.toLittleEndianUByteArray() + type.typeId.toUInt() - .toLittleEndianUByteArray() + - password.size.toUInt().toLittleEndianUByteArray() + password + - salt.size.toUInt().toLittleEndianUByteArray() + salt + - key.size.toUInt().toLittleEndianUByteArray() + key + - associatedData.size.toUInt().toLittleEndianUByteArray() + associatedData - ) - - h0.hexColumsPrint(8) - println("Marker H0") - - val blockCount = (memorySize / (4U * parallelism)) * (4U * parallelism) - val columnCount = (blockCount / parallelism).toInt() - val segmentLength = columnCount / 4 - - // First iteration - - //Allocate memory as Array of parallelism rows (lanes) and columnCount columns - val matrix = Array(parallelism.toInt()) { - Array(columnCount) { - Array(1024) { 0U } - } - } -// matrix.hexPrint() - - //Compute B[i][0] - for (i in 0 until parallelism.toInt()) { - matrix[i][0] = - argonBlake2bArbitraryLenghtHash( - h0 + 0.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray(), - 1024U - ) -// println("Start, matrix [$i][0]") -// matrix[i][0].hexColumsPrint(16) -// println("Marker, matrix [$i][0]") - } - - //Compute B[i][1] - for (i in 0 until parallelism.toInt()) { - matrix[i][1] = - argonBlake2bArbitraryLenghtHash( - h0 + 1.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray(), - 1024U - ) -// println("Start, matrix [$i][1]") -// matrix[i][1].hexColumsPrint(16) -// println("Marker, matrix [$i][1]") - } - - val argonInternalContext = ArgonInternalContext( - matrix, blockCount, columnCount, segmentLength - ) - singleThreaded(argonContext, argonInternalContext) - - val result = matrix.foldIndexed(emptyArray()) { lane, acc, laneArray -> - if (acc.size == 0) { - acc + laneArray[columnCount - 1] // add last element in first lane to the accumulator - } else { - // For each element in our accumulator, xor it with an appropriate element from the last column in current lane (from 1 to `parallelism`) - acc.mapIndexed { index, it -> it xor laneArray[columnCount - 1][index] } - .toTypedArray() - } - } - //Hash the xored last blocks - println("Tag:") - val hash = argonBlake2bArbitraryLenghtHash(result, tagLength) - return hash - } - - fun singleThreaded(argonContext: ArgonContext, argonInternalContext: ArgonInternalContext) { - for (iteration in 0 until argonContext.numberOfIterations.toInt()) { - for (slice in 0 until 4) { - for (lane in 0 until argonContext.parallelism.toInt()) { - println("Processing segment I: $iteration, S: $slice, L: $lane") - val segmentPosition = SegmentPosition(iteration, lane, slice) - processSegment(argonContext, argonInternalContext, segmentPosition) - } - } - println("Done with $iteration") - argonInternalContext.matrix[0][0].slice(0..7).toTypedArray().hexColumsPrint(8) - argonInternalContext.matrix[argonContext.parallelism.toInt() - 1][argonInternalContext.columnCount - 1].slice( - 1016..1023 - ).toTypedArray().hexColumsPrint(8) - - } - } - - fun processSegment( - argonContext: ArgonContext, - argonInternalContext: ArgonInternalContext, - segmentPosition: SegmentPosition - ) { - val password = argonContext.password - val salt = argonContext.salt - val parallelism = argonContext.parallelism - val tagLength = argonContext.tagLength - val memorySize = argonContext.memorySize - val numberOfIterations = argonContext.numberOfIterations - val versionNumber = argonContext.versionNumber - val key = argonContext.key - val associatedData = argonContext.associatedData - val type = argonContext.type - - val matrix = argonInternalContext.matrix - val blockCount = argonInternalContext.blockCount - val columnCount = argonInternalContext.columnCount - val segmentLength = argonInternalContext.segmentLength - - val iteration = segmentPosition.iteration - val lane = segmentPosition.lane - val slice = segmentPosition.slice - - - if (iteration == 0) { - //Compute B[i][j] - //Using B[i][j] = G(B[i][j], B[l][z]) where l and z are provided bu computeIndexes - //Because this is iteration 0 we have B[i][0] and B[i][1] already filled, so whenever we - //are processing first segment we skip these two blocks - if (slice == 0) { - for (column in 2..(slice * segmentLength)) { - val (l, z) = computeIndexNew(matrix, lane, column, columnCount, parallelism.toInt(), 0, 0, type) - println("Calling compress for I: $iteration S: $slice Lane: $lane Column: $column with l: $l z: $z") - matrix[lane][column] = - compressionFunctionG(matrix[lane][column - 1], matrix[l][z], matrix[lane][column], false) -// matrix[lane][column].hexColumsPrint(16) - } - - } else { - for (column in (slice * segmentLength) until ((slice + 1) * segmentLength)) { - val (l, z) = computeIndexNew( - matrix, - lane, - column, - columnCount, - parallelism.toInt(), - iteration, - slice, - type - ) - println("Calling compress for I: $iteration S: $slice Lane: $lane Column: $column with l: $l z: $z") - matrix[lane][column] = - compressionFunctionG(matrix[lane][column - 1], matrix[l][z], matrix[lane][column], false) -// matrix[lane][column].hexColumsPrint(16) - println("debug") - } - } - } else { - if (slice == 0) { - val (l, z) = computeIndexNew( - matrix, - lane, - 0, - columnCount, - parallelism.toInt(), - iteration, - slice, - type - ) - matrix[lane][0] = - compressionFunctionG(matrix[lane][columnCount - 1], matrix[l][z], matrix[lane][0], true) - for (column in 1 until segmentLength) { - val (l, z) = computeIndexNew( - matrix, - lane, - column, - columnCount, - parallelism.toInt(), - iteration, - slice, - type - ) - println("Calling compress for I: $iteration S: $slice Lane: $lane Column: $column with l: $l z: $z") - matrix[lane][column] = - compressionFunctionG(matrix[lane][column - 1], matrix[l][z], matrix[lane][column], true) -// matrix[lane][column].hexColumsPrint(16) - } - } else { - for (column in slice * segmentLength until (slice + 1) * segmentLength) { - val (l, z) = computeIndexNew( - matrix, - lane, - column, - columnCount, - parallelism.toInt(), - iteration, - slice, - type - ) - println("Calling compress for I: $iteration S: $slice Lane: $lane Column: $column with l: $l z: $z") - matrix[lane][column] = - compressionFunctionG(matrix[lane][column - 1], matrix[l][z], matrix[lane][column], true) -// matrix[lane][column].hexColumsPrint(16) - } - } - - - } - - -// //Remaining iteration -// val remainingIterations = (1..numberOfIterations.toInt()).map { iteration -> -// -// for (i in 0 until parallelism.toInt()) { -// for (j in 0 until columnCount) { -// val (l, z) = computeIndexNew( -// matrix, -// i, -// j, -// columnCount, -// parallelism.toInt(), -// iteration, -// iteration / segmentLength, -// type -// ) -// if (j == 0) { -// matrix[i][j] = compressionFunctionG(matrix[i][columnCount - 1], matrix[l][z]) -// } else { -// matrix[i][j] = compressionFunctionG(matrix[i][j - 1], matrix[l][z]) -// } -// -// } -// } -// -// -// val result = matrix.foldIndexed(emptyArray()) { lane, acc, laneArray -> -// return if (acc.size == 0) { -// acc + laneArray[columnCount - 1] // add last element in first lane to the accumulator -// } else { -// // For each element in our accumulator, xor it with an appropriate element from the last column in current lane (from 1 to `parallelism`) -// acc.mapIndexed { index, it -> it xor laneArray[columnCount - 1][index] } -// .toTypedArray() -// } -// } -// result -// } - - -// return remainingIterations.foldRight(emptyArray()) { arrayOfUBytes, acc -> acc xor arrayOfUBytes } //TODO placeholder - } - - } - - - fun calculate(): Array { - return derive( - password, - salt, - parallelism, - tagLength, - memorySize, - numberOfIterations, - versionNumber, - key, - associatedData, - type - ) - } - - -} - -internal object ArgonDebugUtils { - fun Array>>.hexPrint() { - forEachIndexed { i, lane -> - lane.forEachIndexed { j, column -> - println("Printing position at [$i], [$j]") - column.hexColumsPrint(32) - } - } - } -} 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 da37aef..4ea297b 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 @@ -139,7 +139,24 @@ class Argon2( val second32Bit = selectedAddressBlock.sliceArray(4 until 8).fromLittleEndianArrayToUInt() Pair(first32Bit, second32Bit) } - ArgonType.Argon2id -> TODO() + ArgonType.Argon2id -> { + if (iteration == 0 && (slice == 0 || slice == 1)) { + val selectedAddressBlock = addressBlock!!.sliceArray((segmentIndex * 8) until (segmentIndex * 8) + 8) + val first32Bit = selectedAddressBlock.sliceArray(0 until 4).fromLittleEndianArrayToUInt() + val second32Bit = selectedAddressBlock.sliceArray(4 until 8).fromLittleEndianArrayToUInt() + Pair(first32Bit, second32Bit) + } else { + val previousBlock = if (column == 0) { + matrix[lane][columnCount - 1] //Get last block in the SAME lane + } else { + matrix[lane][column - 1] + } + val first32Bit = previousBlock.sliceArray(0 until 4).fromLittleEndianArrayToUInt() + val second32Bit = previousBlock.sliceArray(4 until 8).fromLittleEndianArrayToUInt() + Pair(first32Bit, second32Bit) + } + + } } //If this is first iteration and first slice, block is taken from the current lane 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 e24692d..a867a8b 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 @@ -19,7 +19,6 @@ package com.ionspin.kotlin.crypto.keyderivation.argon2 import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b -import com.ionspin.kotlin.crypto.keyderivation.Argon2Template import com.ionspin.kotlin.crypto.util.* /** diff --git a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/keyderivation/Argon2Test.kt b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/keyderivation/Argon2Test.kt index 8dcdafc..3cd6e49 100644 --- a/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/keyderivation/Argon2Test.kt +++ b/multiplatform-crypto/src/commonTest/kotlin/com/ionspin/kotlin/crypto/hash/keyderivation/Argon2Test.kt @@ -18,11 +18,9 @@ package com.ionspin.kotlin.crypto.hash.keyderivation -import com.ionspin.kotlin.crypto.keyderivation.Argon2Template import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2 import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonType import com.ionspin.kotlin.crypto.util.hexColumsPrint -import kotlin.math.exp import kotlin.test.Test import kotlin.test.assertTrue @@ -34,39 +32,6 @@ import kotlin.test.assertTrue @ExperimentalStdlibApi class Argon2Test { - @Test - fun debugTest() { - val memory = 32U //KiB - val iterations = 3U - val parallelism = 4U - val tagLength = 32U - val password: Array = arrayOf( - 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, - 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, - 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, - 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U - ) - val salt: Array = arrayOf(0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U) - val secret: Array = arrayOf(0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U) - val associatedData: Array = arrayOf(0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U) - - val digest = Argon2Template( - password, - salt, - parallelism, - tagLength, - memory, - iterations, - 0x13U, - secret, - associatedData, - type = Argon2Template.ArgonType.Argon2d - ) - val result = digest.calculate() - result.hexColumsPrint(8) - - } - @Test fun argon2dKATTest() { val expected : Array = arrayOf( @@ -148,4 +113,45 @@ class Argon2Test { assertTrue { expected.contentEquals(result) } } + + @Test + fun argon2idKATTest() { + val expected : Array = arrayOf( + 0x0dU, 0x64U, 0x0dU, 0xf5U, 0x8dU, 0x78U, 0x76U, 0x6cU, + 0x08U, 0xc0U, 0x37U, 0xa3U, 0x4aU, 0x8bU, 0x53U, 0xc9U, + 0xd0U, 0x1eU, 0xf0U, 0x45U, 0x2dU, 0x75U, 0xb6U, 0x5eU, + 0xb5U, 0x25U, 0x20U, 0xe9U, 0x6bU, 0x01U, 0xe6U, 0x59U + ) + + + val memory = 32U //KiB + val iterations = 3U + val parallelism = 4U + val tagLength = 32U + val password: Array = arrayOf( + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, + 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U + ) + val salt: Array = arrayOf(0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U) + val secret: Array = arrayOf(0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U) + val associatedData: Array = arrayOf(0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U) + + val digest = Argon2( + password, + salt, + parallelism.toInt(), + tagLength, + memory, + iterations, + secret, + associatedData, + ArgonType.Argon2id + ) + val result = digest.derive() + result.hexColumsPrint(8) + assertTrue { expected.contentEquals(result) } + + } } \ No newline at end of file