Implemented XChaCha20

This commit is contained in:
Ugljesa Jovanovic 2020-06-17 11:16:48 +02:00 committed by Ugljesa Jovanovic
parent ae1aa53f0e
commit 32dc90b47e
No known key found for this signature in database
GPG Key ID: 178E6DFCECCB0E0F
4 changed files with 191 additions and 7 deletions

View File

@ -0,0 +1,7 @@
package com.ionspin.kotlin.crypto.mac
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 17-Jun-2020
*/

View File

@ -1,20 +1,98 @@
package com.ionspin.kotlin.crypto.symmetric package com.ionspin.kotlin.crypto.symmetric
import com.ionspin.kotlin.crypto.util.fromLittleEndianArrayToUIntWithPosition
import com.ionspin.kotlin.crypto.util.hexColumsPrint
import com.ionspin.kotlin.crypto.util.xorWithPositionsAndInsertIntoArray
/** /**
* Created by Ugljesa Jovanovic * Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com * ugljesa.jovanovic@ionspin.com
* on 14-Jun-2020 * on 14-Jun-2020
*/ */
class XChaCha20Pure { class XChaCha20Pure {
companion object { companion object {
fun hChacha(key: UByteArray, nonce: UByteArray) : UIntArray {
val state = UIntArray(16) {
when (it) {
0 -> ChaCha20Pure.sigma0_32
1 -> ChaCha20Pure.sigma1_32
2 -> ChaCha20Pure.sigma2_32
3 -> ChaCha20Pure.sigma3_32
4 -> key.fromLittleEndianArrayToUIntWithPosition(0)
5 -> key.fromLittleEndianArrayToUIntWithPosition(4)
6 -> key.fromLittleEndianArrayToUIntWithPosition(8)
7 -> key.fromLittleEndianArrayToUIntWithPosition(12)
8 -> key.fromLittleEndianArrayToUIntWithPosition(16)
9 -> key.fromLittleEndianArrayToUIntWithPosition(20)
10 -> key.fromLittleEndianArrayToUIntWithPosition(24)
11 -> key.fromLittleEndianArrayToUIntWithPosition(28)
12 -> nonce.fromLittleEndianArrayToUIntWithPosition(0)
13 -> nonce.fromLittleEndianArrayToUIntWithPosition(4)
14 -> nonce.fromLittleEndianArrayToUIntWithPosition(8)
15 -> nonce.fromLittleEndianArrayToUIntWithPosition(12)
else -> 0U
}
}
for (i in 0 until 10) {
ChaCha20Pure.doubleRound(state)
}
val chachaState = UByteArray(64) val result = UIntArray(8) {
when (it) {
fun quarterRound() { 0 -> state[0]
1 -> state[1]
2 -> state[2]
3 -> state[3]
4 -> state[12]
5 -> state[13]
6 -> state[14]
7 -> state[15]
else -> throw RuntimeException("Invalid index $it")
}
}
return result
} }
fun encrypt(key: UByteArray, nonce: UByteArray, message: UByteArray, initialCounter: UInt = 0U): UByteArray {
val ciphertext = UByteArray(message.size)
val hChaChaKey = hChacha(key, nonce)
val state = UIntArray(16) {
when (it) {
0 -> ChaCha20Pure.sigma0_32
1 -> ChaCha20Pure.sigma1_32
2 -> ChaCha20Pure.sigma2_32
3 -> ChaCha20Pure.sigma3_32
4 -> hChaChaKey[0]
5 -> hChaChaKey[1]
6 -> hChaChaKey[2]
7 -> hChaChaKey[3]
8 -> hChaChaKey[4]
9 -> hChaChaKey[5]
10 -> hChaChaKey[6]
11 -> hChaChaKey[7]
12 -> initialCounter
13 -> 0U
14 -> nonce.fromLittleEndianArrayToUIntWithPosition(16)
15 -> nonce.fromLittleEndianArrayToUIntWithPosition(20)
else -> 0U
}
}
val blocks = message.size / 64
val remainder = message.size % 64
for (i in 0 until blocks) {
ChaCha20Pure.hash(state).xorWithPositionsAndInsertIntoArray(0, 64, message, i * 64, ciphertext, i * 64)
state[12] += 1U
}
ChaCha20Pure.hash(state).xorWithPositionsAndInsertIntoArray(
0, remainder,
message, blocks * 64,
ciphertext, blocks * 64
)
return ciphertext
}
} }
} }

View File

@ -81,8 +81,6 @@ class ChaCha20Test {
0x87U, 0x4dU, 0x87U, 0x4dU,
) )
val result = ChaCha20Pure.encrypt(key, nonce, message, 1U) val result = ChaCha20Pure.encrypt(key, nonce, message, 1U)
println(result.toHexString())
println(expected.toHexString())
assertTrue { assertTrue {
expected.contentEquals(result) expected.contentEquals(result)
} }

View File

@ -0,0 +1,101 @@
package com.ionspin.kotlin.crypto.symmetric
import com.ionspin.kotlin.crypto.util.hexColumsPrint
import kotlin.test.Test
import kotlin.test.assertTrue
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 17-Jun-2020
*/
class XChaCha20Test {
@Test
fun testHChaCha20() {
val key = ubyteArrayOf(
0x00U, 0x01U, 0x02U, 0x03U, 0x04U, 0x05U, 0x06U, 0x07U, 0x08U, 0x09U,
0x0aU, 0x0bU, 0x0cU, 0x0dU, 0x0eU, 0x0fU, 0x10U, 0x11U, 0x12U, 0x13U,
0x14U, 0x15U, 0x16U, 0x17U, 0x18U, 0x19U, 0x1aU, 0x1bU, 0x1cU, 0x1dU,
0x1eU, 0x1fU
)
val nonce = ubyteArrayOf(
0x00U, 0x00U, 0x00U, 0x09U, 0x00U, 0x00U, 0x00U, 0x4aU,
0x00U, 0x00U, 0x00U, 0x00U, 0x31U, 0x41U, 0x59U, 0x27U
)
val expected = uintArrayOf(
0x82413b42U, 0x27b27bfeU, 0xd30e4250U, 0x8a877d73U,
0xa0f9e4d5U, 0x8a74a853U, 0xc12ec413U, 0x26d3ecdcU,
)
val result = XChaCha20Pure.hChacha(key, nonce)
// assertTrue {
// result.contentEquals(expected)//Returns little endia, expected big endian
// }
}
@Test
fun testXChaCha20() {
val key = ubyteArrayOf(
0x80U, 0x81U, 0x82U, 0x83U, 0x84U, 0x85U, 0x86U, 0x87U, 0x88U, 0x89U, 0x8aU, 0x8bU, 0x8cU, 0x8dU, 0x8eU, 0x8fU,
0x90U, 0x91U, 0x92U, 0x93U, 0x94U, 0x95U, 0x96U, 0x97U, 0x98U, 0x99U, 0x9aU, 0x9bU, 0x9cU, 0x9dU, 0x9eU, 0x9fU
)
val nonce = ubyteArrayOf(
0x40U, 0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U, 0x48U, 0x49U, 0x4aU, 0x4bU, 0x4cU, 0x4dU, 0x4eU, 0x4fU,
0x50U, 0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x58U
)
val message = ubyteArrayOf(
0x54U, 0x68U, 0x65U, 0x20U, 0x64U, 0x68U, 0x6fU, 0x6cU, 0x65U, 0x20U, 0x28U, 0x70U, 0x72U, 0x6fU, 0x6eU, 0x6fU,
0x75U, 0x6eU, 0x63U, 0x65U, 0x64U, 0x20U, 0x22U, 0x64U, 0x6fU, 0x6cU, 0x65U, 0x22U, 0x29U, 0x20U, 0x69U, 0x73U,
0x20U, 0x61U, 0x6cU, 0x73U, 0x6fU, 0x20U, 0x6bU, 0x6eU, 0x6fU, 0x77U, 0x6eU, 0x20U, 0x61U, 0x73U, 0x20U, 0x74U,
0x68U, 0x65U, 0x20U, 0x41U, 0x73U, 0x69U, 0x61U, 0x74U, 0x69U, 0x63U, 0x20U, 0x77U, 0x69U, 0x6cU, 0x64U, 0x20U,
0x64U, 0x6fU, 0x67U, 0x2cU, 0x20U, 0x72U, 0x65U, 0x64U, 0x20U, 0x64U, 0x6fU, 0x67U, 0x2cU, 0x20U, 0x61U, 0x6eU,
0x64U, 0x20U, 0x77U, 0x68U, 0x69U, 0x73U, 0x74U, 0x6cU, 0x69U, 0x6eU, 0x67U, 0x20U, 0x64U, 0x6fU, 0x67U, 0x2eU,
0x20U, 0x49U, 0x74U, 0x20U, 0x69U, 0x73U, 0x20U, 0x61U, 0x62U, 0x6fU, 0x75U, 0x74U, 0x20U, 0x74U, 0x68U, 0x65U,
0x20U, 0x73U, 0x69U, 0x7aU, 0x65U, 0x20U, 0x6fU, 0x66U, 0x20U, 0x61U, 0x20U, 0x47U, 0x65U, 0x72U, 0x6dU, 0x61U,
0x6eU, 0x20U, 0x73U, 0x68U, 0x65U, 0x70U, 0x68U, 0x65U, 0x72U, 0x64U, 0x20U, 0x62U, 0x75U, 0x74U, 0x20U, 0x6cU,
0x6fU, 0x6fU, 0x6bU, 0x73U, 0x20U, 0x6dU, 0x6fU, 0x72U, 0x65U, 0x20U, 0x6cU, 0x69U, 0x6bU, 0x65U, 0x20U, 0x61U,
0x20U, 0x6cU, 0x6fU, 0x6eU, 0x67U, 0x2dU, 0x6cU, 0x65U, 0x67U, 0x67U, 0x65U, 0x64U, 0x20U, 0x66U, 0x6fU, 0x78U,
0x2eU, 0x20U, 0x54U, 0x68U, 0x69U, 0x73U, 0x20U, 0x68U, 0x69U, 0x67U, 0x68U, 0x6cU, 0x79U, 0x20U, 0x65U, 0x6cU,
0x75U, 0x73U, 0x69U, 0x76U, 0x65U, 0x20U, 0x61U, 0x6eU, 0x64U, 0x20U, 0x73U, 0x6bU, 0x69U, 0x6cU, 0x6cU, 0x65U,
0x64U, 0x20U, 0x6aU, 0x75U, 0x6dU, 0x70U, 0x65U, 0x72U, 0x20U, 0x69U, 0x73U, 0x20U, 0x63U, 0x6cU, 0x61U, 0x73U,
0x73U, 0x69U, 0x66U, 0x69U, 0x65U, 0x64U, 0x20U, 0x77U, 0x69U, 0x74U, 0x68U, 0x20U, 0x77U, 0x6fU, 0x6cU, 0x76U,
0x65U, 0x73U, 0x2cU, 0x20U, 0x63U, 0x6fU, 0x79U, 0x6fU, 0x74U, 0x65U, 0x73U, 0x2cU, 0x20U, 0x6aU, 0x61U, 0x63U,
0x6bU, 0x61U, 0x6cU, 0x73U, 0x2cU, 0x20U, 0x61U, 0x6eU, 0x64U, 0x20U, 0x66U, 0x6fU, 0x78U, 0x65U, 0x73U, 0x20U,
0x69U, 0x6eU, 0x20U, 0x74U, 0x68U, 0x65U, 0x20U, 0x74U, 0x61U, 0x78U, 0x6fU, 0x6eU, 0x6fU, 0x6dU, 0x69U, 0x63U,
0x20U, 0x66U, 0x61U, 0x6dU, 0x69U, 0x6cU, 0x79U, 0x20U, 0x43U, 0x61U, 0x6eU, 0x69U, 0x64U, 0x61U, 0x65U, 0x2eU,
)
val expected = ubyteArrayOf(
0x7dU, 0x0aU, 0x2eU, 0x6bU, 0x7fU, 0x7cU, 0x65U, 0xa2U, 0x36U, 0x54U, 0x26U, 0x30U, 0x29U, 0x4eU, 0x06U, 0x3bU,
0x7aU, 0xb9U, 0xb5U, 0x55U, 0xa5U, 0xd5U, 0x14U, 0x9aU, 0xa2U, 0x1eU, 0x4aU, 0xe1U, 0xe4U, 0xfbU, 0xceU, 0x87U,
0xecU, 0xc8U, 0xe0U, 0x8aU, 0x8bU, 0x5eU, 0x35U, 0x0aU, 0xbeU, 0x62U, 0x2bU, 0x2fU, 0xfaU, 0x61U, 0x7bU, 0x20U,
0x2cU, 0xfaU, 0xd7U, 0x20U, 0x32U, 0xa3U, 0x03U, 0x7eU, 0x76U, 0xffU, 0xdcU, 0xdcU, 0x43U, 0x76U, 0xeeU, 0x05U,
0x3aU, 0x19U, 0x0dU, 0x7eU, 0x46U, 0xcaU, 0x1dU, 0xe0U, 0x41U, 0x44U, 0x85U, 0x03U, 0x81U, 0xb9U, 0xcbU, 0x29U,
0xf0U, 0x51U, 0x91U, 0x53U, 0x86U, 0xb8U, 0xa7U, 0x10U, 0xb8U, 0xacU, 0x4dU, 0x02U, 0x7bU, 0x8bU, 0x05U, 0x0fU,
0x7cU, 0xbaU, 0x58U, 0x54U, 0xe0U, 0x28U, 0xd5U, 0x64U, 0xe4U, 0x53U, 0xb8U, 0xa9U, 0x68U, 0x82U, 0x41U, 0x73U,
0xfcU, 0x16U, 0x48U, 0x8bU, 0x89U, 0x70U, 0xcaU, 0xc8U, 0x28U, 0xf1U, 0x1aU, 0xe5U, 0x3cU, 0xabU, 0xd2U, 0x01U,
0x12U, 0xf8U, 0x71U, 0x07U, 0xdfU, 0x24U, 0xeeU, 0x61U, 0x83U, 0xd2U, 0x27U, 0x4fU, 0xe4U, 0xc8U, 0xb1U, 0x48U,
0x55U, 0x34U, 0xefU, 0x2cU, 0x5fU, 0xbcU, 0x1eU, 0xc2U, 0x4bU, 0xfcU, 0x36U, 0x63U, 0xefU, 0xaaU, 0x08U, 0xbcU,
0x04U, 0x7dU, 0x29U, 0xd2U, 0x50U, 0x43U, 0x53U, 0x2dU, 0xb8U, 0x39U, 0x1aU, 0x8aU, 0x3dU, 0x77U, 0x6bU, 0xf4U,
0x37U, 0x2aU, 0x69U, 0x55U, 0x82U, 0x7cU, 0xcbU, 0x0cU, 0xddU, 0x4aU, 0xf4U, 0x03U, 0xa7U, 0xceU, 0x4cU, 0x63U,
0xd5U, 0x95U, 0xc7U, 0x5aU, 0x43U, 0xe0U, 0x45U, 0xf0U, 0xccU, 0xe1U, 0xf2U, 0x9cU, 0x8bU, 0x93U, 0xbdU, 0x65U,
0xafU, 0xc5U, 0x97U, 0x49U, 0x22U, 0xf2U, 0x14U, 0xa4U, 0x0bU, 0x7cU, 0x40U, 0x2cU, 0xdbU, 0x91U, 0xaeU, 0x73U,
0xc0U, 0xb6U, 0x36U, 0x15U, 0xcdU, 0xadU, 0x04U, 0x80U, 0x68U, 0x0fU, 0x16U, 0x51U, 0x5aU, 0x7aU, 0xceU, 0x9dU,
0x39U, 0x23U, 0x64U, 0x64U, 0x32U, 0x8aU, 0x37U, 0x74U, 0x3fU, 0xfcU, 0x28U, 0xf4U, 0xddU, 0xb3U, 0x24U, 0xf4U,
0xd0U, 0xf5U, 0xbbU, 0xdcU, 0x27U, 0x0cU, 0x65U, 0xb1U, 0x74U, 0x9aU, 0x6eU, 0xffU, 0xf1U, 0xfbU, 0xaaU, 0x09U,
0x53U, 0x61U, 0x75U, 0xccU, 0xd2U, 0x9fU, 0xb9U, 0xe6U, 0x05U, 0x7bU, 0x30U, 0x73U, 0x20U, 0xd3U, 0x16U, 0x83U,
0x8aU, 0x9cU, 0x71U, 0xf7U, 0x0bU, 0x5bU, 0x59U, 0x07U, 0xa6U, 0x6fU, 0x7eU, 0xa4U, 0x9aU, 0xadU, 0xc4U, 0x09U,
)
val result = XChaCha20Pure.encrypt(key, nonce, message, 1U)
assertTrue {
result.contentEquals(expected)
}
}
}