Add key derivation interface

This commit is contained in:
Ugljesa Jovanovic 2020-05-16 19:02:08 +02:00 committed by Ugljesa Jovanovic
parent 2bc3051748
commit 13ebfa8be9
No known key found for this signature in database
GPG Key ID: 178E6DFCECCB0E0F
3 changed files with 53 additions and 39 deletions

View File

@ -0,0 +1,26 @@
/*
* Copyright 2019 Ugljesa Jovanovic
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ionspin.kotlin.crypto.keyderivation
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 16-May-2020
*/
interface KeyDerivationFunction {
fun derive() : Array<UByte>
}

View File

@ -20,6 +20,7 @@ package com.ionspin.kotlin.crypto.keyderivation.argon2
import com.ionspin.kotlin.bignum.integer.toBigInteger
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b
import com.ionspin.kotlin.crypto.keyderivation.KeyDerivationFunction
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.argonBlake2bArbitraryLenghtHash
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.compressionFunctionG
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.validateArgonParameters
@ -44,16 +45,16 @@ data class SegmentPosition(
)
class Argon2(
val password: Array<UByte>,
val salt: Array<UByte> = emptyArray(),
val parallelism: Int = 1,
val tagLength: UInt = 64U,
private val password: Array<UByte>,
private val salt: Array<UByte> = emptyArray(),
private val parallelism: Int = 1,
private val tagLength: UInt = 64U,
requestedMemorySize: UInt = 0U,
val numberOfIterations: UInt = 1U,
val key: Array<UByte> = emptyArray(),
val associatedData: Array<UByte> = emptyArray(),
val argonType: ArgonType = ArgonType.Argon2id
) {
private val numberOfIterations: UInt = 1U,
private val key: Array<UByte> = emptyArray(),
private val associatedData: Array<UByte> = emptyArray(),
private val argonType: ArgonType = ArgonType.Argon2id
) : KeyDerivationFunction {
init {
validateArgonParameters(
password,
@ -68,23 +69,23 @@ class Argon2(
)
}
//We support only the latest version
val versionNumber: UInt = 0x13U
private val versionNumber: UInt = 0x13U
//Use either requested memory size, or default, or throw exception if the requested amount is less than 8*parallelism
val memorySize = if (requestedMemorySize == 0U) {
private val memorySize = if (requestedMemorySize == 0U) {
((8 * parallelism) * 2).toUInt()
} else {
requestedMemorySize
}
val blockCount = (memorySize / (4U * parallelism.toUInt())) * (4U * parallelism.toUInt())
val columnCount = (blockCount / parallelism.toUInt()).toInt()
val segmentLength = columnCount / 4
private val blockCount = (memorySize / (4U * parallelism.toUInt())) * (4U * parallelism.toUInt())
private val columnCount = (blockCount / parallelism.toUInt()).toInt()
private val segmentLength = columnCount / 4
val useIndependentAddressing = argonType == ArgonType.Argon2id || argonType == ArgonType.Argon2i
private val useIndependentAddressing = argonType == ArgonType.Argon2id || argonType == ArgonType.Argon2i
// State
val matrix = Array(parallelism) {
private val matrix = Array(parallelism) {
Array(columnCount) {
Array<UByte>(1024) { 0U }
}
@ -225,7 +226,7 @@ class Argon2(
return Pair(l, absolutePosition)
}
fun derive(): Array<UByte> {
override fun derive(): Array<UByte> {
val h0 = Blake2b.digest(
parallelism.toUInt()
.toLittleEndianUByteArray() + tagLength.toLittleEndianUByteArray() + memorySize.toLittleEndianUByteArray() +
@ -266,33 +267,25 @@ class Argon2(
}
}
//Hash the xored last blocks
println("Tag:")
val hash = argonBlake2bArbitraryLenghtHash(result, tagLength)
clearMatrix()
return hash
}
fun executeArgonWithSingleThread() {
private fun executeArgonWithSingleThread() {
for (iteration in 0 until numberOfIterations.toInt()) {
for (slice in 0 until 4) {
for (lane in 0 until parallelism.toInt()) {
println("Processing segment I: $iteration, S: $slice, L: $lane")
for (lane in 0 until parallelism) {
val segmentPosition = SegmentPosition(iteration, lane, slice)
processSegment(segmentPosition)
}
}
//Debug prints
// println("Done with $iteration")
// matrix[0][0].slice(0..7).toTypedArray().hexColumsPrint(8)
// matrix[parallelism.toInt() - 1][columnCount - 1].slice(
// 1016..1023
// ).toTypedArray().hexColumsPrint(8)
}
}
fun processSegment(segmentPosition: SegmentPosition) {
private fun processSegment(segmentPosition: SegmentPosition) {
val iteration = segmentPosition.iteration
val slice = segmentPosition.slice
val lane = segmentPosition.lane
@ -308,7 +301,6 @@ class Argon2(
addressBlock = populateAddressBlock(iteration, slice, lane, addressBlock, addressCounter)
addressCounter++
}
val startColumn = if (iteration == 0 && slice == 0) {
2
} else {
@ -327,9 +319,6 @@ class Argon2(
} else {
column - 1
}
if (iteration == 1) {
println("Breakpoint")
}
val (l, z) = computeReferenceBlockIndexes(
iteration,
slice,
@ -337,7 +326,6 @@ class Argon2(
column,
addressBlock
)
// println("Calling compress for I: $iteration S: $slice Lane: $lane Column: $column with l: $l z: $z")
matrix[lane][column] =
compressionFunctionG(
matrix[lane][previousColumn],

View File

@ -34,7 +34,7 @@ object Argon2Utils {
const val R4 = 63
//based on Blake2b mixRound
internal inline fun mixRound(input: Array<UByte>): Array<ULong> {
private fun mixRound(input: Array<UByte>): Array<ULong> {
var v = input.chunked(8).map { it.fromLittleEndianArrayToULong() }.toTypedArray()
v = mix(v, 0, 4, 8, 12)
v = mix(v, 1, 5, 9, 13)
@ -48,7 +48,7 @@ object Argon2Utils {
}
//Based on Blake2b mix
private inline fun mix(v: Array<ULong>, a: Int, b: Int, c: Int, d: Int): Array<ULong> {
private fun mix(v: Array<ULong>, a: Int, b: Int, c: Int, d: Int): Array<ULong> {
v[a] = (v[a] + v[b] + 2U * (v[a] and 0xFFFFFFFFUL) * (v[b] and 0xFFFFFFFFUL))
v[d] = (v[d] xor v[a]) rotateRight R1
v[c] = (v[c] + v[d] + 2U * (v[c] and 0xFFFFFFFFUL) * (v[d] and 0xFFFFFFFFUL))
@ -76,7 +76,7 @@ object Argon2Utils {
}
}
fun compressionFunctionG(
internal fun compressionFunctionG(
previousBlock: Array<UByte>,
referenceBlock: Array<UByte>,
currentBlock: Array<UByte>,
@ -115,7 +115,7 @@ object Argon2Utils {
return final
}
fun argonBlake2bArbitraryLenghtHash(input: Array<UByte>, length: UInt): Array<UByte> {
internal fun argonBlake2bArbitraryLenghtHash(input: Array<UByte>, length: UInt): Array<UByte> {
if (length <= 64U) {
return Blake2b.digest(inputMessage = length + input, hashLength = length.toInt())
}
@ -142,7 +142,7 @@ object Argon2Utils {
* sizes for password, salt, key and associated data. Also since UInt is 32bit we cant set more than 2^32-1 of
* tagLength, requested memory size and number of iterations, so no need to check for upper bound, just lower.
*/
fun validateArgonParameters(
internal fun validateArgonParameters(
password: Array<UByte>,
salt: Array<UByte>,
parallelism: Int ,