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.*
|
import com.ionspin.kotlin.crypto.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
|
* Further resources and examples of implementation:
|
||||||
* https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03
|
* https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03
|
||||||
* https://en.wikipedia.org/wiki/Argon2
|
* https://en.wikipedia.org/wiki/Argon2
|
||||||
* https://www.cryptolux.org/images/0/0d/Argon2.pdf
|
* 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
|
* Created by Ugljesa Jovanovic
|
||||||
* ugljesa.jovanovic@ionspin.com
|
* ugljesa.jovanovic@ionspin.com
|
||||||
* on 08-Jan-2020
|
* on 08-Jan-2020
|
||||||
*
|
*
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
class Argon2 internal constructor(
|
class Argon2 internal constructor(
|
||||||
@ -44,15 +46,28 @@ class Argon2 internal constructor(
|
|||||||
val associatedData: Array<UByte>,
|
val associatedData: Array<UByte>,
|
||||||
val type: ArgonType
|
val type: ArgonType
|
||||||
) {
|
) {
|
||||||
enum class ArgonType {
|
enum class ArgonType(val typeId: Int) {
|
||||||
Argon2i, Argon2d, Argon2id
|
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
|
@ExperimentalStdlibApi
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
|
||||||
fun argonHash(input: Array<UByte>, length: UInt): Array<UByte> {
|
fun argonBlake2bArbitraryLenghtHash(input: Array<UByte>, length: UInt): Array<UByte> {
|
||||||
if (length <= 64U) {
|
if (length <= 64U) {
|
||||||
return Blake2b.digest(length + input)
|
return Blake2b.digest(length + input)
|
||||||
}
|
}
|
||||||
@ -121,7 +136,7 @@ class Argon2 internal constructor(
|
|||||||
|
|
||||||
//based on Blake2b mixRound
|
//based on Blake2b mixRound
|
||||||
internal fun mixRound(input: Array<UByte>): Array<ULong> {
|
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, 0, 4, 8, 12)
|
||||||
v = mix(v, 1, 5, 9, 13)
|
v = mix(v, 1, 5, 9, 13)
|
||||||
v = mix(v, 2, 6, 10, 14)
|
v = mix(v, 2, 6, 10, 14)
|
||||||
@ -152,6 +167,74 @@ class Argon2 internal constructor(
|
|||||||
return v
|
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(
|
internal fun derive(
|
||||||
password: Array<UByte>,
|
password: Array<UByte>,
|
||||||
@ -177,6 +260,8 @@ class Argon2 internal constructor(
|
|||||||
val blockCount = (memorySize / (4U * parallelism)) * (4U * parallelism) //
|
val blockCount = (memorySize / (4U * parallelism)) * (4U * parallelism) //
|
||||||
val columnCount = blockCount / 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
|
//Allocate memory as Array of parallelism rows and columnCount colums
|
||||||
val matrix = Array(parallelism.toInt()) {
|
val matrix = Array(parallelism.toInt()) {
|
||||||
Array(columnCount.toInt()) {
|
Array(columnCount.toInt()) {
|
||||||
@ -187,18 +272,26 @@ class Argon2 internal constructor(
|
|||||||
//Compute B[i][0]
|
//Compute B[i][0]
|
||||||
for (i in 0..parallelism.toInt()) {
|
for (i in 0..parallelism.toInt()) {
|
||||||
matrix[i][0] =
|
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]
|
//Compute B[i][1]
|
||||||
for (i in 0..parallelism.toInt()) {
|
for (i in 0..parallelism.toInt()) {
|
||||||
matrix[i][0] =
|
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 (i in 0..parallelism.toInt()) {
|
||||||
for (j in 1..columnCount.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 iPrim = -1
|
||||||
val jPrim = -1
|
val jPrim = -1
|
||||||
matrix[i][j] = compressionFunctionG(matrix[i][j - 1], matrix[iPrim][jPrim])
|
matrix[i][j] = compressionFunctionG(matrix[i][j - 1], matrix[iPrim][jPrim])
|
||||||
@ -209,13 +302,16 @@ class Argon2 internal constructor(
|
|||||||
return if (acc.size == 0) {
|
return if (acc.size == 0) {
|
||||||
acc + arrayOfArrays[columnCount.toInt() - 1]
|
acc + arrayOfArrays[columnCount.toInt() - 1]
|
||||||
} else {
|
} 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
|
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
|
@ExperimentalUnsignedTypes
|
||||||
operator fun UInt.plus(other : Array<UByte>) : Array<UByte> {
|
operator fun UInt.plus(other : Array<UByte>) : Array<UByte> {
|
||||||
return this.toLittleEndianUByteArray() + other
|
return this.toLittleEndianUByteArray() + other
|
||||||
|
Loading…
x
Reference in New Issue
Block a user