Completed xsalsa20, adding chacha20
This commit is contained in:
parent
0143fe0080
commit
c7445376ca
@ -0,0 +1,38 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.symmetric
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.util.rotateLeft
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Ugljesa Jovanovic
|
||||||
|
* ugljesa.jovanovic@ionspin.com
|
||||||
|
* on 16-Jun-2020
|
||||||
|
*/
|
||||||
|
class ChaCha20Pure {
|
||||||
|
companion object {
|
||||||
|
fun quarterRound(input: UIntArray, aPosition: Int, bPosition: Int, cPosition: Int, dPosition: Int) {
|
||||||
|
input[aPosition] += input[bPosition]; input[dPosition] = input[dPosition] xor input[aPosition]; input[dPosition] = input[dPosition] rotateLeft 16
|
||||||
|
input[cPosition] += input[dPosition]; input[bPosition] = input[bPosition] xor input[cPosition]; input[bPosition] = input[bPosition] rotateLeft 12
|
||||||
|
input[aPosition] += input[bPosition]; input[dPosition] = input[dPosition] xor input[aPosition]; input[dPosition] = input[dPosition] rotateLeft 8
|
||||||
|
input[cPosition] += input[dPosition]; input[bPosition] = input[bPosition] xor input[cPosition]; input[bPosition] = input[bPosition] rotateLeft 7
|
||||||
|
}
|
||||||
|
|
||||||
|
fun rowRound(input: UIntArray) {
|
||||||
|
Salsa20Pure.quarterRound(input, 0, 1, 2, 3)
|
||||||
|
Salsa20Pure.quarterRound(input, 5, 6, 7, 4)
|
||||||
|
Salsa20Pure.quarterRound(input, 10, 11, 8, 9)
|
||||||
|
Salsa20Pure.quarterRound(input, 15, 12, 13, 14)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun columnRound(input: UIntArray) {
|
||||||
|
Salsa20Pure.quarterRound(input, 0, 4, 8, 12)
|
||||||
|
Salsa20Pure.quarterRound(input, 5, 9, 13, 1)
|
||||||
|
Salsa20Pure.quarterRound(input, 10, 14, 2, 6)
|
||||||
|
Salsa20Pure.quarterRound(input, 15, 3, 7, 11)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun doubleRound(input: UIntArray) {
|
||||||
|
columnRound(input)
|
||||||
|
rowRound(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.symmetric
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Ugljesa Jovanovic
|
||||||
|
* ugljesa.jovanovic@ionspin.com
|
||||||
|
* on 16-Jun-2020
|
||||||
|
*/
|
||||||
|
fun littleEndian(
|
||||||
|
input: UByteArray,
|
||||||
|
byte0Position: Int,
|
||||||
|
byte1Position: Int,
|
||||||
|
byte2Position: Int,
|
||||||
|
byte3Position: Int
|
||||||
|
): UInt {
|
||||||
|
var uint = 0U
|
||||||
|
uint = input[byte0Position].toUInt()
|
||||||
|
uint = uint or (input[byte1Position].toUInt() shl 8)
|
||||||
|
uint = uint or (input[byte2Position].toUInt() shl 16)
|
||||||
|
uint = uint or (input[byte3Position].toUInt() shl 24)
|
||||||
|
|
||||||
|
return uint
|
||||||
|
}
|
||||||
|
|
||||||
|
fun littleEndianInverted(
|
||||||
|
input: UIntArray,
|
||||||
|
startingPosition: Int,
|
||||||
|
output: UByteArray,
|
||||||
|
outputPosition: Int
|
||||||
|
) {
|
||||||
|
output[outputPosition] = (input[startingPosition] and 0xFFU).toUByte()
|
||||||
|
output[outputPosition + 1] = ((input[startingPosition] shr 8) and 0xFFU).toUByte()
|
||||||
|
output[outputPosition + 2] = ((input[startingPosition] shr 16) and 0xFFU).toUByte()
|
||||||
|
output[outputPosition + 3] = ((input[startingPosition] shr 24) and 0xFFU).toUByte()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun littleEndianInverted(
|
||||||
|
input: UInt,
|
||||||
|
output: UByteArray,
|
||||||
|
outputPosition: Int
|
||||||
|
) {
|
||||||
|
output[outputPosition] = (input and 0xFFU).toUByte()
|
||||||
|
output[outputPosition + 1] = ((input shr 8) and 0xFFU).toUByte()
|
||||||
|
output[outputPosition + 2] = ((input shr 16) and 0xFFU).toUByte()
|
||||||
|
output[outputPosition + 3] = ((input shr 24) and 0xFFU).toUByte()
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
package com.ionspin.kotlin.crypto.symmetric
|
package com.ionspin.kotlin.crypto.symmetric
|
||||||
|
|
||||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.xorWithBlock
|
|
||||||
import com.ionspin.kotlin.crypto.util.*
|
import com.ionspin.kotlin.crypto.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -8,7 +7,7 @@ import com.ionspin.kotlin.crypto.util.*
|
|||||||
* ugljesa.jovanovic@ionspin.com
|
* ugljesa.jovanovic@ionspin.com
|
||||||
* on 14-Jun-2020
|
* on 14-Jun-2020
|
||||||
*/
|
*/
|
||||||
class Salsa20 {
|
class Salsa20Pure {
|
||||||
companion object {
|
companion object {
|
||||||
fun quarterRound(input: UIntArray, y0position: Int, y1position: Int, y2position: Int, y3position: Int) {
|
fun quarterRound(input: UIntArray, y0position: Int, y1position: Int, y2position: Int, y3position: Int) {
|
||||||
input[y1position] = input[y1position] xor ((input[y0position] + input[y3position]) rotateLeft 7)
|
input[y1position] = input[y1position] xor ((input[y0position] + input[y3position]) rotateLeft 7)
|
||||||
@ -36,44 +35,7 @@ class Salsa20 {
|
|||||||
rowRound(input)
|
rowRound(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun littleEndian(
|
|
||||||
input: UByteArray,
|
|
||||||
byte0Position: Int,
|
|
||||||
byte1Position: Int,
|
|
||||||
byte2Position: Int,
|
|
||||||
byte3Position: Int
|
|
||||||
): UInt {
|
|
||||||
var uint = 0U
|
|
||||||
uint = input[byte0Position].toUInt()
|
|
||||||
uint = uint or (input[byte1Position].toUInt() shl 8)
|
|
||||||
uint = uint or (input[byte2Position].toUInt() shl 16)
|
|
||||||
uint = uint or (input[byte3Position].toUInt() shl 24)
|
|
||||||
|
|
||||||
return uint
|
|
||||||
}
|
|
||||||
|
|
||||||
fun littleEndianInverted(
|
|
||||||
input: UIntArray,
|
|
||||||
startingPosition: Int,
|
|
||||||
output: UByteArray,
|
|
||||||
outputPosition: Int
|
|
||||||
) {
|
|
||||||
output[outputPosition] = (input[startingPosition] and 0xFFU).toUByte()
|
|
||||||
output[outputPosition + 1] = ((input[startingPosition] shr 8) and 0xFFU).toUByte()
|
|
||||||
output[outputPosition + 2] = ((input[startingPosition] shr 16) and 0xFFU).toUByte()
|
|
||||||
output[outputPosition + 3] = ((input[startingPosition] shr 24) and 0xFFU).toUByte()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun littleEndianInverted(
|
|
||||||
input: UInt,
|
|
||||||
output: UByteArray,
|
|
||||||
outputPosition: Int
|
|
||||||
) {
|
|
||||||
output[outputPosition] = (input and 0xFFU).toUByte()
|
|
||||||
output[outputPosition + 1] = ((input shr 8) and 0xFFU).toUByte()
|
|
||||||
output[outputPosition + 2] = ((input shr 16) and 0xFFU).toUByte()
|
|
||||||
output[outputPosition + 3] = ((input shr 24) and 0xFFU).toUByte()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hash(initialState: UIntArray): UByteArray {
|
fun hash(initialState: UIntArray): UByteArray {
|
||||||
val state = initialState.copyOf()
|
val state = initialState.copyOf()
|
||||||
@ -128,23 +90,31 @@ class Salsa20 {
|
|||||||
else -> 0U
|
else -> 0U
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val blocks = message.size / 64
|
||||||
val remainder = message.size % 64
|
val remainder = message.size % 64
|
||||||
for (i in 0 until message.size - 64 step 64) {
|
for (i in 0 until blocks) {
|
||||||
hash(state).xorWithPositionsAndInsertIntoArray(0, 64, message, i, ciphertext, i)
|
hash(state).xorWithPositionsAndInsertIntoArray(0, 64, message, i * 64, ciphertext, i * 64)
|
||||||
state[8] += 1U
|
state[8] += 1U
|
||||||
if (state[8] == 0U) {
|
if (state[8] == 0U) {
|
||||||
state[9] += 1U
|
state[9] += 1U
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ( i in message.size - (64 - remainder) until message.size step 64) {
|
|
||||||
hash(state).xorWithPositionsAndInsertIntoArray(0, (64 - remainder), message, i, ciphertext, i)
|
hash(state).xorWithPositionsAndInsertIntoArray(
|
||||||
|
0, remainder,
|
||||||
|
message, (blocks - 1) * 64,
|
||||||
|
ciphertext, (blocks - 1) * 64)
|
||||||
state[8] += 1U
|
state[8] += 1U
|
||||||
if (state[8] == 0U) {
|
if (state[8] == 0U) {
|
||||||
state[9] += 1U
|
state[9] += 1U
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return ciphertext
|
return ciphertext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun decrypt(key : UByteArray, nonce: UByteArray, ciphertext: UByteArray) : UByteArray {
|
||||||
|
return encrypt(key, nonce, ciphertext)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,106 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.symmetric
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.util.fromLittleEndianArrayToUInt
|
||||||
|
import com.ionspin.kotlin.crypto.util.fromLittleEndianArrayToUIntWithPosition
|
||||||
|
import com.ionspin.kotlin.crypto.util.xorWithPositionsAndInsertIntoArray
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Ugljesa Jovanovic
|
||||||
|
* ugljesa.jovanovic@ionspin.com
|
||||||
|
* on 16-Jun-2020
|
||||||
|
*/
|
||||||
|
class XSalsa20Pure {
|
||||||
|
companion object {
|
||||||
|
fun hSalsa(key: UByteArray, nonce: UByteArray): UIntArray {
|
||||||
|
val state = UIntArray(16) {
|
||||||
|
when (it) {
|
||||||
|
0 -> Salsa20Pure.sigma0_32.fromLittleEndianArrayToUInt()
|
||||||
|
1 -> key.fromLittleEndianArrayToUIntWithPosition(0)
|
||||||
|
2 -> key.fromLittleEndianArrayToUIntWithPosition(4)
|
||||||
|
3 -> key.fromLittleEndianArrayToUIntWithPosition(8)
|
||||||
|
4 -> key.fromLittleEndianArrayToUIntWithPosition(12)
|
||||||
|
5 -> Salsa20Pure.sigma1_32.fromLittleEndianArrayToUInt()
|
||||||
|
6 -> nonce.fromLittleEndianArrayToUIntWithPosition(0)
|
||||||
|
7 -> nonce.fromLittleEndianArrayToUIntWithPosition(4)
|
||||||
|
8 -> nonce.fromLittleEndianArrayToUIntWithPosition(8)
|
||||||
|
9 -> nonce.fromLittleEndianArrayToUIntWithPosition(12)
|
||||||
|
10 -> Salsa20Pure.sigma2_32.fromLittleEndianArrayToUInt()
|
||||||
|
11 -> key.fromLittleEndianArrayToUIntWithPosition(16)
|
||||||
|
12 -> key.fromLittleEndianArrayToUIntWithPosition(20)
|
||||||
|
13 -> key.fromLittleEndianArrayToUIntWithPosition(24)
|
||||||
|
14 -> key.fromLittleEndianArrayToUIntWithPosition(28)
|
||||||
|
15 -> Salsa20Pure.sigma3_32.fromLittleEndianArrayToUInt()
|
||||||
|
else -> throw RuntimeException("Invalid index $it")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i in 0 until 10) {
|
||||||
|
Salsa20Pure.doubleRound(state)
|
||||||
|
}
|
||||||
|
val result = UIntArray(8) {
|
||||||
|
when (it) {
|
||||||
|
0 -> state[0]
|
||||||
|
1 -> state[5]
|
||||||
|
2 -> state[10]
|
||||||
|
3 -> state[15]
|
||||||
|
4 -> state[6]
|
||||||
|
5 -> state[7]
|
||||||
|
6 -> state[8]
|
||||||
|
7 -> state[9]
|
||||||
|
else -> throw RuntimeException("Invalid index $it")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun encrypt(key: UByteArray, nonce: UByteArray, message: UByteArray): UByteArray {
|
||||||
|
if (nonce.size != 24) {
|
||||||
|
throw RuntimeException("Invalid nonce size. required 192 bits, got ${nonce.size * 8}")
|
||||||
|
}
|
||||||
|
val ciphertext = UByteArray(message.size)
|
||||||
|
val hSalsaKey = hSalsa(key, nonce)
|
||||||
|
val state = UIntArray(16) {
|
||||||
|
when (it) {
|
||||||
|
0 -> Salsa20Pure.sigma0_32.fromLittleEndianArrayToUInt()
|
||||||
|
1 -> hSalsaKey[0]
|
||||||
|
2 -> hSalsaKey[1]
|
||||||
|
3 -> hSalsaKey[2]
|
||||||
|
4 -> hSalsaKey[3]
|
||||||
|
5 -> Salsa20Pure.sigma1_32.fromLittleEndianArrayToUInt()
|
||||||
|
6 -> nonce.fromLittleEndianArrayToUIntWithPosition(16) //Last 63 bit of 192 bit nonce
|
||||||
|
7 -> nonce.fromLittleEndianArrayToUIntWithPosition(20)
|
||||||
|
8 -> 0U
|
||||||
|
9 -> 0U
|
||||||
|
10 -> Salsa20Pure.sigma2_32.fromLittleEndianArrayToUInt()
|
||||||
|
11 -> hSalsaKey[4]
|
||||||
|
12 -> hSalsaKey[5]
|
||||||
|
13 -> hSalsaKey[6]
|
||||||
|
14 -> hSalsaKey[7]
|
||||||
|
15 -> Salsa20Pure.sigma3_32.fromLittleEndianArrayToUInt()
|
||||||
|
else -> 0U
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val blocks = message.size / 64
|
||||||
|
val remainder = message.size % 64
|
||||||
|
for (i in 0 until blocks) {
|
||||||
|
Salsa20Pure.hash(state).xorWithPositionsAndInsertIntoArray(0, 64, message, i * 64, ciphertext, i * 64)
|
||||||
|
state[8] += 1U
|
||||||
|
if (state[8] == 0U) {
|
||||||
|
state[9] += 1U
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Salsa20Pure.hash(state).xorWithPositionsAndInsertIntoArray(
|
||||||
|
0, remainder,
|
||||||
|
message, (blocks - 1).coerceAtLeast(0) * 64,
|
||||||
|
ciphertext, (blocks - 1).coerceAtLeast(0) * 64)
|
||||||
|
state[8] += 1U
|
||||||
|
if (state[8] == 0U) {
|
||||||
|
state[9] += 1U
|
||||||
|
}
|
||||||
|
return ciphertext
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -108,9 +108,6 @@ fun UByteArray.xorWithPositionsAndInsertIntoArray(
|
|||||||
other : UByteArray, otherStart: Int,
|
other : UByteArray, otherStart: Int,
|
||||||
targetArray: UByteArray, targetStart : Int) {
|
targetArray: UByteArray, targetStart : Int) {
|
||||||
for (i in start until end) {
|
for (i in start until end) {
|
||||||
if (targetStart + i == 131071) {
|
|
||||||
println("stop")
|
|
||||||
}
|
|
||||||
targetArray[targetStart + i] = this[start + i] xor other[otherStart + i]
|
targetArray[targetStart + i] = this[start + i] xor other[otherStart + i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ class Salsa20Test {
|
|||||||
assertTrue {
|
assertTrue {
|
||||||
val input = uintArrayOf(0U, 0U, 0U, 0U)
|
val input = uintArrayOf(0U, 0U, 0U, 0U)
|
||||||
val expected = uintArrayOf(0U, 0U, 0U, 0U)
|
val expected = uintArrayOf(0U, 0U, 0U, 0U)
|
||||||
Salsa20.quarterRound(input, 0, 1, 2, 3)
|
Salsa20Pure.quarterRound(input, 0, 1, 2, 3)
|
||||||
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
||||||
|
|
||||||
expected.contentEquals(input)
|
expected.contentEquals(input)
|
||||||
@ -37,7 +37,7 @@ class Salsa20Test {
|
|||||||
assertTrue {
|
assertTrue {
|
||||||
val input = uintArrayOf(1U, 0U, 0U, 0U)
|
val input = uintArrayOf(1U, 0U, 0U, 0U)
|
||||||
val expected = uintArrayOf(0x08008145U, 0x00000080U, 0x00010200U, 0x20500000U)
|
val expected = uintArrayOf(0x08008145U, 0x00000080U, 0x00010200U, 0x20500000U)
|
||||||
Salsa20.quarterRound(input, 0, 1, 2, 3)
|
Salsa20Pure.quarterRound(input, 0, 1, 2, 3)
|
||||||
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
||||||
|
|
||||||
expected.contentEquals(input)
|
expected.contentEquals(input)
|
||||||
@ -46,7 +46,7 @@ class Salsa20Test {
|
|||||||
assertTrue {
|
assertTrue {
|
||||||
val input = uintArrayOf(0U, 1U, 0U, 0U)
|
val input = uintArrayOf(0U, 1U, 0U, 0U)
|
||||||
val expected = uintArrayOf(0x88000100U, 0x00000001U, 0x00000200U, 0x00402000U)
|
val expected = uintArrayOf(0x88000100U, 0x00000001U, 0x00000200U, 0x00402000U)
|
||||||
Salsa20.quarterRound(input, 0, 1, 2, 3)
|
Salsa20Pure.quarterRound(input, 0, 1, 2, 3)
|
||||||
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
||||||
|
|
||||||
expected.contentEquals(input)
|
expected.contentEquals(input)
|
||||||
@ -56,14 +56,14 @@ class Salsa20Test {
|
|||||||
val input = uintArrayOf(0U, 0U, 1U, 0U)
|
val input = uintArrayOf(0U, 0U, 1U, 0U)
|
||||||
val expected = uintArrayOf(0x80040000U, 0x00000000U, 0x00000001U, 0x00002000U)
|
val expected = uintArrayOf(0x80040000U, 0x00000000U, 0x00000001U, 0x00002000U)
|
||||||
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
||||||
Salsa20.quarterRound(input, 0, 1, 2, 3)
|
Salsa20Pure.quarterRound(input, 0, 1, 2, 3)
|
||||||
expected.contentEquals(input)
|
expected.contentEquals(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue {
|
assertTrue {
|
||||||
val input = uintArrayOf(0U, 0U, 0U, 1U)
|
val input = uintArrayOf(0U, 0U, 0U, 1U)
|
||||||
val expected = uintArrayOf(0x00048044U, 0x00000080U, 0x00010000U, 0x20100001U)
|
val expected = uintArrayOf(0x00048044U, 0x00000080U, 0x00010000U, 0x20100001U)
|
||||||
Salsa20.quarterRound(input, 0, 1, 2, 3)
|
Salsa20Pure.quarterRound(input, 0, 1, 2, 3)
|
||||||
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
||||||
|
|
||||||
expected.contentEquals(input)
|
expected.contentEquals(input)
|
||||||
@ -73,7 +73,7 @@ class Salsa20Test {
|
|||||||
assertTrue {
|
assertTrue {
|
||||||
val input = uintArrayOf(0xd3917c5bU, 0x55f1c407U, 0x52a58a7aU, 0x8f887a3bU)
|
val input = uintArrayOf(0xd3917c5bU, 0x55f1c407U, 0x52a58a7aU, 0x8f887a3bU)
|
||||||
val expected = uintArrayOf(0x3e2f308cU, 0xd90a8f36U, 0x6ab2a923U, 0x2883524cU)
|
val expected = uintArrayOf(0x3e2f308cU, 0xd90a8f36U, 0x6ab2a923U, 0x2883524cU)
|
||||||
Salsa20.quarterRound(input, 0, 1, 2, 3)
|
Salsa20Pure.quarterRound(input, 0, 1, 2, 3)
|
||||||
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
||||||
expected.contentEquals(input)
|
expected.contentEquals(input)
|
||||||
}
|
}
|
||||||
@ -95,7 +95,7 @@ class Salsa20Test {
|
|||||||
0x00000001U, 0x00000200U, 0x00402000U, 0x88000100U
|
0x00000001U, 0x00000200U, 0x00402000U, 0x88000100U
|
||||||
)
|
)
|
||||||
|
|
||||||
Salsa20.rowRound(input)
|
Salsa20Pure.rowRound(input)
|
||||||
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
||||||
expected.contentEquals(input)
|
expected.contentEquals(input)
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ class Salsa20Test {
|
|||||||
0x3402e183U, 0x3c3af432U, 0x50669f96U, 0xd89ef0a8U,
|
0x3402e183U, 0x3c3af432U, 0x50669f96U, 0xd89ef0a8U,
|
||||||
0x0040ede5U, 0xb545fbceU, 0xd257ed4fU, 0x1818882dU
|
0x0040ede5U, 0xb545fbceU, 0xd257ed4fU, 0x1818882dU
|
||||||
)
|
)
|
||||||
Salsa20.rowRound(input)
|
Salsa20Pure.rowRound(input)
|
||||||
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
||||||
expected.contentEquals(input)
|
expected.contentEquals(input)
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ class Salsa20Test {
|
|||||||
0x40a04001U, 0x00000000U, 0x00000000U, 0x00000000U
|
0x40a04001U, 0x00000000U, 0x00000000U, 0x00000000U
|
||||||
)
|
)
|
||||||
|
|
||||||
Salsa20.columnRound(input)
|
Salsa20Pure.columnRound(input)
|
||||||
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
||||||
expected.contentEquals(input)
|
expected.contentEquals(input)
|
||||||
}
|
}
|
||||||
@ -153,7 +153,7 @@ class Salsa20Test {
|
|||||||
0x789b010cU, 0xd195a681U, 0xeb7d5504U, 0xa774135cU,
|
0x789b010cU, 0xd195a681U, 0xeb7d5504U, 0xa774135cU,
|
||||||
0x481c2027U, 0x53a8e4b5U, 0x4c1f89c5U, 0x3f78c9c8U
|
0x481c2027U, 0x53a8e4b5U, 0x4c1f89c5U, 0x3f78c9c8U
|
||||||
)
|
)
|
||||||
Salsa20.columnRound(input)
|
Salsa20Pure.columnRound(input)
|
||||||
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
||||||
expected.contentEquals(input)
|
expected.contentEquals(input)
|
||||||
}
|
}
|
||||||
@ -175,7 +175,7 @@ class Salsa20Test {
|
|||||||
0x20500000U, 0xa0000040U, 0x0008180aU, 0x612a8020U
|
0x20500000U, 0xa0000040U, 0x0008180aU, 0x612a8020U
|
||||||
)
|
)
|
||||||
|
|
||||||
Salsa20.doubleRound(input)
|
Salsa20Pure.doubleRound(input)
|
||||||
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
||||||
expected.contentEquals(input)
|
expected.contentEquals(input)
|
||||||
}
|
}
|
||||||
@ -193,7 +193,7 @@ class Salsa20Test {
|
|||||||
0xca531c29U, 0x8e7943dbU, 0xac1680cdU, 0xd503ca00U,
|
0xca531c29U, 0x8e7943dbU, 0xac1680cdU, 0xd503ca00U,
|
||||||
0xa74b2ad6U, 0xbc331c5cU, 0x1dda24c7U, 0xee928277U
|
0xa74b2ad6U, 0xbc331c5cU, 0x1dda24c7U, 0xee928277U
|
||||||
)
|
)
|
||||||
Salsa20.doubleRound(input)
|
Salsa20Pure.doubleRound(input)
|
||||||
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
println("Result ${input.joinToString { it.toString(16).padStart(2, '0') }}")
|
||||||
expected.contentEquals(input)
|
expected.contentEquals(input)
|
||||||
}
|
}
|
||||||
@ -204,14 +204,14 @@ class Salsa20Test {
|
|||||||
assertTrue {
|
assertTrue {
|
||||||
val input = ubyteArrayOf(86U, 75U, 30U, 9U)
|
val input = ubyteArrayOf(86U, 75U, 30U, 9U)
|
||||||
val expected = 0x091e4b56U
|
val expected = 0x091e4b56U
|
||||||
val result = Salsa20.littleEndian(input, 0, 1, 2, 3)
|
val result = littleEndian(input, 0, 1, 2, 3)
|
||||||
result == expected
|
result == expected
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue {
|
assertTrue {
|
||||||
val input = ubyteArrayOf(255U, 255U, 255U, 250U)
|
val input = ubyteArrayOf(255U, 255U, 255U, 250U)
|
||||||
val expected = 0xFAFFFFFFU
|
val expected = 0xFAFFFFFFU
|
||||||
val result = Salsa20.littleEndian(input, 0, 1, 2, 3)
|
val result = littleEndian(input, 0, 1, 2, 3)
|
||||||
result == expected
|
result == expected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,7 +222,7 @@ class Salsa20Test {
|
|||||||
val expected = ubyteArrayOf(86U, 75U, 30U, 9U)
|
val expected = ubyteArrayOf(86U, 75U, 30U, 9U)
|
||||||
val input = uintArrayOf(0x091e4b56U)
|
val input = uintArrayOf(0x091e4b56U)
|
||||||
val result = UByteArray(4)
|
val result = UByteArray(4)
|
||||||
Salsa20.littleEndianInverted(input, 0, result, 0)
|
littleEndianInverted(input, 0, result, 0)
|
||||||
result.contentEquals(expected)
|
result.contentEquals(expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +230,7 @@ class Salsa20Test {
|
|||||||
val expected = ubyteArrayOf(255U, 255U, 255U, 250U)
|
val expected = ubyteArrayOf(255U, 255U, 255U, 250U)
|
||||||
val input = uintArrayOf(0xFAFFFFFFU)
|
val input = uintArrayOf(0xFAFFFFFFU)
|
||||||
val result = UByteArray(4)
|
val result = UByteArray(4)
|
||||||
Salsa20.littleEndianInverted(input, 0, result, 0)
|
littleEndianInverted(input, 0, result, 0)
|
||||||
result.contentEquals(expected)
|
result.contentEquals(expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,7 +241,7 @@ class Salsa20Test {
|
|||||||
val expected = ubyteArrayOf(86U, 75U, 30U, 9U)
|
val expected = ubyteArrayOf(86U, 75U, 30U, 9U)
|
||||||
val input = 0x091e4b56U
|
val input = 0x091e4b56U
|
||||||
val result = UByteArray(4)
|
val result = UByteArray(4)
|
||||||
Salsa20.littleEndianInverted(input, result, 0)
|
littleEndianInverted(input, result, 0)
|
||||||
result.contentEquals(expected)
|
result.contentEquals(expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,7 +249,7 @@ class Salsa20Test {
|
|||||||
val expected = ubyteArrayOf(255U, 255U, 255U, 250U)
|
val expected = ubyteArrayOf(255U, 255U, 255U, 250U)
|
||||||
val input = 0xFAFFFFFFU
|
val input = 0xFAFFFFFFU
|
||||||
val result = UByteArray(4)
|
val result = UByteArray(4)
|
||||||
Salsa20.littleEndianInverted(input, result, 0)
|
littleEndianInverted(input, result, 0)
|
||||||
result.contentEquals(expected)
|
result.contentEquals(expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,7 +269,7 @@ class Salsa20Test {
|
|||||||
0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U,
|
0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U,
|
||||||
0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U
|
0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U
|
||||||
)
|
)
|
||||||
val result = Salsa20.hash(input.fromLittleEndianToUInt())
|
val result = Salsa20Pure.hash(input.fromLittleEndianToUInt())
|
||||||
input.contentEquals(expected)
|
input.contentEquals(expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,7 +286,7 @@ class Salsa20Test {
|
|||||||
118U, 40U, 152U, 157U, 180U, 57U, 27U, 94U, 107U, 42U, 236U, 35U, 27U, 111U, 114U, 114U,
|
118U, 40U, 152U, 157U, 180U, 57U, 27U, 94U, 107U, 42U, 236U, 35U, 27U, 111U, 114U, 114U,
|
||||||
219U, 236U, 232U, 135U, 111U, 155U, 110U, 18U, 24U, 232U, 95U, 158U, 179U, 19U, 48U, 202U
|
219U, 236U, 232U, 135U, 111U, 155U, 110U, 18U, 24U, 232U, 95U, 158U, 179U, 19U, 48U, 202U
|
||||||
)
|
)
|
||||||
val result = Salsa20.hash(input.fromLittleEndianToUInt())
|
val result = Salsa20Pure.hash(input.fromLittleEndianToUInt())
|
||||||
result.contentEquals(expected)
|
result.contentEquals(expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,7 +304,7 @@ class Salsa20Test {
|
|||||||
122U, 127U, 195U, 185U, 185U, 204U, 188U, 90U, 245U, 9U, 183U, 248U, 226U, 85U, 245U, 104U
|
122U, 127U, 195U, 185U, 185U, 204U, 188U, 90U, 245U, 9U, 183U, 248U, 226U, 85U, 245U, 104U
|
||||||
)
|
)
|
||||||
val result = (0 until 1_000_000).fold(input) { acc, _ ->
|
val result = (0 until 1_000_000).fold(input) { acc, _ ->
|
||||||
Salsa20.hash(acc.fromLittleEndianToUInt())
|
Salsa20Pure.hash(acc.fromLittleEndianToUInt())
|
||||||
}
|
}
|
||||||
result.contentEquals(expected)
|
result.contentEquals(expected)
|
||||||
}
|
}
|
||||||
@ -326,7 +326,7 @@ class Salsa20Test {
|
|||||||
104U, 197U, 7U, 225U, 197U, 153U, 31U, 2U, 102U, 78U, 76U, 176U, 84U, 245U, 246U, 184U,
|
104U, 197U, 7U, 225U, 197U, 153U, 31U, 2U, 102U, 78U, 76U, 176U, 84U, 245U, 246U, 184U,
|
||||||
177U, 160U, 133U, 130U, 6U, 72U, 149U, 119U, 192U, 195U, 132U, 236U, 234U, 103U, 246U, 74U
|
177U, 160U, 133U, 130U, 6U, 72U, 149U, 119U, 192U, 195U, 132U, 236U, 234U, 103U, 246U, 74U
|
||||||
)
|
)
|
||||||
val result = Salsa20.expansion32(k0 + k1, n)
|
val result = Salsa20Pure.expansion32(k0 + k1, n)
|
||||||
result.contentEquals(expected)
|
result.contentEquals(expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,7 +337,7 @@ class Salsa20Test {
|
|||||||
134U, 85U, 110U, 246U, 161U, 163U, 43U, 235U, 231U, 94U, 171U, 51U, 145U, 214U, 112U, 29U,
|
134U, 85U, 110U, 246U, 161U, 163U, 43U, 235U, 231U, 94U, 171U, 51U, 145U, 214U, 112U, 29U,
|
||||||
14U, 232U, 5U, 16U, 151U, 140U, 183U, 141U, 171U, 9U, 122U, 181U, 104U, 182U, 177U, 193U
|
14U, 232U, 5U, 16U, 151U, 140U, 183U, 141U, 171U, 9U, 122U, 181U, 104U, 182U, 177U, 193U
|
||||||
)
|
)
|
||||||
val result = Salsa20.expansion16(k0, n)
|
val result = Salsa20Pure.expansion16(k0, n)
|
||||||
result.contentEquals(expected)
|
result.contentEquals(expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -359,7 +359,7 @@ class Salsa20Test {
|
|||||||
"CC32B15B93784A36E56A76CC64BC8477"
|
"CC32B15B93784A36E56A76CC64BC8477"
|
||||||
).toLowerCase()
|
).toLowerCase()
|
||||||
|
|
||||||
val ciphertext = Salsa20.encrypt(key, nonce, UByteArray(512) { 0U })
|
val ciphertext = Salsa20Pure.encrypt(key, nonce, UByteArray(512) { 0U })
|
||||||
ciphertext.toHexString().toLowerCase().startsWith(expectedStartsWith) &&
|
ciphertext.toHexString().toLowerCase().startsWith(expectedStartsWith) &&
|
||||||
ciphertext.toHexString().toLowerCase().endsWith(endsWith)
|
ciphertext.toHexString().toLowerCase().endsWith(endsWith)
|
||||||
}
|
}
|
||||||
@ -379,7 +379,7 @@ class Salsa20Test {
|
|||||||
"529C4158B7FF41EE854B1235373988C8"
|
"529C4158B7FF41EE854B1235373988C8"
|
||||||
).toLowerCase()
|
).toLowerCase()
|
||||||
|
|
||||||
val ciphertext = Salsa20.encrypt(key, nonce, UByteArray(131072) { 0U })
|
val ciphertext = Salsa20Pure.encrypt(key, nonce, UByteArray(131072) { 0U })
|
||||||
println(ciphertext.slice(0 until 64).toTypedArray().toHexString())
|
println(ciphertext.slice(0 until 64).toTypedArray().toHexString())
|
||||||
println(ciphertext.slice(131008 until 131072).toTypedArray().toHexString())
|
println(ciphertext.slice(131008 until 131072).toTypedArray().toHexString())
|
||||||
ciphertext.slice(0 until 64).toTypedArray().toHexString().toLowerCase().startsWith(expectedStartsWith) &&
|
ciphertext.slice(0 until 64).toTypedArray().toHexString().toLowerCase().startsWith(expectedStartsWith) &&
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.symmetric
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Ugljesa Jovanovic
|
||||||
|
* ugljesa.jovanovic@ionspin.com
|
||||||
|
* on 16-Jun-2020
|
||||||
|
*/
|
||||||
|
class XSalsa20Test {
|
||||||
|
@Test
|
||||||
|
fun testXSalsa20() {
|
||||||
|
// values from https://go.googlesource.com/crypto/+/master/salsa20/salsa20_test.go xSalsa20TestData
|
||||||
|
assertTrue {
|
||||||
|
val message = "Hello world!".encodeToUByteArray()
|
||||||
|
val nonce = "24-byte nonce for xsalsa".encodeToUByteArray()
|
||||||
|
val key = "this is 32-byte key for xsalsa20".encodeToUByteArray()
|
||||||
|
val expected = ubyteArrayOf(0x00U, 0x2dU, 0x45U, 0x13U, 0x84U, 0x3fU, 0xc2U, 0x40U, 0xc4U, 0x01U, 0xe5U, 0x41U)
|
||||||
|
val result = XSalsa20Pure.encrypt(key, nonce, message)
|
||||||
|
result.contentEquals(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue {
|
||||||
|
val message = UByteArray(64) { 0U }
|
||||||
|
val nonce = "24-byte nonce for xsalsa".encodeToUByteArray()
|
||||||
|
val key = "this is 32-byte key for xsalsa20".encodeToUByteArray()
|
||||||
|
val expected = ubyteArrayOf(
|
||||||
|
0x48U, 0x48U, 0x29U, 0x7fU, 0xebU, 0x1fU, 0xb5U, 0x2fU, 0xb6U,
|
||||||
|
0x6dU, 0x81U, 0x60U, 0x9bU, 0xd5U, 0x47U, 0xfaU, 0xbcU, 0xbeU, 0x70U,
|
||||||
|
0x26U, 0xedU, 0xc8U, 0xb5U, 0xe5U, 0xe4U, 0x49U, 0xd0U, 0x88U, 0xbfU,
|
||||||
|
0xa6U, 0x9cU, 0x08U, 0x8fU, 0x5dU, 0x8dU, 0xa1U, 0xd7U, 0x91U, 0x26U,
|
||||||
|
0x7cU, 0x2cU, 0x19U, 0x5aU, 0x7fU, 0x8cU, 0xaeU, 0x9cU, 0x4bU, 0x40U,
|
||||||
|
0x50U, 0xd0U, 0x8cU, 0xe6U, 0xd3U, 0xa1U, 0x51U, 0xecU, 0x26U, 0x5fU,
|
||||||
|
0x3aU, 0x58U, 0xe4U, 0x76U, 0x48U
|
||||||
|
)
|
||||||
|
val result = XSalsa20Pure.encrypt(key, nonce, message)
|
||||||
|
result.contentEquals(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user