Further progress
This commit is contained in:
parent
7e8e48aa1d
commit
803288cbc4
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user