From 803288cbc4a2461ce8114d4fd672afda0d461828 Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Wed, 15 Jan 2020 21:54:30 +0100 Subject: [PATCH] Further progress --- .../kotlin/crypto/keyderivation/Argon2.kt | 170 ++++++++++++++---- .../com/ionspin/kotlin/crypto/util/Util.kt | 19 ++ 2 files changed, 152 insertions(+), 37 deletions(-) diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/Argon2.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/Argon2.kt index 300f47c..fd1c522 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/Argon2.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/keyderivation/Argon2.kt @@ -20,16 +20,18 @@ 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 * - * - * */ @ExperimentalUnsignedTypes class Argon2 internal constructor( @@ -44,15 +46,28 @@ class Argon2 internal constructor( val associatedData: Array, val type: ArgonType ) { - enum class ArgonType { - Argon2i, Argon2d, Argon2id + 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 argonHash(input: Array, length: UInt): Array { + fun argonBlake2bArbitraryLenghtHash(input: Array, length: UInt): Array { if (length <= 64U) { return Blake2b.digest(length + input) } @@ -121,7 +136,7 @@ class Argon2 internal constructor( //based on Blake2b mixRound internal fun mixRound(input: Array): Array { - var v = input.chunked(4).map { it.fromLittleEndianArrayToULong() }.toTypedArray() + 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) @@ -152,6 +167,74 @@ class Argon2 internal constructor( return v } + private fun computeIndexes( + block: Array>>, + pass: Long, + lane: Int, + column: Int, + blockCount: UInt, + iterationCount: UInt, + type: ArgonType, + laneCounter : Int + + ): Pair { + 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 } + ) + 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 } + ) + Pair(firstPass, secondPass) + } + ArgonType.Argon2d -> { + Pair( + (block[laneCounter][column - 1].sliceArray(0..3).fromLittleEndianArrayToUInt()), + (block[laneCounter][column - 1].sliceArray(4..7).fromLittleEndianArrayToUInt()) + ) + } + ArgonType.Argon2id -> { + Pair(emptyArray(), emptyArray()) + } + } + + return Pair(1, 1) + + } + + fun populateSegment( + matrix: Array>>, + pass: Long, + lane: Int, + column: Int, + blockCount: UInt, + iterationCount: UInt, + type: ArgonType, + laneCounter : Int + ) { + //TODO handle segment by segment + } + internal fun derive( password: Array, @@ -177,48 +260,61 @@ class Argon2 internal constructor( val blockCount = (memorySize / (4U * parallelism)) * (4U * parallelism) // val columnCount = blockCount / parallelism - //Allocate memory as Array of parallelism rows and columnCount colums - val matrix = Array(parallelism.toInt()) { - Array(columnCount.toInt()) { - Array(1024) { 0U } + //TODO pass handling + val allPasses = (0 .. numberOfIterations.toLong()).map { pass -> + //Allocate memory as Array of parallelism rows and columnCount colums + val matrix = Array(parallelism.toInt()) { + Array(columnCount.toInt()) { + Array(1024) { 0U } + } } - } - //Compute B[i][0] - for (i in 0..parallelism.toInt()) { - matrix[i][0] = - argonHash(h0 + 0.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray(), 64U) - } - - //Compute B[i][1] - for (i in 0..parallelism.toInt()) { - matrix[i][0] = - argonHash(h0 + 1.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray(), 64U) - } - - for (i in 0..parallelism.toInt()) { - for (j in 1..columnCount.toInt()) { - //TODO i,j choosing based on type - val iPrim = -1 - val jPrim = -1 - matrix[i][j] = compressionFunctionG(matrix[i][j - 1], matrix[iPrim][jPrim]) + //Compute B[i][0] + for (i in 0..parallelism.toInt()) { + matrix[i][0] = + argonBlake2bArbitraryLenghtHash( + h0 + 0.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray(), + 64U + ) } - } - val result = matrix.foldIndexed(emptyArray()) { index, acc, arrayOfArrays -> - return if (acc.size == 0) { - acc + arrayOfArrays[columnCount.toInt() - 1] - } else { - acc.mapIndexed { index, it -> it xor arrayOfArrays[columnCount.toInt() - 1][index] }.toTypedArray() + //Compute B[i][1] + for (i in 0..parallelism.toInt()) { + matrix[i][0] = + argonBlake2bArbitraryLenghtHash( + h0 + 1.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray(), + 64U + ) } + + for (i in 0..parallelism.toInt()) { + for (j in 1..columnCount.toInt()) { + + val counter = 0 //TODO handle counter + computeIndexes(matrix, pass, i, j, blockCount, numberOfIterations, type) + val iPrim = -1 + val jPrim = -1 + matrix[i][j] = compressionFunctionG(matrix[i][j - 1], matrix[iPrim][jPrim]) + } + } + + val result = matrix.foldIndexed(emptyArray()) { index, acc, arrayOfArrays -> + return if (acc.size == 0) { + acc + arrayOfArrays[columnCount.toInt() - 1] + } else { + acc.mapIndexed { index, it -> it xor arrayOfArrays[columnCount.toInt() - 1][index] } + .toTypedArray() + } + } + result } - return result + return allPasses.foldRight(emptyArray()) { arrayOfUBytes, acc -> acc xor arrayOfUBytes } //TODO placeholder } } -} \ No newline at end of file +} diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/util/Util.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/util/Util.kt index 8d8924b..795b180 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/util/Util.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/util/Util.kt @@ -140,6 +140,25 @@ fun Array.fromBigEndianArrayToULong() : ULong { return ulong } +@ExperimentalUnsignedTypes +fun Array.fromLittleEndianArrayToUInt() : ULong { + if (this.size > 4) { + throw RuntimeException("ore than 8 bytes in input, potential overflow") + } + var ulong = this.foldIndexed(0UL) { index, acc, uByte -> acc or (uByte.toULong() shl (index * 8))} + return ulong +} + + +@ExperimentalUnsignedTypes +fun Array.fromBigEndianArrayToUInt() : ULong { + if (this.size > 4) { + throw RuntimeException("ore than 8 bytes in input, potential overflow") + } + var ulong = this.foldIndexed(0UL) { index, acc, uByte -> acc or (uByte.toULong() shl (24 - (index * 8))) } + return ulong +} + @ExperimentalUnsignedTypes operator fun UInt.plus(other : Array) : Array { return this.toLittleEndianUByteArray() + other