Cleanup, working kat for Argon2id
This commit is contained in:
		
							parent
							
								
									e08f69f643
								
							
						
					
					
						commit
						1208d0549c
					
				| @ -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<UByte>, |  | ||||||
|     val salt: Array<UByte>, |  | ||||||
|     val parallelism: UInt, |  | ||||||
|     val tagLength: UInt, |  | ||||||
|     val memorySize: UInt, |  | ||||||
|     val numberOfIterations: UInt, |  | ||||||
|     val versionNumber: UInt, |  | ||||||
|     val key: Array<UByte>, |  | ||||||
|     val associatedData: Array<UByte>, |  | ||||||
|     val type: ArgonType |  | ||||||
| ) { |  | ||||||
|     enum class ArgonType(val typeId: Int) { |  | ||||||
|         Argon2d(0), Argon2i(1), Argon2id(2) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     data class Argon2StreamGContext( |  | ||||||
|         val block: Array<UByte>, |  | ||||||
|         val passNumber: Int, |  | ||||||
|         val sliceNumber: Int, |  | ||||||
|         val blockCount: UInt, |  | ||||||
|         val numberOfIterations: UInt, |  | ||||||
|         val counter: UInt, |  | ||||||
|         val type: ArgonType |  | ||||||
|     ) { |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     @ExperimentalStdlibApi |  | ||||||
|     companion object { |  | ||||||
| 
 |  | ||||||
|         fun Array<UByte>.xor(target: Array<UByte>, other: Array<UByte>) { |  | ||||||
|             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<UByte>, length: UInt): Array<UByte> { |  | ||||||
|             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<Array<UByte>>(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<UByte>()) { arrayOfUBytes, acc -> arrayOfUBytes + acc } |  | ||||||
| 
 |  | ||||||
|             return concat |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|         fun compressionFunctionG( |  | ||||||
|             previousBlock: Array<UByte>, |  | ||||||
|             referenceBlock: Array<UByte>, |  | ||||||
|             currentBlock: Array<UByte>, |  | ||||||
|             xorWithCurrentBlock: Boolean |  | ||||||
|         ): Array<UByte> { |  | ||||||
|             val r = referenceBlock xor previousBlock |  | ||||||
| //            println("R = X xor Y") |  | ||||||
| //            r.hexColumsPrint(16) |  | ||||||
| //            val r = Array<UByte>(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<UByte>(1024) { 0U } |  | ||||||
|             val z = Array<UByte>(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<UByte>, columnPosition: Int): Array<UByte> { |  | ||||||
|             val result = Array<UByte>(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<UByte>, columnPosition: Int, columnData: Array<UByte>) { |  | ||||||
|             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<UByte>): Array<ULong> { |  | ||||||
|             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<ULong>, a: Int, b: Int, c: Int, d: Int): Array<ULong> { |  | ||||||
|             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<Array<Array<UByte>>> |  | ||||||
|         ): Pair<Int, Int> { |  | ||||||
|             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<UByte>(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<UByte>(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<UByte>(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<UByte>, |  | ||||||
|             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<Array<Array<UByte>>>, |  | ||||||
|             lane: Int, |  | ||||||
|             column: Int, |  | ||||||
|             columnCount: Int, |  | ||||||
|             parallelism: Int, |  | ||||||
|             iteration: Int, |  | ||||||
|             slice: Int, |  | ||||||
|             argonType: ArgonType |  | ||||||
|         ): Pair<Int, Int> { |  | ||||||
|             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<UByte>, |  | ||||||
|             val salt: Array<UByte>, |  | ||||||
|             val parallelism: UInt, |  | ||||||
|             val tagLength: UInt, |  | ||||||
|             val memorySize: UInt, |  | ||||||
|             val numberOfIterations: UInt, |  | ||||||
|             val versionNumber: UInt, |  | ||||||
|             val key: Array<UByte>, |  | ||||||
|             val associatedData: Array<UByte>, |  | ||||||
|             val type: ArgonType |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|         data class ArgonInternalContext( |  | ||||||
|             val matrix: Array<Array<Array<UByte>>>, |  | ||||||
|             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<UByte>, |  | ||||||
|             salt: Array<UByte>, |  | ||||||
|             parallelism: UInt, |  | ||||||
|             tagLength: UInt, |  | ||||||
|             memorySize: UInt, |  | ||||||
|             numberOfIterations: UInt, |  | ||||||
|             versionNumber: UInt, |  | ||||||
|             key: Array<UByte>, |  | ||||||
|             associatedData: Array<UByte>, |  | ||||||
|             type: ArgonType |  | ||||||
|         ): Array<UByte> { |  | ||||||
|             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<UByte>(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<UByte>()) { 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<UByte>()) { 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<UByte> { |  | ||||||
|         return derive( |  | ||||||
|             password, |  | ||||||
|             salt, |  | ||||||
|             parallelism, |  | ||||||
|             tagLength, |  | ||||||
|             memorySize, |  | ||||||
|             numberOfIterations, |  | ||||||
|             versionNumber, |  | ||||||
|             key, |  | ||||||
|             associatedData, |  | ||||||
|             type |  | ||||||
|         ) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| internal object ArgonDebugUtils { |  | ||||||
|     fun Array<Array<Array<UByte>>>.hexPrint() { |  | ||||||
|         forEachIndexed { i, lane -> |  | ||||||
|             lane.forEachIndexed { j, column -> |  | ||||||
|                 println("Printing position at [$i], [$j]") |  | ||||||
|                 column.hexColumsPrint(32) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -139,7 +139,24 @@ class Argon2( | |||||||
|                 val second32Bit = selectedAddressBlock.sliceArray(4 until 8).fromLittleEndianArrayToUInt() |                 val second32Bit = selectedAddressBlock.sliceArray(4 until 8).fromLittleEndianArrayToUInt() | ||||||
|                 Pair(first32Bit, second32Bit) |                 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 |         //If this is first iteration and first slice, block is taken from the current lane | ||||||
|  | |||||||
| @ -19,7 +19,6 @@ | |||||||
| package com.ionspin.kotlin.crypto.keyderivation.argon2 | package com.ionspin.kotlin.crypto.keyderivation.argon2 | ||||||
| 
 | 
 | ||||||
| import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b | import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b | ||||||
| import com.ionspin.kotlin.crypto.keyderivation.Argon2Template |  | ||||||
| import com.ionspin.kotlin.crypto.util.* | import com.ionspin.kotlin.crypto.util.* | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | |||||||
| @ -18,11 +18,9 @@ | |||||||
| 
 | 
 | ||||||
| package com.ionspin.kotlin.crypto.hash.keyderivation | 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.Argon2 | ||||||
| import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonType | import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonType | ||||||
| import com.ionspin.kotlin.crypto.util.hexColumsPrint | import com.ionspin.kotlin.crypto.util.hexColumsPrint | ||||||
| import kotlin.math.exp |  | ||||||
| import kotlin.test.Test | import kotlin.test.Test | ||||||
| import kotlin.test.assertTrue | import kotlin.test.assertTrue | ||||||
| 
 | 
 | ||||||
| @ -34,39 +32,6 @@ import kotlin.test.assertTrue | |||||||
| @ExperimentalStdlibApi | @ExperimentalStdlibApi | ||||||
| class Argon2Test { | class Argon2Test { | ||||||
| 
 | 
 | ||||||
|     @Test |  | ||||||
|     fun debugTest() { |  | ||||||
|         val memory = 32U //KiB |  | ||||||
|         val iterations = 3U |  | ||||||
|         val parallelism = 4U |  | ||||||
|         val tagLength = 32U |  | ||||||
|         val password: Array<UByte> = 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<UByte> =           arrayOf(0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U) |  | ||||||
|         val secret: Array<UByte> =         arrayOf(0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U) |  | ||||||
|         val associatedData: Array<UByte> = 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 |     @Test | ||||||
|     fun argon2dKATTest() { |     fun argon2dKATTest() { | ||||||
|         val expected : Array<UByte> = arrayOf( |         val expected : Array<UByte> = arrayOf( | ||||||
| @ -148,4 +113,45 @@ class Argon2Test { | |||||||
|         assertTrue { expected.contentEquals(result) } |         assertTrue { expected.contentEquals(result) } | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     fun argon2idKATTest() { | ||||||
|  |         val expected : Array<UByte> = 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<UByte> = 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<UByte> =           arrayOf(0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U, 0x02U) | ||||||
|  |         val secret: Array<UByte> =         arrayOf(0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U) | ||||||
|  |         val associatedData: Array<UByte> = 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) } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
| } | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user