Replacing array of arrays of ubyte arrays with custom argon2 matrix
This commit is contained in:
parent
f5b3eb6b92
commit
13b60a5eee
@ -27,6 +27,7 @@ import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.compressionFun
|
|||||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.validateArgonParameters
|
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.validateArgonParameters
|
||||||
import com.ionspin.kotlin.crypto.util.fromLittleEndianArrayToUInt
|
import com.ionspin.kotlin.crypto.util.fromLittleEndianArrayToUInt
|
||||||
import com.ionspin.kotlin.crypto.util.toLittleEndianUByteArray
|
import com.ionspin.kotlin.crypto.util.toLittleEndianUByteArray
|
||||||
|
import com.ionspin.kotlin.crypto.util.xor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Ugljesa Jovanovic
|
* Created by Ugljesa Jovanovic
|
||||||
@ -132,15 +133,10 @@ class Argon2(
|
|||||||
private val useIndependentAddressing = argonType == ArgonType.Argon2id || argonType == ArgonType.Argon2i
|
private val useIndependentAddressing = argonType == ArgonType.Argon2id || argonType == ArgonType.Argon2i
|
||||||
|
|
||||||
// State
|
// State
|
||||||
private val matrix: Array<Array<UByteArray>>
|
private val matrix: Argon2Matrix
|
||||||
|
|
||||||
init {
|
init {
|
||||||
matrix = Array(parallelism) {
|
matrix = Argon2Matrix(columnCount, parallelism)
|
||||||
Array(columnCount) {
|
|
||||||
UByteArray(1024)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
validateArgonParameters(
|
validateArgonParameters(
|
||||||
password,
|
password,
|
||||||
salt,
|
salt,
|
||||||
@ -154,15 +150,7 @@ class Argon2(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun clearMatrix() {
|
|
||||||
matrix.forEachIndexed { laneIndex, lane ->
|
|
||||||
lane.forEachIndexed { columnIndex, block ->
|
|
||||||
block.forEachIndexed { byteIndex, byte ->
|
|
||||||
matrix[laneIndex][columnIndex][byteIndex] = 0U
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun populateAddressBlock(
|
private fun populateAddressBlock(
|
||||||
iteration: Int,
|
iteration: Int,
|
||||||
@ -202,17 +190,18 @@ class Argon2(
|
|||||||
column: Int,
|
column: Int,
|
||||||
addressBlock: UByteArray?
|
addressBlock: UByteArray?
|
||||||
): Pair<Int, Int> {
|
): Pair<Int, Int> {
|
||||||
|
|
||||||
val segmentIndex = (column % segmentLength)
|
val segmentIndex = (column % segmentLength)
|
||||||
val independentIndex = segmentIndex % 128 // 128 is the number of addresses in address block
|
val independentIndex = segmentIndex % 128 // 128 is the number of addresses in address block
|
||||||
val (j1, j2) = when (argonType) {
|
val (j1, j2) = when (argonType) {
|
||||||
ArgonType.Argon2d -> {
|
ArgonType.Argon2d -> {
|
||||||
val previousBlock = if (column == 0) {
|
val (previousBlockStart, previousBlockEnd) = if (column == 0) {
|
||||||
matrix[lane][columnCount - 1] //Get last block in the SAME lane
|
matrix.getBlockStartAndEndPositions(lane, columnCount - 1) //Get last block in the SAME lane
|
||||||
} else {
|
} else {
|
||||||
matrix[lane][column - 1]
|
matrix.getBlockStartAndEndPositions(lane, column - 1)
|
||||||
}
|
}
|
||||||
val first32Bit = previousBlock.sliceArray(0 until 4).fromLittleEndianArrayToUInt()
|
val first32Bit = matrix.sliceArray(previousBlockStart until previousBlockStart + 4).fromLittleEndianArrayToUInt()
|
||||||
val second32Bit = previousBlock.sliceArray(4 until 8).fromLittleEndianArrayToUInt()
|
val second32Bit = matrix.sliceArray(previousBlockStart + 4 until previousBlockStart + 8).fromLittleEndianArrayToUInt()
|
||||||
Pair(first32Bit, second32Bit)
|
Pair(first32Bit, second32Bit)
|
||||||
}
|
}
|
||||||
ArgonType.Argon2i -> {
|
ArgonType.Argon2i -> {
|
||||||
@ -230,13 +219,13 @@ class Argon2(
|
|||||||
val second32Bit = selectedAddressBlock.sliceArray(4 until 8).fromLittleEndianArrayToUInt()
|
val second32Bit = selectedAddressBlock.sliceArray(4 until 8).fromLittleEndianArrayToUInt()
|
||||||
Pair(first32Bit, second32Bit)
|
Pair(first32Bit, second32Bit)
|
||||||
} else {
|
} else {
|
||||||
val previousBlock = if (column == 0) {
|
val (previousBlockStart, previousBlockEnd) = if (column == 0) {
|
||||||
matrix[lane][columnCount - 1] //Get last block in the SAME lane
|
matrix.getBlockStartAndEndPositions(lane, columnCount - 1) //Get last block in the SAME lane
|
||||||
} else {
|
} else {
|
||||||
matrix[lane][column - 1]
|
matrix.getBlockStartAndEndPositions(lane, column - 1)
|
||||||
}
|
}
|
||||||
val first32Bit = previousBlock.sliceArray(0 until 4).fromLittleEndianArrayToUInt()
|
val first32Bit = matrix.sliceArray(previousBlockStart until previousBlockStart + 4).fromLittleEndianArrayToUInt()
|
||||||
val second32Bit = previousBlock.sliceArray(4 until 8).fromLittleEndianArrayToUInt()
|
val second32Bit = matrix.sliceArray(previousBlockStart + 4 until previousBlockStart + 8).fromLittleEndianArrayToUInt()
|
||||||
Pair(first32Bit, second32Bit)
|
Pair(first32Bit, second32Bit)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,35 +304,43 @@ class Argon2(
|
|||||||
|
|
||||||
//Compute B[i][0]
|
//Compute B[i][0]
|
||||||
for (i in 0 until parallelism) {
|
for (i in 0 until parallelism) {
|
||||||
matrix[i][0] =
|
matrix.setBlockAt(i, 0,
|
||||||
argonBlake2bArbitraryLenghtHash(
|
argonBlake2bArbitraryLenghtHash(
|
||||||
(h0 + 0.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray()).toUByteArray(),
|
(h0 + 0.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray()).toUByteArray(),
|
||||||
1024U
|
1024U
|
||||||
)
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Compute B[i][1]
|
//Compute B[i][1]
|
||||||
for (i in 0 until parallelism) {
|
for (i in 0 until parallelism) {
|
||||||
matrix[i][1] =
|
matrix.setBlockAt(i, 1,
|
||||||
argonBlake2bArbitraryLenghtHash(
|
argonBlake2bArbitraryLenghtHash(
|
||||||
(h0 + 1.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray()).toUByteArray(),
|
(h0 + 1.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray()).toUByteArray(),
|
||||||
1024U
|
1024U
|
||||||
)
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
//Run all iterations over all lanes and all segments
|
||||||
executeArgonWithSingleThread()
|
executeArgonWithSingleThread()
|
||||||
|
|
||||||
val result = matrix.foldIndexed(ubyteArrayOf()) { lane, acc, laneArray ->
|
// val result = matrix.foldIndexed(ubyteArrayOf()) { lane, acc, laneArray ->
|
||||||
if (acc.size == 0) {
|
// if (acc.size == 0) {
|
||||||
acc + laneArray[columnCount - 1] // add last element in first lane to the accumulator
|
// acc + laneArray[columnCount - 1] // add last element in first lane to the accumulator
|
||||||
} else {
|
// } else {
|
||||||
// For each element in our accumulator, xor it with an appropriate element from the last column in current lane (from 1 to `parallelism`)
|
// // 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] }.toUByteArray()
|
// acc.mapIndexed { index, it -> it xor laneArray[columnCount - 1][index] }.toUByteArray()
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
//Temporary fold
|
||||||
|
val acc = matrix.getBlockAt(0, columnCount - 1).copyOf()
|
||||||
|
for (i in 1 until parallelism) {
|
||||||
|
acc.xor(matrix.getBlockAt(i, columnCount -1))
|
||||||
}
|
}
|
||||||
//Hash the xored last blocks
|
//Hash the xored last blocks
|
||||||
val hash = argonBlake2bArbitraryLenghtHash(result, tagLength)
|
val hash = argonBlake2bArbitraryLenghtHash(acc, tagLength)
|
||||||
clearMatrix()
|
matrix.clearMatrix()
|
||||||
return hash
|
return hash
|
||||||
|
|
||||||
|
|
||||||
@ -403,13 +400,14 @@ class Argon2(
|
|||||||
column,
|
column,
|
||||||
addressBlock
|
addressBlock
|
||||||
)
|
)
|
||||||
matrix[lane][column] =
|
matrix.setBlockAt(lane, column,
|
||||||
compressionFunctionG(
|
compressionFunctionG(
|
||||||
matrix[lane][previousColumn],
|
matrix.getBlockAt(lane, previousColumn),
|
||||||
matrix[l][z],
|
matrix.getBlockAt(l,z),
|
||||||
matrix[lane][column],
|
matrix.getBlockAt(lane,column),
|
||||||
true
|
true
|
||||||
).toUByteArray()
|
).toUByteArray()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,21 +28,67 @@ package com.ionspin.kotlin.crypto.keyderivation.argon2
|
|||||||
internal val storage: UByteArray = UByteArray(columnCount * rowCount * 1024)
|
internal val storage: UByteArray = UByteArray(columnCount * rowCount * 1024)
|
||||||
|
|
||||||
operator fun get(rowPosition: Int, columnPosition: Int, inBlockPosition: Int) : UByte {
|
operator fun get(rowPosition: Int, columnPosition: Int, inBlockPosition: Int) : UByte {
|
||||||
return storage[rowPosition * (columnCount - 1) * 1024 + columnPosition * 1024 + inBlockPosition]
|
if (rowPosition > rowCount - 1) {
|
||||||
|
throw RuntimeException("Invalid row (lane) requested: $rowPosition, rowCount: $rowCount")
|
||||||
|
}
|
||||||
|
if (columnPosition > columnCount - 1) {
|
||||||
|
throw RuntimeException("Invalid column requested: $columnPosition, columnCount: $columnCount")
|
||||||
|
}
|
||||||
|
return storage[getBlockStartPosition(rowPosition, columnPosition) + inBlockPosition]
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun get(rowPosition: Int, columnPosition: Int) : UByteArray {
|
operator fun set(rowPosition: Int, columnPosition: Int, inBlockPosition: Int, value: UByte) {
|
||||||
println("Expensive.")
|
storage[getBlockStartPosition(rowPosition, columnPosition) + inBlockPosition] = value
|
||||||
return storage.copyOfRange(
|
}
|
||||||
rowPosition * (columnCount - 1) * 1024 + columnPosition * 1024,
|
|
||||||
rowPosition * (columnCount - 1) * 1024 + columnPosition * 1024 + 1024
|
fun getBlockStartAndEndPositions(rowPosition: Int, columnPosition: Int) : Pair<Int, Int> {
|
||||||
|
val start = getBlockStartPosition(rowPosition, columnPosition)
|
||||||
|
return Pair(
|
||||||
|
start,
|
||||||
|
start + 1024
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun get(rowPosition: Int) : Array<UByteArray> {
|
fun sliceArray(indices: IntRange): UByteArray {
|
||||||
return Array(columnCount) {
|
return storage.sliceArray(indices)
|
||||||
this.get(rowPosition, it)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
fun getBlockAt(rowPosition: Int, columnPosition: Int) : UByteArray {
|
||||||
|
println("Expensive get")
|
||||||
|
return storage.copyOfRange(
|
||||||
|
getBlockStartPosition(rowPosition, columnPosition),
|
||||||
|
getBlockStartPosition(rowPosition, columnPosition) + 1024
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setBlockAt(rowPosition: Int, columnPosition: Int, blockValue: UByteArray) {
|
||||||
|
println("Expensive set")
|
||||||
|
blockValue.copyInto(
|
||||||
|
storage,
|
||||||
|
getBlockStartPosition(rowPosition, columnPosition)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun getBlockStartPosition(rowPosition: Int, columnPosition: Int) : Int {
|
||||||
|
return rowPosition * columnCount * 1024 + columnPosition * 1024
|
||||||
|
}
|
||||||
|
|
||||||
|
// operator fun get(rowPosition: Int, columnPosition: Int) : UByteArray {
|
||||||
|
// println("Expensive.")
|
||||||
|
// return storage.copyOfRange(
|
||||||
|
// rowPosition * (columnCount - 1) * 1024 + columnPosition * 1024,
|
||||||
|
// rowPosition * (columnCount - 1) * 1024 + columnPosition * 1024 + 1024
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// operator fun get(rowPosition: Int) : Array<UByteArray> {
|
||||||
|
// return Array(columnCount) {
|
||||||
|
// this.get(rowPosition, it)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
|
internal fun clearMatrix() {
|
||||||
|
for( index in storage.indices) { storage[index] = 0U }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -36,7 +36,36 @@ class Argon2MatrixTest {
|
|||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun debugTest() {
|
fun indexAccessTest() {
|
||||||
|
val argon2Matrix = Argon2Matrix(2, 2)
|
||||||
|
(zeroesBlock + onesBlock + twosBlock + threesBlock).copyInto(argon2Matrix.storage)
|
||||||
|
println(argon2Matrix[0, 0, 0])
|
||||||
|
println(argon2Matrix[0, 1, 0])
|
||||||
|
println(argon2Matrix[1, 0, 0])
|
||||||
|
println(argon2Matrix[1, 1, 0])
|
||||||
|
// argon2Matrix.storage.hexColumsPrint(1024)
|
||||||
|
var expectedByteValue = 0U.toUByte()
|
||||||
|
for (lane in 0 until 2) {
|
||||||
|
for (column in 0 until 2) {
|
||||||
|
for (blockPosition in 0 until 1024) {
|
||||||
|
assertTrue {
|
||||||
|
argon2Matrix[lane, column, blockPosition] == expectedByteValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expectedByteValue++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue {
|
||||||
|
argon2Matrix[0, 0, 0] == 0U.toUByte() &&
|
||||||
|
argon2Matrix[0, 1, 0] == 1U.toUByte() &&
|
||||||
|
argon2Matrix[1, 0, 0] == 2U.toUByte() &&
|
||||||
|
argon2Matrix[1, 1, 0] == 3U.toUByte()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun blockRetrievalTest() {
|
||||||
val argon2Matrix = Argon2Matrix(2, 2)
|
val argon2Matrix = Argon2Matrix(2, 2)
|
||||||
(zeroesBlock + onesBlock + twosBlock + threesBlock).copyInto(argon2Matrix.storage)
|
(zeroesBlock + onesBlock + twosBlock + threesBlock).copyInto(argon2Matrix.storage)
|
||||||
println(argon2Matrix[0, 0, 0])
|
println(argon2Matrix[0, 0, 0])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user