Further progress

This commit is contained in:
Ugljesa Jovanovic 2020-01-15 21:54:30 +01:00
parent 7e8e48aa1d
commit 803288cbc4
No known key found for this signature in database
GPG Key ID: 178E6DFCECCB0E0F
2 changed files with 152 additions and 37 deletions

View File

@ -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<UByte>,
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<UByte>,
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<UByte>, length: UInt): Array<UByte> {
fun argonBlake2bArbitraryLenghtHash(input: Array<UByte>, length: UInt): Array<UByte> {
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<UByte>): Array<ULong> {
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<Array<Array<UByte>>>,
pass: Long,
lane: Int,
column: Int,
blockCount: UInt,
iterationCount: UInt,
type: ArgonType,
laneCounter : Int
): Pair<Int, Int> {
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 }
)
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 }
)
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<UByte>(), emptyArray<UByte>())
}
}
return Pair(1, 1)
}
fun populateSegment(
matrix: Array<Array<Array<UByte>>>,
pass: Long,
lane: Int,
column: Int,
blockCount: UInt,
iterationCount: UInt,
type: ArgonType,
laneCounter : Int
) {
//TODO handle segment by segment
}
internal fun derive(
password: Array<UByte>,
@ -177,6 +260,8 @@ class Argon2 internal constructor(
val blockCount = (memorySize / (4U * parallelism)) * (4U * parallelism) //
val columnCount = blockCount / parallelism
//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()) {
@ -187,18 +272,26 @@ class Argon2 internal constructor(
//Compute B[i][0]
for (i in 0..parallelism.toInt()) {
matrix[i][0] =
argonHash(h0 + 0.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray(), 64U)
argonBlake2bArbitraryLenghtHash(
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)
argonBlake2bArbitraryLenghtHash(
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 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])
@ -209,13 +302,16 @@ class Argon2 internal constructor(
return if (acc.size == 0) {
acc + arrayOfArrays[columnCount.toInt() - 1]
} else {
acc.mapIndexed { index, it -> it xor arrayOfArrays[columnCount.toInt() - 1][index] }.toTypedArray()
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
}
}

View File

@ -140,6 +140,25 @@ fun Array<UByte>.fromBigEndianArrayToULong() : ULong {
return ulong
}
@ExperimentalUnsignedTypes
fun Array<UByte>.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<UByte>.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<UByte>) : Array<UByte> {
return this.toLittleEndianUByteArray() + other