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.bignum.integer.toBigInteger | ||||||
| import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b | 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.argonBlake2bArbitraryLenghtHash | ||||||
| import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.compressionFunctionG | import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.compressionFunctionG | ||||||
| import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.validateArgonParameters | import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.validateArgonParameters | ||||||
| @ -44,16 +45,16 @@ data class SegmentPosition( | |||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| class Argon2( | class Argon2( | ||||||
|     val password: Array<UByte>, |     private val password: Array<UByte>, | ||||||
|     val salt: Array<UByte> = emptyArray(), |     private val salt: Array<UByte> = emptyArray(), | ||||||
|     val parallelism: Int = 1, |     private val parallelism: Int = 1, | ||||||
|     val tagLength: UInt = 64U, |     private val tagLength: UInt = 64U, | ||||||
|     requestedMemorySize: UInt = 0U, |     requestedMemorySize: UInt = 0U, | ||||||
|     val numberOfIterations: UInt = 1U, |     private val numberOfIterations: UInt = 1U, | ||||||
|     val key: Array<UByte> = emptyArray(), |     private val key: Array<UByte> = emptyArray(), | ||||||
|     val associatedData: Array<UByte> = emptyArray(), |     private val associatedData: Array<UByte> = emptyArray(), | ||||||
|     val argonType: ArgonType = ArgonType.Argon2id |     private val argonType: ArgonType = ArgonType.Argon2id | ||||||
| ) { | ) : KeyDerivationFunction { | ||||||
|     init { |     init { | ||||||
|         validateArgonParameters( |         validateArgonParameters( | ||||||
|             password, |             password, | ||||||
| @ -68,23 +69,23 @@ class Argon2( | |||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|     //We support only the latest version |     //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 |     //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() |         ((8 * parallelism) * 2).toUInt() | ||||||
|     } else { |     } else { | ||||||
|         requestedMemorySize |         requestedMemorySize | ||||||
|     } |     } | ||||||
|     val blockCount = (memorySize / (4U * parallelism.toUInt())) * (4U * parallelism.toUInt()) |     private val blockCount = (memorySize / (4U * parallelism.toUInt())) * (4U * parallelism.toUInt()) | ||||||
|     val columnCount = (blockCount / parallelism.toUInt()).toInt() |     private val columnCount = (blockCount / parallelism.toUInt()).toInt() | ||||||
|     val segmentLength = columnCount / 4 |     private val segmentLength = columnCount / 4 | ||||||
| 
 | 
 | ||||||
|     val useIndependentAddressing = argonType == ArgonType.Argon2id || argonType == ArgonType.Argon2i |     private val useIndependentAddressing = argonType == ArgonType.Argon2id || argonType == ArgonType.Argon2i | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     // State |     // State | ||||||
|     val matrix = Array(parallelism) { |     private val matrix = Array(parallelism) { | ||||||
|         Array(columnCount) { |         Array(columnCount) { | ||||||
|             Array<UByte>(1024) { 0U } |             Array<UByte>(1024) { 0U } | ||||||
|         } |         } | ||||||
| @ -225,7 +226,7 @@ class Argon2( | |||||||
|         return Pair(l, absolutePosition) |         return Pair(l, absolutePosition) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun derive(): Array<UByte> { |     override fun derive(): Array<UByte> { | ||||||
|         val h0 = Blake2b.digest( |         val h0 = Blake2b.digest( | ||||||
|             parallelism.toUInt() |             parallelism.toUInt() | ||||||
|                 .toLittleEndianUByteArray() + tagLength.toLittleEndianUByteArray() + memorySize.toLittleEndianUByteArray() + |                 .toLittleEndianUByteArray() + tagLength.toLittleEndianUByteArray() + memorySize.toLittleEndianUByteArray() + | ||||||
| @ -266,33 +267,25 @@ class Argon2( | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         //Hash the xored last blocks |         //Hash the xored last blocks | ||||||
|         println("Tag:") |  | ||||||
|         val hash = argonBlake2bArbitraryLenghtHash(result, tagLength) |         val hash = argonBlake2bArbitraryLenghtHash(result, tagLength) | ||||||
|  |         clearMatrix() | ||||||
|         return hash |         return hash | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun executeArgonWithSingleThread() { |     private fun executeArgonWithSingleThread() { | ||||||
|         for (iteration in 0 until numberOfIterations.toInt()) { |         for (iteration in 0 until numberOfIterations.toInt()) { | ||||||
|             for (slice in 0 until 4) { |             for (slice in 0 until 4) { | ||||||
|                 for (lane in 0 until parallelism.toInt()) { |                 for (lane in 0 until parallelism) { | ||||||
|                     println("Processing segment I: $iteration, S: $slice, L: $lane") |  | ||||||
|                     val segmentPosition = SegmentPosition(iteration, lane, slice) |                     val segmentPosition = SegmentPosition(iteration, lane, slice) | ||||||
|                     processSegment(segmentPosition) |                     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 iteration = segmentPosition.iteration | ||||||
|         val slice = segmentPosition.slice |         val slice = segmentPosition.slice | ||||||
|         val lane = segmentPosition.lane |         val lane = segmentPosition.lane | ||||||
| @ -308,7 +301,6 @@ class Argon2( | |||||||
|             addressBlock = populateAddressBlock(iteration, slice, lane, addressBlock, addressCounter) |             addressBlock = populateAddressBlock(iteration, slice, lane, addressBlock, addressCounter) | ||||||
|             addressCounter++ |             addressCounter++ | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         val startColumn = if (iteration == 0 && slice == 0) { |         val startColumn = if (iteration == 0 && slice == 0) { | ||||||
|             2 |             2 | ||||||
|         } else { |         } else { | ||||||
| @ -327,9 +319,6 @@ class Argon2( | |||||||
|             } else { |             } else { | ||||||
|                 column - 1 |                 column - 1 | ||||||
|             } |             } | ||||||
|             if (iteration == 1) { |  | ||||||
|                 println("Breakpoint") |  | ||||||
|             } |  | ||||||
|             val (l, z) = computeReferenceBlockIndexes( |             val (l, z) = computeReferenceBlockIndexes( | ||||||
|                 iteration, |                 iteration, | ||||||
|                 slice, |                 slice, | ||||||
| @ -337,7 +326,6 @@ class Argon2( | |||||||
|                 column, |                 column, | ||||||
|                 addressBlock |                 addressBlock | ||||||
|             ) |             ) | ||||||
| //            println("Calling compress for I: $iteration S: $slice Lane: $lane Column: $column with l: $l z: $z") |  | ||||||
|             matrix[lane][column] = |             matrix[lane][column] = | ||||||
|                 compressionFunctionG( |                 compressionFunctionG( | ||||||
|                     matrix[lane][previousColumn], |                     matrix[lane][previousColumn], | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ object Argon2Utils { | |||||||
|     const val R4 = 63 |     const val R4 = 63 | ||||||
| 
 | 
 | ||||||
|     //based on Blake2b mixRound |     //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() |         var v = input.chunked(8).map { it.fromLittleEndianArrayToULong() }.toTypedArray() | ||||||
|         v = mix(v, 0, 4, 8, 12) |         v = mix(v, 0, 4, 8, 12) | ||||||
|         v = mix(v, 1, 5, 9, 13) |         v = mix(v, 1, 5, 9, 13) | ||||||
| @ -48,7 +48,7 @@ object Argon2Utils { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     //Based on Blake2b mix |     //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[a] = (v[a] + v[b] + 2U * (v[a] and 0xFFFFFFFFUL) * (v[b] and 0xFFFFFFFFUL)) | ||||||
|         v[d] = (v[d] xor v[a]) rotateRight R1 |         v[d] = (v[d] xor v[a]) rotateRight R1 | ||||||
|         v[c] = (v[c] + v[d] + 2U * (v[c] and 0xFFFFFFFFUL) * (v[d] and 0xFFFFFFFFUL)) |         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>, |         previousBlock: Array<UByte>, | ||||||
|         referenceBlock: Array<UByte>, |         referenceBlock: Array<UByte>, | ||||||
|         currentBlock: Array<UByte>, |         currentBlock: Array<UByte>, | ||||||
| @ -115,7 +115,7 @@ object Argon2Utils { | |||||||
|         return final |         return final | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun argonBlake2bArbitraryLenghtHash(input: Array<UByte>, length: UInt): Array<UByte> { |     internal fun argonBlake2bArbitraryLenghtHash(input: Array<UByte>, length: UInt): Array<UByte> { | ||||||
|         if (length <= 64U) { |         if (length <= 64U) { | ||||||
|             return Blake2b.digest(inputMessage = length + input, hashLength = length.toInt()) |             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 |      * 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. |      * 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>, |         password: Array<UByte>, | ||||||
|         salt: Array<UByte>, |         salt: Array<UByte>, | ||||||
|         parallelism: Int , |         parallelism: Int , | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user