First steps
This commit is contained in:
1 parent
aecad37e64
commit
9858eaa5fb
52 files changed
+5088
-526
No files matched your search
@@ -186,6 +186,7 @@ kotlin {
|
||||
implementation(kotlin(Deps.Common.test))
|
||||
implementation(Deps.Common.coroutines)
|
||||
implementation(Deps.Common.kotlinBigNum)
|
||||
implementation(project(":multiplatform-crypto-api"))
|
||||
}
|
||||
}
|
||||
val commonTest by getting {
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.ionspin.kotlin.crypto
|
||||
|
||||
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bPure
|
||||
import com.ionspin.kotlin.crypto.hash.sha.Sha256Pure
|
||||
import com.ionspin.kotlin.crypto.hash.sha.Sha512Pure
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 24-May-2020
|
||||
*/
|
||||
typealias Blake2bStateless = Blake2bPure.Companion
|
||||
typealias Sha256Stateless = Sha256Pure.Companion
|
||||
typealias Sha512Stateless = Sha512Pure.Companion
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* 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.hash
|
||||
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 20-Jul-2019
|
||||
*/
|
||||
interface Hash {
|
||||
val MAX_HASH_BYTES : Int
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
interface UpdatableHash : Hash {
|
||||
fun update(data : UByteArray)
|
||||
|
||||
fun update(data : String)
|
||||
|
||||
fun digest() : UByteArray
|
||||
|
||||
fun digestString() : String
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
interface StatelessHash : Hash {
|
||||
fun digest(inputString: String, key: String? = null, hashLength: Int = MAX_HASH_BYTES): UByteArray
|
||||
|
||||
fun digest(
|
||||
inputMessage: UByteArray = ubyteArrayOf(),
|
||||
key: UByteArray = ubyteArrayOf(),
|
||||
hashLength: Int = MAX_HASH_BYTES
|
||||
): UByteArray
|
||||
}
|
||||
|
||||
+3
-6
@@ -19,9 +19,6 @@ package com.ionspin.kotlin.crypto.hash.blake2b
|
||||
import com.ionspin.kotlin.bignum.integer.BigInteger
|
||||
import com.ionspin.kotlin.bignum.integer.toBigInteger
|
||||
import com.ionspin.kotlin.crypto.*
|
||||
import com.ionspin.kotlin.crypto.hash.StatelessHash
|
||||
import com.ionspin.kotlin.crypto.hash.UpdatableHash
|
||||
import com.ionspin.kotlin.crypto.util.chunked
|
||||
import com.ionspin.kotlin.crypto.util.rotateRight
|
||||
|
||||
/**
|
||||
@@ -31,9 +28,9 @@ import com.ionspin.kotlin.crypto.util.rotateRight
|
||||
*/
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
class Blake2b(val key: UByteArray? = null, val hashLength: Int = 64) : UpdatableHash {
|
||||
class Blake2bPure(val key: UByteArray? = null, val hashLength: Int = 64) : Blake2b {
|
||||
|
||||
companion object : StatelessHash {
|
||||
companion object : Blake2bStatelessInterface {
|
||||
//Hack start
|
||||
//If this line is not included konanc 1.4-M1 fails to link because it cant find ByteArray which is
|
||||
//a backing class for UByteArray
|
||||
@@ -255,7 +252,7 @@ class Blake2b(val key: UByteArray? = null, val hashLength: Int = 64) : Updatable
|
||||
requestedHashLenght
|
||||
)
|
||||
|
||||
override val MAX_HASH_BYTES: Int = Blake2b.MAX_HASH_BYTES
|
||||
override val MAX_HASH_BYTES: Int = Blake2bPure.MAX_HASH_BYTES
|
||||
|
||||
var h = iv.copyOf()
|
||||
var counter = BigInteger.ZERO
|
||||
+2
-3
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.ionspin.kotlin.crypto.hash.sha
|
||||
|
||||
import com.ionspin.kotlin.crypto.util.chunked
|
||||
import com.ionspin.kotlin.crypto.hash.StatelessHash
|
||||
import com.ionspin.kotlin.crypto.hash.UpdatableHash
|
||||
import com.ionspin.kotlin.crypto.util.rotateRight
|
||||
@@ -30,12 +29,12 @@ import com.ionspin.kotlin.crypto.util.rotateRight
|
||||
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
class Sha256 : UpdatableHash {
|
||||
class Sha256Pure : Sha256 {
|
||||
|
||||
override val MAX_HASH_BYTES: Int = 32
|
||||
|
||||
|
||||
companion object : StatelessHash {
|
||||
companion object : StatelessSha256 {
|
||||
const val BLOCK_SIZE = 512
|
||||
const val BLOCK_SIZE_IN_BYTES = 64
|
||||
const val UINT_MASK = 0xFFFFFFFFU
|
||||
+2
-3
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.ionspin.kotlin.crypto.hash.sha
|
||||
|
||||
import com.ionspin.kotlin.crypto.util.chunked
|
||||
import com.ionspin.kotlin.crypto.hash.StatelessHash
|
||||
import com.ionspin.kotlin.crypto.hash.UpdatableHash
|
||||
import com.ionspin.kotlin.crypto.util.rotateRight
|
||||
@@ -28,11 +27,11 @@ import com.ionspin.kotlin.crypto.util.rotateRight
|
||||
*/
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
class Sha512 : UpdatableHash {
|
||||
class Sha512Pure : Sha512 {
|
||||
|
||||
override val MAX_HASH_BYTES: Int = 32
|
||||
|
||||
companion object : StatelessHash {
|
||||
companion object : StatelessSha512 {
|
||||
const val BLOCK_SIZE = 1024
|
||||
const val BLOCK_SIZE_IN_BYTES = 128
|
||||
const val CHUNK_SIZE = 80
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* 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() : UByteArray
|
||||
}
|
||||
+2
-398
@@ -1,406 +1,10 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
|
||||
|
||||
package com.ionspin.kotlin.crypto.keyderivation.argon2
|
||||
|
||||
import com.ionspin.kotlin.bignum.integer.toBigInteger
|
||||
import com.ionspin.kotlin.crypto.SRNG
|
||||
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
|
||||
import com.ionspin.kotlin.crypto.util.*
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 16-May-2020
|
||||
* on 24-May-2020
|
||||
*/
|
||||
|
||||
enum class ArgonType(val typeId: Int) {
|
||||
Argon2d(0), Argon2i(1), Argon2id(2)
|
||||
}
|
||||
|
||||
data class SegmentPosition(
|
||||
val iteration: Int,
|
||||
val lane: Int,
|
||||
val slice: Int
|
||||
)
|
||||
|
||||
data class ArgonResult(
|
||||
val hashBytes: UByteArray,
|
||||
val salt: UByteArray
|
||||
) {
|
||||
val hashString by lazy { hashBytes.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "") }
|
||||
val saltString by lazy { salt.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "") }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
class Argon2(
|
||||
private val password: UByteArray,
|
||||
private val salt: UByteArray = ubyteArrayOf(),
|
||||
private val parallelism: Int = 1,
|
||||
private val tagLength: UInt = 64U,
|
||||
requestedMemorySize: UInt = 0U,
|
||||
private val numberOfIterations: Int = 1,
|
||||
private val key: UByteArray = ubyteArrayOf(),
|
||||
private val associatedData: UByteArray = ubyteArrayOf(),
|
||||
private val argonType: ArgonType = ArgonType.Argon2id
|
||||
) : KeyDerivationFunction {
|
||||
|
||||
companion object {
|
||||
fun derive(
|
||||
password: String,
|
||||
salt: String? = null,
|
||||
key: String,
|
||||
associatedData: String,
|
||||
parallelism: Int = 16,
|
||||
tagLength: Int = 64,
|
||||
memory: Int = 4096,
|
||||
numberOfIterations: Int = 10,
|
||||
): ArgonResult {
|
||||
val salt = SRNG.getRandomBytes(64)
|
||||
val argon = Argon2(
|
||||
password.encodeToByteArray().toUByteArray(),
|
||||
salt,
|
||||
parallelism,
|
||||
tagLength.toUInt(),
|
||||
memory.toUInt(),
|
||||
numberOfIterations,
|
||||
key.encodeToByteArray().toUByteArray(),
|
||||
associatedData.encodeToByteArray().toUByteArray(),
|
||||
ArgonType.Argon2id
|
||||
)
|
||||
val resultArray = argon.derive()
|
||||
return ArgonResult(resultArray, salt)
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
password: String,
|
||||
salt: String = "",
|
||||
parallelism: Int = 1,
|
||||
tagLength: UInt = 64U,
|
||||
requestedMemorySize: UInt = 0U,
|
||||
numberOfIterations: Int = 10,
|
||||
key: String = "",
|
||||
associatedData: String = "",
|
||||
argonType: ArgonType = ArgonType.Argon2id
|
||||
) : this(
|
||||
password.encodeToByteArray().toUByteArray(),
|
||||
salt.encodeToByteArray().toUByteArray(),
|
||||
parallelism,
|
||||
tagLength,
|
||||
requestedMemorySize,
|
||||
numberOfIterations,
|
||||
key.encodeToByteArray().toUByteArray(),
|
||||
associatedData.encodeToByteArray().toUByteArray(),
|
||||
argonType
|
||||
)
|
||||
|
||||
//We support only the latest version
|
||||
private val versionNumber: UInt = 0x13U
|
||||
|
||||
//Use either requested memory size, or default, or throw exception if the requested amount is less than 8*parallelism
|
||||
private val memorySize = if (requestedMemorySize == 0U) {
|
||||
((8 * parallelism) * 2).toUInt()
|
||||
} else {
|
||||
requestedMemorySize
|
||||
}
|
||||
private val blockCount = (memorySize / (4U * parallelism.toUInt())) * (4U * parallelism.toUInt())
|
||||
private val columnCount = (blockCount / parallelism.toUInt()).toInt()
|
||||
private val segmentLength = columnCount / 4
|
||||
|
||||
private val useIndependentAddressing = argonType == ArgonType.Argon2id || argonType == ArgonType.Argon2i
|
||||
|
||||
// State
|
||||
private val matrix: ArgonMatrix
|
||||
|
||||
init {
|
||||
matrix = ArgonMatrix(columnCount, parallelism)
|
||||
validateArgonParameters(
|
||||
password,
|
||||
salt,
|
||||
parallelism,
|
||||
tagLength,
|
||||
requestedMemorySize,
|
||||
numberOfIterations,
|
||||
key,
|
||||
associatedData,
|
||||
argonType
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
private fun populateAddressBlock(
|
||||
iteration: Int,
|
||||
slice: Int,
|
||||
lane: Int,
|
||||
addressBlock: ArgonBlockPointer,
|
||||
addressCounter: ULong
|
||||
): ArgonBlockPointer {
|
||||
//Calculate first pass
|
||||
val zeroesBlock = ArgonBlock()
|
||||
val firstPass = compressionFunctionG(
|
||||
zeroesBlock.getBlockPointer(),
|
||||
ArgonBlock(iteration.toULong().toLittleEndianUByteArray() +
|
||||
lane.toULong().toLittleEndianUByteArray() +
|
||||
slice.toULong().toLittleEndianUByteArray() +
|
||||
blockCount.toULong().toLittleEndianUByteArray() +
|
||||
numberOfIterations.toULong().toLittleEndianUByteArray() +
|
||||
argonType.typeId.toULong().toLittleEndianUByteArray() +
|
||||
addressCounter.toLittleEndianUByteArray() +
|
||||
UByteArray(968) { 0U }
|
||||
).getBlockPointer(),
|
||||
addressBlock,
|
||||
false
|
||||
)
|
||||
val secondPass = compressionFunctionG(
|
||||
zeroesBlock.getBlockPointer(),
|
||||
firstPass,
|
||||
firstPass,
|
||||
false
|
||||
)
|
||||
return secondPass
|
||||
}
|
||||
|
||||
|
||||
private fun computeReferenceBlockIndexes(
|
||||
iteration: Int,
|
||||
slice: Int,
|
||||
lane: Int,
|
||||
column: Int,
|
||||
addressBlockPointer: ArgonBlockPointer?
|
||||
): Pair<Int, Int> {
|
||||
|
||||
val segmentIndex = (column % segmentLength)
|
||||
val independentIndex = segmentIndex % 128 // 128 is the number of addresses in address block
|
||||
val (j1, j2) = when (argonType) {
|
||||
ArgonType.Argon2d -> {
|
||||
val previousBlockStart = if (column == 0) {
|
||||
matrix.getBlockPointer(lane, columnCount - 1) //Get last block in the SAME lane
|
||||
} else {
|
||||
matrix.getBlockPointer(lane, column - 1)
|
||||
}
|
||||
val first32Bit = matrix.sliceArray(previousBlockStart.asInt() until previousBlockStart.asInt() + 4).fromLittleEndianArrayToUInt()
|
||||
val second32Bit = matrix.sliceArray(previousBlockStart.asInt() + 4 until previousBlockStart.asInt() + 8).fromLittleEndianArrayToUInt()
|
||||
|
||||
Pair(first32Bit, second32Bit)
|
||||
}
|
||||
ArgonType.Argon2i -> {
|
||||
val first32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8)
|
||||
val second32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8 + 4)
|
||||
Pair(first32Bit, second32Bit)
|
||||
}
|
||||
ArgonType.Argon2id -> {
|
||||
if (iteration == 0 && (slice == 0 || slice == 1)) {
|
||||
val first32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8)
|
||||
val second32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8 + 4)
|
||||
Pair(first32Bit, second32Bit)
|
||||
} else {
|
||||
val previousBlockStart = if (column == 0) {
|
||||
matrix.getBlockPointer(lane, columnCount - 1) //Get last block in the SAME lane
|
||||
} else {
|
||||
matrix.getBlockPointer(lane, column - 1)
|
||||
}
|
||||
val first32Bit = matrix.sliceArray(previousBlockStart.asInt() until previousBlockStart.asInt() + 4).fromLittleEndianArrayToUInt()
|
||||
val second32Bit = matrix.sliceArray(previousBlockStart.asInt() + 4 until previousBlockStart.asInt() + 8).fromLittleEndianArrayToUInt()
|
||||
Pair(first32Bit, second32Bit)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//If this is first iteration and first slice, block is taken from the current lane
|
||||
val l = if (iteration == 0 && slice == 0) {
|
||||
lane
|
||||
} else {
|
||||
(j2.toBigInteger() % parallelism).intValue()
|
||||
|
||||
}
|
||||
|
||||
|
||||
val referenceAreaSize = if (iteration == 0) {
|
||||
if (slice == 0) {
|
||||
//All indices except the previous
|
||||
segmentIndex - 1
|
||||
} else {
|
||||
if (lane == l) {
|
||||
//Same lane
|
||||
column - 1
|
||||
} else {
|
||||
slice * (columnCount / 4) + if (segmentIndex == 0) { // Check if column is first block of the SEGMENT
|
||||
-1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (lane == l) {
|
||||
columnCount - (columnCount / 4) + (segmentIndex - 1)
|
||||
} else {
|
||||
columnCount - (columnCount / 4) + if (segmentIndex == 0) {
|
||||
-1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val x = (j1.toULong() * j1) shr 32
|
||||
val y = (referenceAreaSize.toULong() * x) shr 32
|
||||
val z = referenceAreaSize.toULong() - 1U - y
|
||||
|
||||
val startPosition = if (iteration == 0) {
|
||||
0
|
||||
} else {
|
||||
if (slice == 3) {
|
||||
0
|
||||
} else {
|
||||
(slice + 1) * segmentLength
|
||||
}
|
||||
}
|
||||
val absolutePosition = (startPosition + z.toInt()) % columnCount
|
||||
|
||||
return Pair(l, absolutePosition)
|
||||
}
|
||||
|
||||
override fun derive(): UByteArray {
|
||||
val blakeInput = parallelism.toUInt().toLittleEndianUByteArray() +
|
||||
tagLength.toLittleEndianUByteArray() +
|
||||
memorySize.toLittleEndianUByteArray() +
|
||||
numberOfIterations.toUInt().toLittleEndianUByteArray() +
|
||||
versionNumber.toLittleEndianUByteArray() +
|
||||
argonType.typeId.toUInt().toLittleEndianUByteArray() +
|
||||
password.size.toUInt().toLittleEndianUByteArray() + password +
|
||||
salt.size.toUInt().toLittleEndianUByteArray() + salt +
|
||||
key.size.toUInt().toLittleEndianUByteArray() + key +
|
||||
associatedData.size.toUInt().toLittleEndianUByteArray() + associatedData
|
||||
val h0 = Blake2b.digest(
|
||||
blakeInput
|
||||
)
|
||||
|
||||
//Compute B[i][0]
|
||||
for (i in 0 until parallelism) {
|
||||
matrix.setBlockAt(i, 0,
|
||||
argonBlake2bArbitraryLenghtHash(
|
||||
(h0 + 0.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray()).toUByteArray(),
|
||||
1024U
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
//Compute B[i][1]
|
||||
for (i in 0 until parallelism) {
|
||||
matrix.setBlockAt(i, 1,
|
||||
argonBlake2bArbitraryLenghtHash(
|
||||
(h0 + 1.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray()).toUByteArray(),
|
||||
1024U
|
||||
)
|
||||
)
|
||||
}
|
||||
//Run all iterations over all lanes and all segments
|
||||
executeArgonWithSingleThread()
|
||||
|
||||
|
||||
val acc = ArgonBlock(matrix.getBlockAt(0, columnCount - 1))
|
||||
val accPointer = acc.getBlockPointer()
|
||||
for (i in 1 until parallelism) {
|
||||
accPointer.xorInplaceWith(matrix.getBlockPointer(i, columnCount - 1))
|
||||
}
|
||||
//Hash the xored last blocks
|
||||
val hash = argonBlake2bArbitraryLenghtHash(acc.storage, tagLength)
|
||||
matrix.clearMatrix()
|
||||
return hash
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fun executeArgonWithSingleThread() {
|
||||
for (iteration in 0 until numberOfIterations) {
|
||||
for (slice in 0 until 4) {
|
||||
for (lane in 0 until parallelism) {
|
||||
val segmentPosition = SegmentPosition(iteration, lane, slice)
|
||||
processSegment(segmentPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processSegment(segmentPosition: SegmentPosition) {
|
||||
val iteration = segmentPosition.iteration
|
||||
val slice = segmentPosition.slice
|
||||
val lane = segmentPosition.lane
|
||||
|
||||
var addressBlock: ArgonBlockPointer? = null
|
||||
var addressCounter = 1UL //Starts from 1 in each segment as defined by the spec
|
||||
|
||||
//Generate initial segment address block
|
||||
if (useIndependentAddressing) {
|
||||
addressBlock = ArgonBlock().getBlockPointer()
|
||||
addressBlock = populateAddressBlock(iteration, slice, lane, addressBlock, addressCounter)
|
||||
addressCounter++
|
||||
}
|
||||
val startColumn = if (iteration == 0 && slice == 0) {
|
||||
2
|
||||
} else {
|
||||
slice * segmentLength
|
||||
}
|
||||
|
||||
|
||||
for (column in startColumn until (slice + 1) * segmentLength) {
|
||||
val segmentIndex = column - (slice * segmentLength)
|
||||
//Each address block contains 128 addresses, and we use one per iteration,
|
||||
//so once we do 128 iterations we need to calculate a new address block
|
||||
if (useIndependentAddressing && segmentIndex != 0 && segmentIndex % 128 == 0) {
|
||||
addressBlock = populateAddressBlock(iteration, slice, lane, addressBlock!!, addressCounter)
|
||||
addressCounter++
|
||||
}
|
||||
val previousColumn = if (column == 0) {
|
||||
columnCount - 1
|
||||
} else {
|
||||
column - 1
|
||||
}
|
||||
val (l, z) = computeReferenceBlockIndexes(
|
||||
iteration,
|
||||
slice,
|
||||
lane,
|
||||
column,
|
||||
addressBlock
|
||||
)
|
||||
|
||||
matrix.setBlockAt(lane, column,
|
||||
compressionFunctionG(
|
||||
matrix.getBlockPointer(lane, previousColumn),
|
||||
matrix.getBlockPointer(l,z),
|
||||
matrix.getBlockPointer(lane,column),
|
||||
true
|
||||
).getAsUByteArray()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
interface Argon2 : KeyDerivationFunction
|
||||
+405
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
|
||||
|
||||
package com.ionspin.kotlin.crypto.keyderivation.argon2
|
||||
|
||||
import com.ionspin.kotlin.bignum.integer.toBigInteger
|
||||
import com.ionspin.kotlin.crypto.SRNG
|
||||
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bStateless
|
||||
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
|
||||
import com.ionspin.kotlin.crypto.util.*
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 16-May-2020
|
||||
*/
|
||||
|
||||
enum class ArgonType(val typeId: Int) {
|
||||
Argon2d(0), Argon2i(1), Argon2id(2)
|
||||
}
|
||||
|
||||
data class SegmentPosition(
|
||||
val iteration: Int,
|
||||
val lane: Int,
|
||||
val slice: Int
|
||||
)
|
||||
|
||||
data class ArgonResult(
|
||||
val hashBytes: UByteArray,
|
||||
val salt: UByteArray
|
||||
) {
|
||||
val hashString by lazy { hashBytes.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "") }
|
||||
val saltString by lazy { salt.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "") }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
class Argon2Pure(
|
||||
private val password: UByteArray,
|
||||
private val salt: UByteArray = ubyteArrayOf(),
|
||||
private val parallelism: Int = 1,
|
||||
private val tagLength: UInt = 64U,
|
||||
requestedMemorySize: UInt = 0U,
|
||||
private val numberOfIterations: Int = 1,
|
||||
private val key: UByteArray = ubyteArrayOf(),
|
||||
private val associatedData: UByteArray = ubyteArrayOf(),
|
||||
private val argonType: ArgonType = ArgonType.Argon2id
|
||||
) : Argon2 {
|
||||
|
||||
companion object {
|
||||
fun derive(
|
||||
password: String,
|
||||
salt: String? = null,
|
||||
key: String,
|
||||
associatedData: String,
|
||||
parallelism: Int = 16,
|
||||
tagLength: Int = 64,
|
||||
memory: Int = 4096,
|
||||
numberOfIterations: Int = 10,
|
||||
): ArgonResult {
|
||||
val salt = SRNG.getRandomBytes(64)
|
||||
val argon = Argon2Pure(
|
||||
password.encodeToByteArray().toUByteArray(),
|
||||
salt,
|
||||
parallelism,
|
||||
tagLength.toUInt(),
|
||||
memory.toUInt(),
|
||||
numberOfIterations,
|
||||
key.encodeToByteArray().toUByteArray(),
|
||||
associatedData.encodeToByteArray().toUByteArray(),
|
||||
ArgonType.Argon2id
|
||||
)
|
||||
val resultArray = argon.derive()
|
||||
return ArgonResult(resultArray, salt)
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
password: String,
|
||||
salt: String = "",
|
||||
parallelism: Int = 1,
|
||||
tagLength: UInt = 64U,
|
||||
requestedMemorySize: UInt = 0U,
|
||||
numberOfIterations: Int = 10,
|
||||
key: String = "",
|
||||
associatedData: String = "",
|
||||
argonType: ArgonType = ArgonType.Argon2id
|
||||
) : this(
|
||||
password.encodeToByteArray().toUByteArray(),
|
||||
salt.encodeToByteArray().toUByteArray(),
|
||||
parallelism,
|
||||
tagLength,
|
||||
requestedMemorySize,
|
||||
numberOfIterations,
|
||||
key.encodeToByteArray().toUByteArray(),
|
||||
associatedData.encodeToByteArray().toUByteArray(),
|
||||
argonType
|
||||
)
|
||||
|
||||
//We support only the latest version
|
||||
private val versionNumber: UInt = 0x13U
|
||||
|
||||
//Use either requested memory size, or default, or throw exception if the requested amount is less than 8*parallelism
|
||||
private val memorySize = if (requestedMemorySize == 0U) {
|
||||
((8 * parallelism) * 2).toUInt()
|
||||
} else {
|
||||
requestedMemorySize
|
||||
}
|
||||
private val blockCount = (memorySize / (4U * parallelism.toUInt())) * (4U * parallelism.toUInt())
|
||||
private val columnCount = (blockCount / parallelism.toUInt()).toInt()
|
||||
private val segmentLength = columnCount / 4
|
||||
|
||||
private val useIndependentAddressing = argonType == ArgonType.Argon2id || argonType == ArgonType.Argon2i
|
||||
|
||||
// State
|
||||
private val matrix: ArgonMatrix
|
||||
|
||||
init {
|
||||
matrix = ArgonMatrix(columnCount, parallelism)
|
||||
validateArgonParameters(
|
||||
password,
|
||||
salt,
|
||||
parallelism,
|
||||
tagLength,
|
||||
requestedMemorySize,
|
||||
numberOfIterations,
|
||||
key,
|
||||
associatedData,
|
||||
argonType
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
private fun populateAddressBlock(
|
||||
iteration: Int,
|
||||
slice: Int,
|
||||
lane: Int,
|
||||
addressBlock: ArgonBlockPointer,
|
||||
addressCounter: ULong
|
||||
): ArgonBlockPointer {
|
||||
//Calculate first pass
|
||||
val zeroesBlock = ArgonBlock()
|
||||
val firstPass = compressionFunctionG(
|
||||
zeroesBlock.getBlockPointer(),
|
||||
ArgonBlock(iteration.toULong().toLittleEndianUByteArray() +
|
||||
lane.toULong().toLittleEndianUByteArray() +
|
||||
slice.toULong().toLittleEndianUByteArray() +
|
||||
blockCount.toULong().toLittleEndianUByteArray() +
|
||||
numberOfIterations.toULong().toLittleEndianUByteArray() +
|
||||
argonType.typeId.toULong().toLittleEndianUByteArray() +
|
||||
addressCounter.toLittleEndianUByteArray() +
|
||||
UByteArray(968) { 0U }
|
||||
).getBlockPointer(),
|
||||
addressBlock,
|
||||
false
|
||||
)
|
||||
val secondPass = compressionFunctionG(
|
||||
zeroesBlock.getBlockPointer(),
|
||||
firstPass,
|
||||
firstPass,
|
||||
false
|
||||
)
|
||||
return secondPass
|
||||
}
|
||||
|
||||
|
||||
private fun computeReferenceBlockIndexes(
|
||||
iteration: Int,
|
||||
slice: Int,
|
||||
lane: Int,
|
||||
column: Int,
|
||||
addressBlockPointer: ArgonBlockPointer?
|
||||
): Pair<Int, Int> {
|
||||
|
||||
val segmentIndex = (column % segmentLength)
|
||||
val independentIndex = segmentIndex % 128 // 128 is the number of addresses in address block
|
||||
val (j1, j2) = when (argonType) {
|
||||
ArgonType.Argon2d -> {
|
||||
val previousBlockStart = if (column == 0) {
|
||||
matrix.getBlockPointer(lane, columnCount - 1) //Get last block in the SAME lane
|
||||
} else {
|
||||
matrix.getBlockPointer(lane, column - 1)
|
||||
}
|
||||
val first32Bit = matrix.sliceArray(previousBlockStart.asInt() until previousBlockStart.asInt() + 4).fromLittleEndianArrayToUInt()
|
||||
val second32Bit = matrix.sliceArray(previousBlockStart.asInt() + 4 until previousBlockStart.asInt() + 8).fromLittleEndianArrayToUInt()
|
||||
|
||||
Pair(first32Bit, second32Bit)
|
||||
}
|
||||
ArgonType.Argon2i -> {
|
||||
val first32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8)
|
||||
val second32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8 + 4)
|
||||
Pair(first32Bit, second32Bit)
|
||||
}
|
||||
ArgonType.Argon2id -> {
|
||||
if (iteration == 0 && (slice == 0 || slice == 1)) {
|
||||
val first32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8)
|
||||
val second32Bit = addressBlockPointer!!.getUIntFromPosition(independentIndex * 8 + 4)
|
||||
Pair(first32Bit, second32Bit)
|
||||
} else {
|
||||
val previousBlockStart = if (column == 0) {
|
||||
matrix.getBlockPointer(lane, columnCount - 1) //Get last block in the SAME lane
|
||||
} else {
|
||||
matrix.getBlockPointer(lane, column - 1)
|
||||
}
|
||||
val first32Bit = matrix.sliceArray(previousBlockStart.asInt() until previousBlockStart.asInt() + 4).fromLittleEndianArrayToUInt()
|
||||
val second32Bit = matrix.sliceArray(previousBlockStart.asInt() + 4 until previousBlockStart.asInt() + 8).fromLittleEndianArrayToUInt()
|
||||
Pair(first32Bit, second32Bit)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//If this is first iteration and first slice, block is taken from the current lane
|
||||
val l = if (iteration == 0 && slice == 0) {
|
||||
lane
|
||||
} else {
|
||||
(j2.toBigInteger() % parallelism).intValue()
|
||||
|
||||
}
|
||||
|
||||
|
||||
val referenceAreaSize = if (iteration == 0) {
|
||||
if (slice == 0) {
|
||||
//All indices except the previous
|
||||
segmentIndex - 1
|
||||
} else {
|
||||
if (lane == l) {
|
||||
//Same lane
|
||||
column - 1
|
||||
} else {
|
||||
slice * (columnCount / 4) + if (segmentIndex == 0) { // Check if column is first block of the SEGMENT
|
||||
-1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (lane == l) {
|
||||
columnCount - (columnCount / 4) + (segmentIndex - 1)
|
||||
} else {
|
||||
columnCount - (columnCount / 4) + if (segmentIndex == 0) {
|
||||
-1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val x = (j1.toULong() * j1) shr 32
|
||||
val y = (referenceAreaSize.toULong() * x) shr 32
|
||||
val z = referenceAreaSize.toULong() - 1U - y
|
||||
|
||||
val startPosition = if (iteration == 0) {
|
||||
0
|
||||
} else {
|
||||
if (slice == 3) {
|
||||
0
|
||||
} else {
|
||||
(slice + 1) * segmentLength
|
||||
}
|
||||
}
|
||||
val absolutePosition = (startPosition + z.toInt()) % columnCount
|
||||
|
||||
return Pair(l, absolutePosition)
|
||||
}
|
||||
|
||||
override fun derive(): UByteArray {
|
||||
val blakeInput = parallelism.toUInt().toLittleEndianUByteArray() +
|
||||
tagLength.toLittleEndianUByteArray() +
|
||||
memorySize.toLittleEndianUByteArray() +
|
||||
numberOfIterations.toUInt().toLittleEndianUByteArray() +
|
||||
versionNumber.toLittleEndianUByteArray() +
|
||||
argonType.typeId.toUInt().toLittleEndianUByteArray() +
|
||||
password.size.toUInt().toLittleEndianUByteArray() + password +
|
||||
salt.size.toUInt().toLittleEndianUByteArray() + salt +
|
||||
key.size.toUInt().toLittleEndianUByteArray() + key +
|
||||
associatedData.size.toUInt().toLittleEndianUByteArray() + associatedData
|
||||
val h0 = Blake2bStateless.digest(
|
||||
blakeInput
|
||||
)
|
||||
|
||||
//Compute B[i][0]
|
||||
for (i in 0 until parallelism) {
|
||||
matrix.setBlockAt(i, 0,
|
||||
argonBlake2bArbitraryLenghtHash(
|
||||
(h0 + 0.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray()).toUByteArray(),
|
||||
1024U
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
//Compute B[i][1]
|
||||
for (i in 0 until parallelism) {
|
||||
matrix.setBlockAt(i, 1,
|
||||
argonBlake2bArbitraryLenghtHash(
|
||||
(h0 + 1.toUInt().toLittleEndianUByteArray() + i.toUInt().toLittleEndianUByteArray()).toUByteArray(),
|
||||
1024U
|
||||
)
|
||||
)
|
||||
}
|
||||
//Run all iterations over all lanes and all segments
|
||||
executeArgonWithSingleThread()
|
||||
|
||||
|
||||
val acc = ArgonBlock(matrix.getBlockAt(0, columnCount - 1))
|
||||
val accPointer = acc.getBlockPointer()
|
||||
for (i in 1 until parallelism) {
|
||||
accPointer.xorInplaceWith(matrix.getBlockPointer(i, columnCount - 1))
|
||||
}
|
||||
//Hash the xored last blocks
|
||||
val hash = argonBlake2bArbitraryLenghtHash(acc.storage, tagLength)
|
||||
matrix.clearMatrix()
|
||||
return hash
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fun executeArgonWithSingleThread() {
|
||||
for (iteration in 0 until numberOfIterations) {
|
||||
for (slice in 0 until 4) {
|
||||
for (lane in 0 until parallelism) {
|
||||
val segmentPosition = SegmentPosition(iteration, lane, slice)
|
||||
processSegment(segmentPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processSegment(segmentPosition: SegmentPosition) {
|
||||
val iteration = segmentPosition.iteration
|
||||
val slice = segmentPosition.slice
|
||||
val lane = segmentPosition.lane
|
||||
|
||||
var addressBlock: ArgonBlockPointer? = null
|
||||
var addressCounter = 1UL //Starts from 1 in each segment as defined by the spec
|
||||
|
||||
//Generate initial segment address block
|
||||
if (useIndependentAddressing) {
|
||||
addressBlock = ArgonBlock().getBlockPointer()
|
||||
addressBlock = populateAddressBlock(iteration, slice, lane, addressBlock, addressCounter)
|
||||
addressCounter++
|
||||
}
|
||||
val startColumn = if (iteration == 0 && slice == 0) {
|
||||
2
|
||||
} else {
|
||||
slice * segmentLength
|
||||
}
|
||||
|
||||
|
||||
for (column in startColumn until (slice + 1) * segmentLength) {
|
||||
val segmentIndex = column - (slice * segmentLength)
|
||||
//Each address block contains 128 addresses, and we use one per iteration,
|
||||
//so once we do 128 iterations we need to calculate a new address block
|
||||
if (useIndependentAddressing && segmentIndex != 0 && segmentIndex % 128 == 0) {
|
||||
addressBlock = populateAddressBlock(iteration, slice, lane, addressBlock!!, addressCounter)
|
||||
addressCounter++
|
||||
}
|
||||
val previousColumn = if (column == 0) {
|
||||
columnCount - 1
|
||||
} else {
|
||||
column - 1
|
||||
}
|
||||
val (l, z) = computeReferenceBlockIndexes(
|
||||
iteration,
|
||||
slice,
|
||||
lane,
|
||||
column,
|
||||
addressBlock
|
||||
)
|
||||
|
||||
matrix.setBlockAt(lane, column,
|
||||
compressionFunctionG(
|
||||
matrix.getBlockPointer(lane, previousColumn),
|
||||
matrix.getBlockPointer(l,z),
|
||||
matrix.getBlockPointer(lane,column),
|
||||
true
|
||||
).getAsUByteArray()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+5
-7
@@ -18,10 +18,8 @@
|
||||
|
||||
package com.ionspin.kotlin.crypto.keyderivation.argon2
|
||||
|
||||
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b
|
||||
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bPure
|
||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.BLOCK_SIZE
|
||||
import com.ionspin.kotlin.crypto.util.arrayChunked
|
||||
import com.ionspin.kotlin.crypto.util.fromLittleEndianArrayToULong
|
||||
import com.ionspin.kotlin.crypto.util.plus
|
||||
import com.ionspin.kotlin.crypto.util.rotateRight
|
||||
|
||||
@@ -101,17 +99,17 @@ object Argon2Utils {
|
||||
|
||||
internal fun argonBlake2bArbitraryLenghtHash(input: UByteArray, length: UInt): UByteArray {
|
||||
if (length <= 64U) {
|
||||
return Blake2b.digest(inputMessage = length + input, hashLength = length.toInt())
|
||||
return Blake2bPure.digest(inputMessage = length + input, hashLength = length.toInt())
|
||||
}
|
||||
//We can cast to int because UInt even if MAX_VALUE divided by 32 is guaranteed not to overflow
|
||||
val numberOf64ByteBlocks = (1U + ((length - 1U) / 32U) - 2U).toInt() // equivalent to ceil(length/32) - 2
|
||||
val v = Array<UByteArray>(numberOf64ByteBlocks) { ubyteArrayOf() }
|
||||
v[0] = Blake2b.digest(length + input)
|
||||
v[0] = Blake2bPure.digest(length + input)
|
||||
for (i in 1 until numberOf64ByteBlocks) {
|
||||
v[i] = Blake2b.digest(v[i - 1])
|
||||
v[i] = Blake2bPure.digest(v[i - 1])
|
||||
}
|
||||
val remainingPartOfInput = length.toInt() - numberOf64ByteBlocks * 32
|
||||
val vLast = Blake2b.digest(v[numberOf64ByteBlocks - 1], hashLength = remainingPartOfInput)
|
||||
val vLast = Blake2bPure.digest(v[numberOf64ByteBlocks - 1], hashLength = remainingPartOfInput)
|
||||
val concat =
|
||||
(v.map { it.copyOfRange(0, 32) })
|
||||
.plus(listOf(vLast))
|
||||
|
||||
-4
@@ -16,11 +16,7 @@
|
||||
|
||||
package com.ionspin.kotlin.crypto.parallelization
|
||||
|
||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.measureTime
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
|
||||
+12
-13
@@ -17,13 +17,12 @@
|
||||
package com.ionspin.kotlin.crypto.symmetric
|
||||
|
||||
import com.ionspin.kotlin.crypto.SRNG
|
||||
import com.ionspin.kotlin.crypto.util.chunked
|
||||
import com.ionspin.kotlin.crypto.util.xor
|
||||
|
||||
/**
|
||||
* Advanced encryption standard with cipher block chaining and PKCS #5
|
||||
*
|
||||
* For bulk encryption/decryption use [AesCbc.encrypt] and [AesCbc.decrypt]
|
||||
* For bulk encryption/decryption use [AesCbcPure.encrypt] and [AesCbcPure.decrypt]
|
||||
*
|
||||
* To get an instance of AesCbc and then feed it data sequentially with [addData] use [createEncryptor] and [createDecryptor]
|
||||
*
|
||||
@@ -32,7 +31,7 @@ import com.ionspin.kotlin.crypto.util.xor
|
||||
* on 21-Sep-2019
|
||||
*/
|
||||
@ExperimentalUnsignedTypes
|
||||
class AesCbc internal constructor(val aesKey: AesKey, val mode: Mode, initializationVector: UByteArray? = null) {
|
||||
class AesCbcPure internal constructor(val aesKey: AesKey, val mode: Mode, initializationVector: UByteArray? = null) {
|
||||
|
||||
companion object {
|
||||
const val BLOCK_BYTES = 16
|
||||
@@ -40,22 +39,22 @@ class AesCbc internal constructor(val aesKey: AesKey, val mode: Mode, initializa
|
||||
* Creates and returns AesCbc instance that can be fed data using [addData]. Once you have submitted all
|
||||
* data call [encrypt]
|
||||
*/
|
||||
fun createEncryptor(aesKey: AesKey) : AesCbc {
|
||||
return AesCbc(aesKey, Mode.ENCRYPT)
|
||||
fun createEncryptor(aesKey: AesKey) : AesCbcPure {
|
||||
return AesCbcPure(aesKey, Mode.ENCRYPT)
|
||||
}
|
||||
/**
|
||||
* Creates and returns AesCbc instance that can be fed data using [addData]. Once you have submitted all
|
||||
* data call [decrypt]
|
||||
*/
|
||||
fun createDecryptor(aesKey : AesKey) : AesCbc {
|
||||
return AesCbc(aesKey, Mode.DECRYPT)
|
||||
fun createDecryptor(aesKey : AesKey) : AesCbcPure {
|
||||
return AesCbcPure(aesKey, Mode.DECRYPT)
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk encryption, returns encrypted data and a random initialization vector
|
||||
*/
|
||||
fun encrypt(aesKey: AesKey, data: UByteArray): EncryptedDataAndInitializationVector {
|
||||
val aesCbc = AesCbc(aesKey, Mode.ENCRYPT)
|
||||
val aesCbc = AesCbcPure(aesKey, Mode.ENCRYPT)
|
||||
aesCbc.addData(data)
|
||||
return aesCbc.encrypt()
|
||||
}
|
||||
@@ -64,7 +63,7 @@ class AesCbc internal constructor(val aesKey: AesKey, val mode: Mode, initializa
|
||||
* Bulk decryption, returns decrypted data
|
||||
*/
|
||||
fun decrypt(aesKey: AesKey, data: UByteArray, initialCounter: UByteArray? = null): UByteArray {
|
||||
val aesCbc = AesCbc(aesKey, Mode.DECRYPT, initialCounter)
|
||||
val aesCbc = AesCbcPure(aesKey, Mode.DECRYPT, initialCounter)
|
||||
aesCbc.addData(data)
|
||||
return aesCbc.decrypt()
|
||||
}
|
||||
@@ -199,17 +198,17 @@ class AesCbc internal constructor(val aesKey: AesKey, val mode: Mode, initializa
|
||||
Mode.ENCRYPT -> {
|
||||
currentOutput = if (currentOutput.isEmpty()) {
|
||||
println("IV: $initVector")
|
||||
Aes.encrypt(aesKey, data xor initVector)
|
||||
AesPure.encrypt(aesKey, data xor initVector)
|
||||
} else {
|
||||
Aes.encrypt(aesKey, data xor currentOutput)
|
||||
AesPure.encrypt(aesKey, data xor currentOutput)
|
||||
}
|
||||
currentOutput
|
||||
}
|
||||
Mode.DECRYPT -> {
|
||||
if (currentOutput.isEmpty()) {
|
||||
currentOutput = Aes.decrypt(aesKey, data) xor initVector
|
||||
currentOutput = AesPure.decrypt(aesKey, data) xor initVector
|
||||
} else {
|
||||
currentOutput = Aes.decrypt(aesKey, data) xor previousEncrypted
|
||||
currentOutput = AesPure.decrypt(aesKey, data) xor previousEncrypted
|
||||
}
|
||||
previousEncrypted = data
|
||||
currentOutput
|
||||
+11
-12
@@ -20,15 +20,14 @@ import com.ionspin.kotlin.bignum.Endianness
|
||||
import com.ionspin.kotlin.bignum.integer.BigInteger
|
||||
import com.ionspin.kotlin.bignum.modular.ModularBigInteger
|
||||
import com.ionspin.kotlin.crypto.SRNG
|
||||
import com.ionspin.kotlin.crypto.util.chunked
|
||||
import com.ionspin.kotlin.crypto.symmetric.AesCtr.Companion.encrypt
|
||||
import com.ionspin.kotlin.crypto.symmetric.AesCtrPure.Companion.encrypt
|
||||
import com.ionspin.kotlin.crypto.util.xor
|
||||
|
||||
/**
|
||||
*
|
||||
* Advanced encryption standard with counter mode
|
||||
*
|
||||
* For bulk encryption/decryption use [AesCtr.encrypt] and [AesCtr.decrypt]
|
||||
* For bulk encryption/decryption use [AesCtrPure.encrypt] and [AesCtrPure.decrypt]
|
||||
*
|
||||
* To get an instance of AesCtr and then feed it data sequentially with [addData] use [createEncryptor] and [createDecryptor]
|
||||
*
|
||||
@@ -37,7 +36,7 @@ import com.ionspin.kotlin.crypto.util.xor
|
||||
* on 22-Sep-2019
|
||||
*/
|
||||
@ExperimentalUnsignedTypes
|
||||
class AesCtr internal constructor(val aesKey: AesKey, val mode: Mode, initialCounter: UByteArray? = null) {
|
||||
class AesCtrPure internal constructor(val aesKey: AesKey, val mode: Mode, initialCounter: UByteArray? = null) {
|
||||
|
||||
companion object {
|
||||
const val BLOCK_BYTES = 16
|
||||
@@ -47,21 +46,21 @@ class AesCtr internal constructor(val aesKey: AesKey, val mode: Mode, initialCou
|
||||
* Creates and returns AesCtr instance that can be fed data using [addData]. Once you have submitted all
|
||||
* data call [encrypt]
|
||||
*/
|
||||
fun createEncryptor(aesKey: AesKey) : AesCtr {
|
||||
return AesCtr(aesKey, Mode.ENCRYPT)
|
||||
fun createEncryptor(aesKey: AesKey) : AesCtrPure {
|
||||
return AesCtrPure(aesKey, Mode.ENCRYPT)
|
||||
}
|
||||
/**
|
||||
* Creates and returns AesCtr instance that can be fed data using [addData]. Once you have submitted all
|
||||
* data call [decrypt]
|
||||
*/
|
||||
fun createDecryptor(aesKey : AesKey) : AesCtr {
|
||||
return AesCtr(aesKey, Mode.DECRYPT)
|
||||
fun createDecryptor(aesKey : AesKey) : AesCtrPure {
|
||||
return AesCtrPure(aesKey, Mode.DECRYPT)
|
||||
}
|
||||
/**
|
||||
* Bulk encryption, returns encrypted data and a random initial counter
|
||||
*/
|
||||
fun encrypt(aesKey: AesKey, data: UByteArray): EncryptedDataAndInitialCounter {
|
||||
val aesCtr = AesCtr(aesKey, Mode.ENCRYPT)
|
||||
val aesCtr = AesCtrPure(aesKey, Mode.ENCRYPT)
|
||||
aesCtr.addData(data)
|
||||
return aesCtr.encrypt()
|
||||
}
|
||||
@@ -69,7 +68,7 @@ class AesCtr internal constructor(val aesKey: AesKey, val mode: Mode, initialCou
|
||||
* Bulk decryption, returns decrypted data
|
||||
*/
|
||||
fun decrypt(aesKey: AesKey, data: UByteArray, initialCounter: UByteArray? = null): UByteArray {
|
||||
val aesCtr = AesCtr(aesKey, Mode.DECRYPT, initialCounter)
|
||||
val aesCtr = AesCtrPure(aesKey, Mode.DECRYPT, initialCounter)
|
||||
aesCtr.addData(data)
|
||||
return aesCtr.decrypt()
|
||||
}
|
||||
@@ -165,10 +164,10 @@ class AesCtr internal constructor(val aesKey: AesKey, val mode: Mode, initialCou
|
||||
val blockCountAsByteArray = blockCount.toUByteArray(Endianness.BIG).toUByteArray().expandCounterTo16Bytes()
|
||||
return when (mode) {
|
||||
Mode.ENCRYPT -> {
|
||||
Aes.encrypt(aesKey, blockCountAsByteArray) xor data
|
||||
AesPure.encrypt(aesKey, blockCountAsByteArray) xor data
|
||||
}
|
||||
Mode.DECRYPT -> {
|
||||
Aes.encrypt(aesKey, blockCountAsByteArray) xor data
|
||||
AesPure.encrypt(aesKey, blockCountAsByteArray) xor data
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -6,7 +6,7 @@ import com.ionspin.kotlin.crypto.util.flattenToUByteArray
|
||||
* Created by Ugljesa Jovanovic (jovanovic.ugljesa@gmail.com) on 07/Sep/2019
|
||||
*/
|
||||
@ExperimentalUnsignedTypes
|
||||
internal class Aes internal constructor(val aesKey: AesKey, val input: UByteArray) {
|
||||
internal class AesPure internal constructor(val aesKey: AesKey, val input: UByteArray) {
|
||||
companion object {
|
||||
private val debug = false
|
||||
|
||||
@@ -57,11 +57,11 @@ internal class Aes internal constructor(val aesKey: AesKey, val input: UByteArra
|
||||
val rcon: UByteArray = ubyteArrayOf(0x8DU, 0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U, 0x1BU, 0x36U)
|
||||
|
||||
fun encrypt(aesKey: AesKey, input: UByteArray): UByteArray {
|
||||
return Aes(aesKey, input).encrypt()
|
||||
return AesPure(aesKey, input).encrypt()
|
||||
}
|
||||
|
||||
fun decrypt(aesKey: AesKey, input: UByteArray): UByteArray {
|
||||
return Aes(aesKey, input).decrypt()
|
||||
return AesPure(aesKey, input).decrypt()
|
||||
}
|
||||
|
||||
}
|
||||
+13
-13
@@ -16,10 +16,10 @@
|
||||
|
||||
package com.ionspin.kotlin.crypto
|
||||
|
||||
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b
|
||||
import com.ionspin.kotlin.crypto.hash.sha.Sha256
|
||||
import com.ionspin.kotlin.crypto.hash.sha.Sha512
|
||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2
|
||||
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bPure
|
||||
import com.ionspin.kotlin.crypto.hash.sha.Sha256Pure
|
||||
import com.ionspin.kotlin.crypto.hash.sha.Sha512Pure
|
||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Pure
|
||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonType
|
||||
import com.ionspin.kotlin.crypto.util.testBlocking
|
||||
import kotlin.test.Test
|
||||
@@ -40,7 +40,7 @@ class ReadmeTest {
|
||||
@Test
|
||||
fun blake2bObjectExample() {
|
||||
val input = "abc"
|
||||
val result = Blake2b.digest(input)
|
||||
val result = Blake2bPure.digest(input)
|
||||
//@formatter:off
|
||||
val expectedResult = ubyteArrayOf(
|
||||
0xBAU,0x80U,0xA5U,0x3FU,0x98U,0x1CU,0x4DU,0x0DU,0x6AU,0x27U,0x97U,0xB6U,0x9FU,0x12U,0xF6U,0xE9U,
|
||||
@@ -59,7 +59,7 @@ class ReadmeTest {
|
||||
fun blake2bInstanceExample() {
|
||||
val test = "abc"
|
||||
val key = "key"
|
||||
val blake2b = Blake2b(key)
|
||||
val blake2b = Blake2bPure(key)
|
||||
blake2b.update(test)
|
||||
val result = blake2b.digest()
|
||||
|
||||
@@ -79,7 +79,7 @@ class ReadmeTest {
|
||||
@Test
|
||||
fun sha256Example() {
|
||||
val input = "abc"
|
||||
val result = Sha256.digest(inputString = input)
|
||||
val result = Sha256Pure.digest(inputString = input)
|
||||
val expectedResult = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toUByteArray())
|
||||
@@ -92,7 +92,7 @@ class ReadmeTest {
|
||||
@Test
|
||||
fun sha512Example() {
|
||||
val input = "abc"
|
||||
val result = Sha512.digest(inputMessage = input.encodeToByteArray().map { it.toUByte() }.toUByteArray())
|
||||
val result = Sha512Pure.digest(inputMessage = input.encodeToByteArray().map { it.toUByte() }.toUByteArray())
|
||||
println(result.map { it.toString(16) })
|
||||
val expectedResult = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" +
|
||||
"2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
|
||||
@@ -106,7 +106,7 @@ class ReadmeTest {
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun sha256UpdatableExample() {
|
||||
val sha256 = Sha256()
|
||||
val sha256 = Sha256Pure()
|
||||
sha256.update("abc")
|
||||
val result = sha256.digest()
|
||||
val expectedResult = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
|
||||
@@ -118,7 +118,7 @@ class ReadmeTest {
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun sha512UpdatableExample() {
|
||||
val sha512 = Sha512()
|
||||
val sha512 = Sha512Pure()
|
||||
sha512.update("abc")
|
||||
val result = sha512.digest()
|
||||
val expectedResult = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" +
|
||||
@@ -133,13 +133,13 @@ class ReadmeTest {
|
||||
@ExperimentalTime
|
||||
@Test
|
||||
fun argon2StringExample() = testBlocking {
|
||||
val argon2Instance = Argon2(
|
||||
val argon2Instance = Argon2Pure(
|
||||
password = "Password",
|
||||
salt = "RandomSalt",
|
||||
parallelism = 1,
|
||||
tagLength = 64U,
|
||||
requestedMemorySize = 4096U,
|
||||
numberOfIterations = 100,
|
||||
numberOfIterations = 2,
|
||||
key = "",
|
||||
associatedData = "",
|
||||
argonType = ArgonType.Argon2id
|
||||
@@ -147,7 +147,7 @@ class ReadmeTest {
|
||||
val time = measureTime {
|
||||
val tag = argon2Instance.derive()
|
||||
val tagString = tag.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "")
|
||||
val expectedTagString = "27c61b6538ef9f4a1250f8712cac09fc4329969295f9440249437d38c1617a005c2702d76a8a59e4cda2dfba48e1132261dacdfd31296945906992ea32f1d06e"
|
||||
val expectedTagString = "c19db7e22d1480702b943872c863baf8c43b53d0c3e2c782cd07bfc613eda159233bd821a945c239c5085c70257f7c93d8a809f81c4af367f4ad8f0443a8fc47"
|
||||
println("Tag: ${tagString}")
|
||||
assertEquals(tagString, expectedTagString)
|
||||
}
|
||||
|
||||
+4
-4
@@ -18,7 +18,7 @@
|
||||
|
||||
package com.ionspin.kotlin.crypto.hash.argon
|
||||
|
||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2
|
||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Pure
|
||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.ArgonType
|
||||
import com.ionspin.kotlin.crypto.util.hexColumsPrint
|
||||
import kotlin.test.Test
|
||||
@@ -57,7 +57,7 @@ class Argon2KATTest {
|
||||
val secret: UByteArray = ubyteArrayOf(0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U)
|
||||
val associatedData: UByteArray = ubyteArrayOf(0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U)
|
||||
|
||||
val digest = Argon2(
|
||||
val digest = Argon2Pure(
|
||||
password,
|
||||
salt,
|
||||
parallelism.toInt(),
|
||||
@@ -98,7 +98,7 @@ class Argon2KATTest {
|
||||
val secret: UByteArray = ubyteArrayOf(0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U)
|
||||
val associatedData: UByteArray = ubyteArrayOf(0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U)
|
||||
|
||||
val digest = Argon2(
|
||||
val digest = Argon2Pure(
|
||||
password,
|
||||
salt,
|
||||
parallelism.toInt(),
|
||||
@@ -139,7 +139,7 @@ class Argon2KATTest {
|
||||
val secret: UByteArray = ubyteArrayOf(0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U, 0x03U)
|
||||
val associatedData: UByteArray = ubyteArrayOf(0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U, 0x04U)
|
||||
|
||||
val digest = Argon2(
|
||||
val digest = Argon2Pure(
|
||||
password,
|
||||
salt,
|
||||
parallelism.toInt(),
|
||||
|
||||
+7
-7
@@ -46,7 +46,7 @@ class Blake2BTest {
|
||||
"1234567890" +
|
||||
"1234567890"
|
||||
|
||||
val result = Blake2b.digest(test)
|
||||
val result = Blake2bPure.digest(test)
|
||||
//Generated with b2sum 8.31
|
||||
val expectedResult = ubyteArrayOf(
|
||||
//@formatter:off
|
||||
@@ -77,7 +77,7 @@ class Blake2BTest {
|
||||
"1234567890"
|
||||
|
||||
|
||||
val result = Blake2b.digest(test)
|
||||
val result = Blake2bPure.digest(test)
|
||||
val expectedResultString = "800bb78cd4da18995c8074713bb674" +
|
||||
"3cd94b2b6490a693fe4000ed00833b88b7b474d94af9cfed246b1b" +
|
||||
"4ce1935a76154d7ea7c410493557741d18ec3a08da75"
|
||||
@@ -93,7 +93,7 @@ class Blake2BTest {
|
||||
fun testDigest() {
|
||||
val test = "111111111122222222223333333333333"
|
||||
|
||||
val result = Blake2b.digest(test)
|
||||
val result = Blake2bPure.digest(test)
|
||||
//Generated with b2sum 8.31
|
||||
val expectedResult = ubyteArrayOf(
|
||||
//@formatter:off
|
||||
@@ -115,7 +115,7 @@ class Blake2BTest {
|
||||
val test = "abc"
|
||||
val key = "key"
|
||||
|
||||
val result = Blake2b.digest(test, key)
|
||||
val result = Blake2bPure.digest(test, key)
|
||||
|
||||
assertTrue {
|
||||
result.isNotEmpty()
|
||||
@@ -134,7 +134,7 @@ class Blake2BTest {
|
||||
fun testDigestFromRfc() {
|
||||
val test = "abc"
|
||||
|
||||
val result = Blake2b.digest(test)
|
||||
val result = Blake2bPure.digest(test)
|
||||
//@formatter:off
|
||||
val expectedResult = ubyteArrayOf(
|
||||
|
||||
@@ -272,7 +272,7 @@ class Blake2BTest {
|
||||
for (i in 0 until mixChain.size - 1) {
|
||||
val inputRound = mixChain[i]
|
||||
val round = i
|
||||
val result = Blake2b.mixRound(inputRound, message, round)
|
||||
val result = Blake2bPure.mixRound(inputRound, message, round)
|
||||
val expectedResult = mixChain[i + 1]
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult)
|
||||
@@ -286,7 +286,7 @@ class Blake2BTest {
|
||||
fun testInvalidHashLength() {
|
||||
val test = "1234567890"
|
||||
assertFailsWith(RuntimeException::class) {
|
||||
val result = Blake2b.digest(inputString = test, hashLength = 65)
|
||||
val result = Blake2bPure.digest(inputString = test, hashLength = 65)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -42,7 +42,7 @@ class Blake2bInstanceTest {
|
||||
//@formatter:on
|
||||
)
|
||||
|
||||
val blake2b = Blake2b()
|
||||
val blake2b = Blake2bPure()
|
||||
for (i in 0 until updates) {
|
||||
blake2b.update(input)
|
||||
}
|
||||
@@ -60,7 +60,7 @@ class Blake2bInstanceTest {
|
||||
val expectedResult = "2F49AEB613E34E924E175A6AF2FAAD7BC78235F9C5E461C68FD5B47E".toLowerCase() +
|
||||
"E8E2FD2FB4C07D7E4A72404612D92899AF8A328F3B614ED77244B481151D40B11E32A4".toLowerCase()
|
||||
|
||||
val blake2b = Blake2b()
|
||||
val blake2b = Blake2bPure()
|
||||
for (i in 0 until updates) {
|
||||
blake2b.update(input)
|
||||
}
|
||||
@@ -74,7 +74,7 @@ class Blake2bInstanceTest {
|
||||
fun testDigestWithKey() {
|
||||
val test = "abc"
|
||||
val key = "key"
|
||||
val blake2b = Blake2b(key)
|
||||
val blake2b = Blake2bPure(key)
|
||||
blake2b.update(test)
|
||||
val result = blake2b.digest()
|
||||
|
||||
|
||||
+2
-2
@@ -37,7 +37,7 @@ class Blake2bKnowAnswerTests {
|
||||
fun knownAnswerTest() {
|
||||
kat.forEach {
|
||||
val parsedInput = it.input.chunked(2).map { it.toUByte(16) }.toUByteArray()
|
||||
val result = Blake2b.digest(
|
||||
val result = Blake2bPure.digest(
|
||||
inputMessage = parsedInput,
|
||||
key = it.key.chunked(2).map { it.toUByte(16) }.toUByteArray()
|
||||
)
|
||||
@@ -53,7 +53,7 @@ class Blake2bKnowAnswerTests {
|
||||
kat.forEach { kat ->
|
||||
val parsedInput = kat.input.chunked(2).map { it.toUByte(16) }.toUByteArray()
|
||||
val chunkedInput = parsedInput.toList().chunked(128).map { it.toUByteArray() }
|
||||
val blake2b = Blake2b(key = kat.key.chunked(2).map { it.toUByte(16) }.toUByteArray())
|
||||
val blake2b = Blake2bPure(key = kat.key.chunked(2).map { it.toUByte(16) }.toUByteArray())
|
||||
chunkedInput.forEach { blake2b.update(it) }
|
||||
val result = blake2b.digest()
|
||||
assertTrue("KAT ${kat.input} \nkey: ${kat.key} \nexpected: {${kat.hash}") {
|
||||
|
||||
+4
-4
@@ -31,7 +31,7 @@ class Sha256Test {
|
||||
@Test
|
||||
fun testWellKnownValue() {
|
||||
|
||||
val result = Sha256.digest(inputString = "abc")
|
||||
val result = Sha256Pure.digest(inputString = "abc")
|
||||
val expectedResult = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult.chunked(2).map { it.toUByte(16) }.toUByteArray())
|
||||
@@ -44,7 +44,7 @@ class Sha256Test {
|
||||
@Test
|
||||
fun testWellKnownDoubleBlock() {
|
||||
|
||||
val resultDoubleBlock = Sha256.digest(inputString = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")
|
||||
val resultDoubleBlock = Sha256Pure.digest(inputString = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")
|
||||
val expectedResultForDoubleBlock = "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"
|
||||
assertTrue {
|
||||
resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray())
|
||||
@@ -56,7 +56,7 @@ class Sha256Test {
|
||||
fun testWellKnown3() { //It's good that I'm consistent with names.
|
||||
|
||||
|
||||
val resultDoubleBlock = Sha256.digest(inputString = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")
|
||||
val resultDoubleBlock = Sha256Pure.digest(inputString = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")
|
||||
println(resultDoubleBlock.map{ it.toString(16)}.joinToString(separator = ""))
|
||||
val expectedResultForDoubleBlock = "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1"
|
||||
assertTrue {
|
||||
@@ -71,7 +71,7 @@ class Sha256Test {
|
||||
for (i in 0 until 1000000) {
|
||||
inputBuilder.append("a")
|
||||
}
|
||||
val resultDoubleBlock = Sha256.digest(inputMessage = (inputBuilder.toString()).encodeToByteArray().map { it.toUByte() }.toUByteArray())
|
||||
val resultDoubleBlock = Sha256Pure.digest(inputMessage = (inputBuilder.toString()).encodeToByteArray().map { it.toUByte() }.toUByteArray())
|
||||
val expectedResultForDoubleBlock = "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"
|
||||
assertTrue {
|
||||
resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray())
|
||||
|
||||
+5
-5
@@ -31,7 +31,7 @@ class Sha256UpdatableTest {
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun testWellKnownValue() {
|
||||
val sha256 = Sha256()
|
||||
val sha256 = Sha256Pure()
|
||||
sha256.update("abc")
|
||||
val result = sha256.digest()
|
||||
val expectedResult = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
|
||||
@@ -43,7 +43,7 @@ class Sha256UpdatableTest {
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun testWellKnownDoubleBlock() {
|
||||
val sha256 = Sha256()
|
||||
val sha256 = Sha256Pure()
|
||||
sha256.update(data = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")
|
||||
val resultDoubleBlock = sha256.digest()
|
||||
println(resultDoubleBlock.map{ it.toString(16)}.joinToString(separator = ""))
|
||||
@@ -56,7 +56,7 @@ class Sha256UpdatableTest {
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun testWellKnown3() { //It's good that I'm consistent with names.
|
||||
val sha256 = Sha256()
|
||||
val sha256 = Sha256Pure()
|
||||
sha256.update(data = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")
|
||||
val resultDoubleBlock = sha256.digest()
|
||||
println(resultDoubleBlock.map{ it.toString(16)}.joinToString(separator = ""))
|
||||
@@ -69,7 +69,7 @@ class Sha256UpdatableTest {
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun testWellKnownLong() {
|
||||
val sha256 = Sha256()
|
||||
val sha256 = Sha256Pure()
|
||||
for (i in 0 until 10000) {
|
||||
sha256.update("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
|
||||
}
|
||||
@@ -84,7 +84,7 @@ class Sha256UpdatableTest {
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun testWellKnownLonger() {
|
||||
val sha256 = Sha256()
|
||||
val sha256 = Sha256Pure()
|
||||
for (i in 0 until 16_777_216) {
|
||||
if (i % 10000 == 0) {
|
||||
println("$i/16777216")
|
||||
|
||||
+3
-3
@@ -30,7 +30,7 @@ class Sha512Test {
|
||||
@Test
|
||||
fun testWellKnownValue() {
|
||||
|
||||
val result = Sha512.digest(inputMessage = "abc".encodeToByteArray().map { it.toUByte() }.toUByteArray())
|
||||
val result = Sha512Pure.digest(inputMessage = "abc".encodeToByteArray().map { it.toUByte() }.toUByteArray())
|
||||
println(result.map {it.toString(16)})
|
||||
val expectedResult = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" +
|
||||
"2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
|
||||
@@ -45,7 +45,7 @@ class Sha512Test {
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun testWellKnown3() {
|
||||
val sha512 = Sha512()
|
||||
val sha512 = Sha512Pure()
|
||||
sha512.update(data = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")
|
||||
val resultDoubleBlock = sha512.digest()
|
||||
val expectedResultForDoubleBlock = "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" +
|
||||
@@ -62,7 +62,7 @@ class Sha512Test {
|
||||
for (i in 0 until 1000000) {
|
||||
inputBuilder.append("a")
|
||||
}
|
||||
val resultDoubleBlock = Sha512.digest(inputMessage = (inputBuilder.toString()).encodeToByteArray().map { it.toUByte() }.toUByteArray())
|
||||
val resultDoubleBlock = Sha512Pure.digest(inputMessage = (inputBuilder.toString()).encodeToByteArray().map { it.toUByte() }.toUByteArray())
|
||||
val expectedResultForDoubleBlock = "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"
|
||||
assertTrue {
|
||||
resultDoubleBlock.contentEquals(expectedResultForDoubleBlock.chunked(2).map { it.toUByte(16) }.toUByteArray())
|
||||
|
||||
+4
-4
@@ -29,7 +29,7 @@ class Sha512UpdatableTest {
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun testWellKnownValue() {
|
||||
val sha512 = Sha512()
|
||||
val sha512 = Sha512Pure()
|
||||
sha512.update("abc")
|
||||
val result = sha512.digest()
|
||||
val expectedResult = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" +
|
||||
@@ -44,7 +44,7 @@ class Sha512UpdatableTest {
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun testWellKnownDoubleBlock() {
|
||||
val sha512 = Sha512()
|
||||
val sha512 = Sha512Pure()
|
||||
sha512.update(data = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")
|
||||
val resultDoubleBlock = sha512.digest()
|
||||
println(resultDoubleBlock.map{ it.toString(16)}.joinToString(separator = ""))
|
||||
@@ -58,7 +58,7 @@ class Sha512UpdatableTest {
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun testWellKnownLong() {
|
||||
val sha512 = Sha512()
|
||||
val sha512 = Sha512Pure()
|
||||
for (i in 0 until 10000) {
|
||||
sha512.update("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
|
||||
}
|
||||
@@ -73,7 +73,7 @@ class Sha512UpdatableTest {
|
||||
@ExperimentalStdlibApi
|
||||
@Test
|
||||
fun testWellKnownLonger() {
|
||||
val sha512 = Sha512()
|
||||
val sha512 = Sha512Pure()
|
||||
for (i in 0 until 16_777_216) {
|
||||
if (i % 10000 == 0) {
|
||||
println("$i/16777216")
|
||||
|
||||
+5
-6
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.ionspin.kotlin.crypto.symmetric
|
||||
|
||||
import com.ionspin.kotlin.crypto.util.hexStringToUByteArray
|
||||
import com.ionspin.kotlin.crypto.util.hexStringToUByteArray
|
||||
import com.ionspin.kotlin.crypto.util.toHexString
|
||||
import kotlin.test.Test
|
||||
@@ -38,7 +37,7 @@ class AesCbcTest {
|
||||
val plaintext = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
||||
val expectedCipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7"
|
||||
val aesCbc =
|
||||
AesCbc(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initializationVector = iv.hexStringToUByteArray())
|
||||
AesCbcPure(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initializationVector = iv.hexStringToUByteArray())
|
||||
aesCbc.addData(plaintext.hexStringToUByteArray())
|
||||
val encrypted = aesCbc.encrypt()
|
||||
println("Encrypted: ${encrypted.encryptedData.toHexString()}")
|
||||
@@ -59,8 +58,8 @@ class AesCbcTest {
|
||||
|
||||
val plainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
||||
|
||||
val encryptedDataAndInitializationVector = AesCbc.encrypt(key, plainText.hexStringToUByteArray())
|
||||
val decrypted = AesCbc.decrypt(
|
||||
val encryptedDataAndInitializationVector = AesCbcPure.encrypt(key, plainText.hexStringToUByteArray())
|
||||
val decrypted = AesCbcPure.decrypt(
|
||||
key,
|
||||
encryptedDataAndInitializationVector.encryptedData,
|
||||
encryptedDataAndInitializationVector.initilizationVector
|
||||
@@ -77,7 +76,7 @@ class AesCbcTest {
|
||||
val cipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7"
|
||||
val expectedPlainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
||||
val aesCbc =
|
||||
AesCbc(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initializationVector = iv.hexStringToUByteArray())
|
||||
AesCbcPure(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initializationVector = iv.hexStringToUByteArray())
|
||||
aesCbc.addData(cipherText.hexStringToUByteArray())
|
||||
val decrypted = aesCbc.decrypt()
|
||||
println("Decrypted: ${decrypted.toHexString()}")
|
||||
@@ -96,7 +95,7 @@ class AesCbcTest {
|
||||
val iv = "57f02a5c5339daeb0a2908a06ac6393f"
|
||||
val cipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7"
|
||||
val expectedPlainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
||||
val decrypted = AesCbc.decrypt(AesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), iv.hexStringToUByteArray())
|
||||
val decrypted = AesCbcPure.decrypt(AesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), iv.hexStringToUByteArray())
|
||||
println("Decrypted: ${decrypted.toHexString()}")
|
||||
|
||||
expectedPlainText == decrypted.toHexString()
|
||||
|
||||
+5
-5
@@ -38,7 +38,7 @@ class AesCtrTest {
|
||||
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
||||
val expectedCipherText =
|
||||
"874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"
|
||||
val aesCtr = AesCtr(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initialCounter = ic.hexStringToUByteArray())
|
||||
val aesCtr = AesCtrPure(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initialCounter = ic.hexStringToUByteArray())
|
||||
aesCtr.addData(
|
||||
plaintext.hexStringToUByteArray()
|
||||
)
|
||||
@@ -57,8 +57,8 @@ class AesCtrTest {
|
||||
val key = AesKey.Aes128Key(keyString)
|
||||
val plainText = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
||||
|
||||
val encryptedDataAndInitializationVector = AesCtr.encrypt(key, plainText.hexStringToUByteArray())
|
||||
val decrypted = AesCtr.decrypt(
|
||||
val encryptedDataAndInitializationVector = AesCtrPure.encrypt(key, plainText.hexStringToUByteArray())
|
||||
val decrypted = AesCtrPure.decrypt(
|
||||
key,
|
||||
encryptedDataAndInitializationVector.encryptedData,
|
||||
encryptedDataAndInitializationVector.initialCounter
|
||||
@@ -77,7 +77,7 @@ class AesCtrTest {
|
||||
"874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"
|
||||
val expectedPlainText =
|
||||
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
||||
val aesCtr = AesCtr(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initialCounter = ic.hexStringToUByteArray())
|
||||
val aesCtr = AesCtrPure(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initialCounter = ic.hexStringToUByteArray())
|
||||
aesCtr.addData(cipherText.hexStringToUByteArray())
|
||||
val decrypted = aesCtr.decrypt()
|
||||
println("Decrypted: ${decrypted.toHexString()}")
|
||||
@@ -97,7 +97,7 @@ class AesCtrTest {
|
||||
"874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"
|
||||
val expectedPlainText =
|
||||
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
||||
val decrypted = AesCtr.decrypt(AesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), ic.hexStringToUByteArray())
|
||||
val decrypted = AesCtrPure.decrypt(AesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), ic.hexStringToUByteArray())
|
||||
println("Decrypted: ${decrypted.toHexString()}")
|
||||
expectedPlainText == decrypted.toHexString()
|
||||
}
|
||||
|
||||
+19
-19
@@ -20,7 +20,7 @@ class AesTest {
|
||||
ubyteArrayOf(0U, 0U, 0U, 0U),
|
||||
ubyteArrayOf(0U, 0U, 0U, 0U)
|
||||
)
|
||||
val aes = Aes(AesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
||||
val aes = AesPure(AesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
||||
fakeState.copyInto(aes.state)
|
||||
aes.subBytes()
|
||||
assertTrue {
|
||||
@@ -42,7 +42,7 @@ class AesTest {
|
||||
ubyteArrayOf(2U, 3U, 0U, 1U),
|
||||
ubyteArrayOf(3U, 0U, 1U, 2U)
|
||||
)
|
||||
val aes = Aes(AesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
||||
val aes = AesPure(AesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
||||
fakeState.copyInto(aes.state)
|
||||
aes.shiftRows()
|
||||
assertTrue {
|
||||
@@ -56,7 +56,7 @@ class AesTest {
|
||||
assertTrue {
|
||||
val a = 0x57U
|
||||
val b = 0x83U
|
||||
val aes = Aes(AesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
||||
val aes = AesPure(AesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
||||
val c = aes.galoisFieldMultiply(a.toUByte(), b.toUByte())
|
||||
c == 0xC1U.toUByte()
|
||||
}
|
||||
@@ -64,7 +64,7 @@ class AesTest {
|
||||
assertTrue {
|
||||
val a = 0x57U
|
||||
val b = 0x13U
|
||||
val aes = Aes(AesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
||||
val aes = AesPure(AesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
||||
val c = aes.galoisFieldMultiply(a.toUByte(), b.toUByte())
|
||||
c == 0xFEU.toUByte()
|
||||
}
|
||||
@@ -89,7 +89,7 @@ class AesTest {
|
||||
ubyteArrayOf(0xbcU, 0x9dU, 0x01U, 0xc6U)
|
||||
)
|
||||
|
||||
val aes = Aes(AesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
||||
val aes = AesPure(AesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
||||
fakeState.copyInto(aes.state)
|
||||
aes.mixColumns()
|
||||
assertTrue {
|
||||
@@ -116,7 +116,7 @@ class AesTest {
|
||||
).toTypedArray()
|
||||
|
||||
|
||||
val aes = Aes(AesKey.Aes128Key(key), irrelevantInput)
|
||||
val aes = AesPure(AesKey.Aes128Key(key), irrelevantInput)
|
||||
val result = aes.expandedKey.map {
|
||||
it.foldIndexed(0U) { index, acc, uByte ->
|
||||
acc + (uByte.toUInt() shl (24 - index * 8))
|
||||
@@ -140,7 +140,7 @@ class AesTest {
|
||||
).toTypedArray()
|
||||
|
||||
|
||||
val aes = Aes(AesKey.Aes192Key(key), irrelevantInput)
|
||||
val aes = AesPure(AesKey.Aes192Key(key), irrelevantInput)
|
||||
val result = aes.expandedKey.map {
|
||||
it.foldIndexed(0U) { index, acc, uByte ->
|
||||
acc + (uByte.toUInt() shl (24 - index * 8))
|
||||
@@ -166,7 +166,7 @@ class AesTest {
|
||||
).toTypedArray()
|
||||
|
||||
|
||||
val aes = Aes(AesKey.Aes256Key(key), irrelevantInput)
|
||||
val aes = AesPure(AesKey.Aes256Key(key), irrelevantInput)
|
||||
val result = aes.expandedKey.map {
|
||||
it.foldIndexed(0U) { index, acc, uByte ->
|
||||
acc + (uByte.toUInt() shl (24 - index * 8))
|
||||
@@ -183,7 +183,7 @@ class AesTest {
|
||||
val key = "2b7e151628aed2a6abf7158809cf4f3c"
|
||||
val expectedResult = "3925841d02dc09fbdc118597196a0b32"
|
||||
|
||||
val aes = Aes(AesKey.Aes128Key(key), input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
||||
val aes = AesPure(AesKey.Aes128Key(key), input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
||||
val result = aes.encrypt()
|
||||
assertTrue {
|
||||
result.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
||||
@@ -197,12 +197,12 @@ class AesTest {
|
||||
val key = "2b7e151628aed2a6abf7158809cf4f3c"
|
||||
val expectedResult = "3925841d02dc09fbdc118597196a0b32"
|
||||
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()
|
||||
val aes = Aes(AesKey.Aes128Key(key), original)
|
||||
val aes = AesPure(AesKey.Aes128Key(key), original)
|
||||
val encrypted = aes.encrypt()
|
||||
assertTrue {
|
||||
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
||||
}
|
||||
val decrypted = Aes.decrypt(AesKey.Aes128Key(key), encrypted)
|
||||
val decrypted = AesPure.decrypt(AesKey.Aes128Key(key), encrypted)
|
||||
|
||||
decrypted.contentEquals(original)
|
||||
}
|
||||
@@ -211,12 +211,12 @@ class AesTest {
|
||||
val key = "000102030405060708090a0b0c0d0e0f"
|
||||
val expectedResult = "69c4e0d86a7b0430d8cdb78070b4c55a"
|
||||
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()
|
||||
val aes = Aes(AesKey.Aes128Key(key), original)
|
||||
val aes = AesPure(AesKey.Aes128Key(key), original)
|
||||
val encrypted = aes.encrypt()
|
||||
assertTrue {
|
||||
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
||||
}
|
||||
val aesDec = Aes(AesKey.Aes128Key(key), encrypted)
|
||||
val aesDec = AesPure(AesKey.Aes128Key(key), encrypted)
|
||||
val decrypted = aesDec.decrypt()
|
||||
assertTrue {
|
||||
aesDec.expandedKey.contentDeepEquals(aes.expandedKey)
|
||||
@@ -229,11 +229,11 @@ class AesTest {
|
||||
val key = "000102030405060708090a0b0c0d0e0f"
|
||||
val expectedResult = "69c4e0d86a7b0430d8cdb78070b4c55a"
|
||||
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()
|
||||
val encrypted = Aes.encrypt(AesKey.Aes128Key(key), original)
|
||||
val encrypted = AesPure.encrypt(AesKey.Aes128Key(key), original)
|
||||
assertTrue {
|
||||
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
||||
}
|
||||
val decrypted = Aes.decrypt(AesKey.Aes128Key(key), encrypted)
|
||||
val decrypted = AesPure.decrypt(AesKey.Aes128Key(key), encrypted)
|
||||
decrypted.contentEquals(original)
|
||||
}
|
||||
|
||||
@@ -242,11 +242,11 @@ class AesTest {
|
||||
val key = "000102030405060708090a0b0c0d0e0f1011121314151617"
|
||||
val expectedResult = "dda97ca4864cdfe06eaf70a0ec0d7191"
|
||||
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()
|
||||
val encrypted = Aes.encrypt(AesKey.Aes192Key(key), original)
|
||||
val encrypted = AesPure.encrypt(AesKey.Aes192Key(key), original)
|
||||
assertTrue {
|
||||
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
||||
}
|
||||
val decrypted = Aes.decrypt(AesKey.Aes192Key(key), encrypted)
|
||||
val decrypted = AesPure.decrypt(AesKey.Aes192Key(key), encrypted)
|
||||
decrypted.contentEquals(original)
|
||||
}
|
||||
|
||||
@@ -255,11 +255,11 @@ class AesTest {
|
||||
val key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
|
||||
val expectedResult = "8ea2b7ca516745bfeafc49904b496089"
|
||||
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()
|
||||
val encrypted = Aes.encrypt(AesKey.Aes256Key(key), original)
|
||||
val encrypted = AesPure.encrypt(AesKey.Aes256Key(key), original)
|
||||
assertTrue {
|
||||
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
||||
}
|
||||
val decrypted = Aes.decrypt(AesKey.Aes256Key(key), encrypted)
|
||||
val decrypted = AesPure.decrypt(AesKey.Aes256Key(key), encrypted)
|
||||
decrypted.contentEquals(original)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user