Add key derivation interface
This commit is contained in:
parent
2bc3051748
commit
13ebfa8be9
@ -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>
|
||||
}
|
@ -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],
|
||||
|
@ -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 ,
|
||||
|
Loading…
x
Reference in New Issue
Block a user