Continued Argon2 implementation
This commit is contained in:
parent
decc1ab91f
commit
d22f5b73f7
@ -44,6 +44,12 @@ It's not peer reviewed, not guaranteed to be bug free, and not guaranteed to be
|
|||||||
* AES
|
* AES
|
||||||
* Modes: CBC, CTR
|
* Modes: CBC, CTR
|
||||||
|
|
||||||
|
## Key Derivation
|
||||||
|
|
||||||
|
* Argon2
|
||||||
|
|
||||||
|
## AEAD
|
||||||
|
|
||||||
More to come.
|
More to come.
|
||||||
|
|
||||||
## Integration
|
## Integration
|
||||||
|
@ -16,14 +16,21 @@
|
|||||||
|
|
||||||
package com.ionspin.kotlin.crypto.keyderivation
|
package com.ionspin.kotlin.crypto.keyderivation
|
||||||
|
|
||||||
import com.ionspin.kotlin.crypto.chunked
|
|
||||||
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b
|
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b
|
||||||
import com.ionspin.kotlin.crypto.plus
|
import com.ionspin.kotlin.crypto.plus
|
||||||
|
import com.ionspin.kotlin.crypto.toLittleEndianUByteArray
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 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
|
||||||
|
*
|
||||||
* 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(
|
||||||
@ -35,15 +42,17 @@ class Argon2 internal constructor(
|
|||||||
val numberOfIterations: UInt,
|
val numberOfIterations: UInt,
|
||||||
val versionNumber: UInt,
|
val versionNumber: UInt,
|
||||||
val key: Array<UByte>,
|
val key: Array<UByte>,
|
||||||
|
associatedData: Array<UByte>
|
||||||
val type: ArgonType
|
val type: ArgonType
|
||||||
) {
|
) {
|
||||||
enum class ArgonType {
|
enum class ArgonType {
|
||||||
Argon2i, Argon2d, Argon2id
|
Argon2i, Argon2d, Argon2id
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
|
||||||
fun hash(input : Array<UByte>, length : UInt) : Array<UByte> {
|
fun argonHash(input: Array<UByte>, length: UInt): Array<UByte> {
|
||||||
if (length <= 64U) {
|
if (length <= 64U) {
|
||||||
return Blake2b.digest(length + input)
|
return Blake2b.digest(length + input)
|
||||||
}
|
}
|
||||||
@ -55,8 +64,96 @@ class Argon2 internal constructor(
|
|||||||
v[i] = Blake2b.digest(v[i - 1])
|
v[i] = Blake2b.digest(v[i - 1])
|
||||||
}
|
}
|
||||||
val remainingPartOfInput = input.copyOfRange(input.size - numberOfBlocks * 32, input.size)
|
val remainingPartOfInput = input.copyOfRange(input.size - numberOfBlocks * 32, input.size)
|
||||||
v[numberOfBlocks] = Blake2b.digest(remainingPartOfInput, hashLength = remainingPartOfInput.size)
|
val vLast = Blake2b.digest(remainingPartOfInput, hashLength = remainingPartOfInput.size)
|
||||||
v.chunked(8)
|
val concat =
|
||||||
|
(v.map { it.copyOfRange(0, 32) })
|
||||||
|
.plus(listOf(vLast))
|
||||||
|
.foldRight(emptyArray<UByte>()) { arrayOfUBytes, acc -> arrayOfUBytes + acc }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return concat
|
||||||
|
}
|
||||||
|
|
||||||
|
fun compressionFunctionG(x : Array<UByte>, y : Array<UByte>) : Array<Array<Array<UByte>>> {
|
||||||
|
val r = Array<UByte>(1024) { 0U }
|
||||||
|
x.forEachIndexed { index, it -> r[index] = it xor y[index] }
|
||||||
|
// mix rounds
|
||||||
|
return emptyArray() // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------- Unmodified blake2b mixing
|
||||||
|
/*
|
||||||
|
internal fun mixRound(input: Array<ULong>, message: Array<ULong>, round: Int): Array<ULong> {
|
||||||
|
var v = input
|
||||||
|
val selectedSigma = sigma[round % 10]
|
||||||
|
v = mix(v, 0, 4, 8, 12, message[selectedSigma[0]], message[selectedSigma[1]])
|
||||||
|
v = mix(v, 1, 5, 9, 13, message[selectedSigma[2]], message[selectedSigma[3]])
|
||||||
|
v = mix(v, 2, 6, 10, 14, message[selectedSigma[4]], message[selectedSigma[5]])
|
||||||
|
v = mix(v, 3, 7, 11, 15, message[selectedSigma[6]], message[selectedSigma[7]])
|
||||||
|
v = mix(v, 0, 5, 10, 15, message[selectedSigma[8]], message[selectedSigma[9]])
|
||||||
|
v = mix(v, 1, 6, 11, 12, message[selectedSigma[10]], message[selectedSigma[11]])
|
||||||
|
v = mix(v, 2, 7, 8, 13, message[selectedSigma[12]], message[selectedSigma[13]])
|
||||||
|
v = mix(v, 3, 4, 9, 14, message[selectedSigma[14]], message[selectedSigma[15]])
|
||||||
|
return v
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun mix(v: Array<ULong>, a: Int, b: Int, c: Int, d: Int, x: ULong, y: ULong): Array<ULong> {
|
||||||
|
v[a] = (v[a] + v[b] + x)
|
||||||
|
v[d] = (v[d] xor v[a]) rotateRight R1
|
||||||
|
v[c] = (v[c] + v[d])
|
||||||
|
v[b] = (v[b] xor v[c]) rotateRight R2
|
||||||
|
v[a] = (v[a] + v[b] + y)
|
||||||
|
v[d] = (v[d] xor v[a]) rotateRight R3
|
||||||
|
v[c] = (v[c] + v[d])
|
||||||
|
v[b] = (v[b] xor v[c]) rotateRight R4
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
internal fun derive(
|
||||||
|
password: Array<UByte>,
|
||||||
|
salt: Array<UByte>,
|
||||||
|
parallelism: UInt,
|
||||||
|
tagLength: UInt,
|
||||||
|
memorySize: UInt,
|
||||||
|
numberOfIterations: UInt,
|
||||||
|
versionNumber: UInt,
|
||||||
|
key: Array<UByte>,
|
||||||
|
associatedData: Array<UByte>,
|
||||||
|
type: ArgonType
|
||||||
|
): Array<UByte> {
|
||||||
|
val h0 = Blake2b.digest(
|
||||||
|
parallelism.toLittleEndianUByteArray() + tagLength.toLittleEndianUByteArray() + memorySize.toLittleEndianUByteArray() +
|
||||||
|
numberOfIterations.toLittleEndianUByteArray() + versionNumber.toLittleEndianUByteArray() +
|
||||||
|
password.size.toUInt().toLittleEndianUByteArray() + password +
|
||||||
|
salt.size.toUInt().toLittleEndianUByteArray() + salt +
|
||||||
|
key.size.toUInt().toLittleEndianUByteArray() + key +
|
||||||
|
associatedData.size.toUInt().toLittleEndianUByteArray() + associatedData
|
||||||
|
)
|
||||||
|
|
||||||
|
val blockCount = (memorySize / (4U * parallelism)) * (4U * parallelism) //
|
||||||
|
val columnCount = blockCount / parallelism
|
||||||
|
|
||||||
|
//Allocate memory as Array of parallelism rows and columnCount colums
|
||||||
|
val matrix = Array(parallelism.toInt()) {
|
||||||
|
Array(columnCount.toInt()) {
|
||||||
|
Array<UByte>(1024) { 0U }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Compute B[i][0]
|
||||||
|
for (i in 0..parallelism.toInt()) {
|
||||||
|
matrix[i][0] =
|
||||||
|
argonHash(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -66,9 +163,4 @@ class Argon2 internal constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user