Adding cbc, added tests

This commit is contained in:
Ugljesa Jovanovic 2019-09-21 19:19:07 +02:00 committed by Ugljesa Jovanovic
parent 1a91d90f41
commit d3ed17b1c0
No known key found for this signature in database
GPG Key ID: 33A5F353387711A5
10 changed files with 329 additions and 26 deletions

View File

@ -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
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 21-Sep-2019
*/
expect object SRNG {
fun getRandomBytes(amount : Int) : Array<UByte>
}

View File

@ -63,4 +63,12 @@ infix fun UInt.rotateRight(places: Int): UInt {
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
infix fun ULong.rotateRight(places: Int): ULong { infix fun ULong.rotateRight(places: Int): ULong {
return (this shr places) xor (this shl (64 - places)) return (this shr places) xor (this shl (64 - places))
}
@ExperimentalUnsignedTypes
infix fun Array<UByte>.xor(other : Array<UByte>) : Array<UByte> {
if (this.size != other.size) {
throw RuntimeException("Operands of different sizes are not supported yet")
}
return this.copyOf().mapIndexed { index, it -> it xor other[index] }.toTypedArray()
} }

View File

@ -6,6 +6,8 @@ package com.ionspin.kotlin.crypto.symmetric
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
internal class Aes internal constructor(val aesKey: AesKey, val input: Array<UByte>) { internal class Aes internal constructor(val aesKey: AesKey, val input: Array<UByte>) {
companion object { companion object {
private val debug = false
private val sBox: UByteArray = private val sBox: UByteArray =
ubyteArrayOf( ubyteArrayOf(
// @formatter:off // @formatter:off
@ -317,14 +319,22 @@ internal class Aes internal constructor(val aesKey: AesKey, val input: Array<UBy
return transposedMatrix.flatten().toTypedArray() return transposedMatrix.flatten().toTypedArray()
} }
fun printState() {
private fun printState() {
if (!debug) {
return
}
println() println()
state.forEach { state.forEach {
println(it.joinToString(separator = " ") { it.toString(16) }) println(it.joinToString(separator = " ") { it.toString(16) })
} }
} }
fun printState(specific : Array<Array<UByte>>) { private fun printState(specific : Array<Array<UByte>>) {
if (!debug) {
return
}
println() println()
specific.forEach { specific.forEach {
println(it.joinToString(separator = " ") { it.toString(16) }) println(it.joinToString(separator = " ") { it.toString(16) })

View File

@ -0,0 +1,110 @@
/*
* 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.symmetric
import com.ionspin.kotlin.crypto.SRNG
import com.ionspin.kotlin.crypto.xor
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 21-Sep-2019
*/
@ExperimentalUnsignedTypes
class AesCbc (val aesKey: AesKey) {
companion object {
val BLOCK_BYTES = 16
}
var currentOutput : Array<UByte> = arrayOf()
val iv = SRNG.getRandomBytes(16)
val output = MutableList<Array<UByte>>(0) { arrayOf() }
val buffer : Array<UByte> = UByteArray(16) { 0U }.toTypedArray()
var bufferCounter = 0
// fun addData(data : UByteArray) {
// //Padding
// when {
// bufferCounter + data.size < BLOCK_BYTES -> appendToBuffer(data, bufferCounter)
// bufferCounter + data.size >= BLOCK_BYTES -> {
// val chunked = data.chunked(BLOCK_BYTES)
// chunked.forEach { chunk ->
// if (bufferCounter + chunk.size < BLOCK_BYTES) {
// appendToBuffer(chunk, bufferCounter)
// } else {
// chunk.copyInto(
// destination = buffer,
// destinationOffset = bufferCounter,
// startIndex = 0,
// endIndex = BLOCK_BYTES - bufferCounter
// )
// counter += BLOCK_BYTES
// consumeBlock(buffer)
// buffer = Array<UByte>(BLOCK_BYTES) {
// when (it) {
// in (0 until (chunk.size - (BLOCK_BYTES - bufferCounter))) -> {
// chunk[it + (BLOCK_BYTES - bufferCounter)]
// }
// else -> {
// 0U
// }
// }
//
// }
// bufferCounter = chunk.size - (BLOCK_BYTES - bufferCounter)
// }
// }
//
// }
// data.size < 16 -> {
// val paddingSize = 16 - data.size
// val padding = UByteArray(16 - data.size) { paddingSize.toUByte() }
// output += processBlock(data + padding)
// }
// data.size == 16 -> {
//
// }
// data.size > 16 -> {
//
// }
// }
//
// if (data.size < 16) {
//
// }
//
// }
private fun appendToBuffer(array: Array<UByte>, start: Int) {
array.copyInto(destination = buffer, destinationOffset = start, startIndex = 0, endIndex = array.size)
bufferCounter += array.size
}
private fun processBlock(data : Array<UByte>) : Array<UByte> {
if (currentOutput.isEmpty()) {
currentOutput = Aes.encrypt(aesKey, data xor iv)
} else {
currentOutput = Aes.encrypt(aesKey, data xor currentOutput)
}
return currentOutput
}
}

View File

@ -191,42 +191,79 @@ class AesTest {
} }
@Test @Test
fun testDecryption() { fun testEncryptionAndDecryption() {
val input = "3243f6a8885a308d313198a2e0370734"
val key = "2b7e151628aed2a6abf7158809cf4f3c"
val expectedResult = "3925841d02dc09fbdc118597196a0b32"
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toTypedArray()
val aes = Aes(AesKey.Aes128Key(key), original)
val encrypted = aes.encrypt()
assertTrue {
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toTypedArray())
}
val decrypted = Aes.decrypt(AesKey.Aes128Key(key), encrypted)
assertTrue { assertTrue {
val input = "3243f6a8885a308d313198a2e0370734"
val key = "2b7e151628aed2a6abf7158809cf4f3c"
val expectedResult = "3925841d02dc09fbdc118597196a0b32"
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toTypedArray()
val aes = Aes(AesKey.Aes128Key(key), original)
val encrypted = aes.encrypt()
assertTrue {
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toTypedArray())
}
val decrypted = Aes.decrypt(AesKey.Aes128Key(key), encrypted)
decrypted.contentEquals(original) decrypted.contentEquals(original)
} }
} assertTrue {
val input = "00112233445566778899aabbccddeeff"
val key = "000102030405060708090a0b0c0d0e0f"
val expectedResult = "69c4e0d86a7b0430d8cdb78070b4c55a"
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toTypedArray()
val aes = Aes(AesKey.Aes128Key(key), original)
val encrypted = aes.encrypt()
assertTrue {
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toTypedArray())
}
val aesDec = Aes(AesKey.Aes128Key(key), encrypted)
val decrypted = aesDec.decrypt()
assertTrue {
aesDec.expandedKey.contentDeepEquals(aes.expandedKey)
}
decrypted.contentDeepEquals(original)
}
@Test
fun testDecryption2() {
val input = "00112233445566778899aabbccddeeff"
val key = "000102030405060708090a0b0c0d0e0f"
val expectedResult = "69c4e0d86a7b0430d8cdb78070b4c55a"
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toTypedArray()
val aes = Aes(AesKey.Aes128Key(key), original)
val encrypted = aes.encrypt()
assertTrue { assertTrue {
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toTypedArray()) val input = "00112233445566778899aabbccddeeff"
val key = "000102030405060708090a0b0c0d0e0f"
val expectedResult = "69c4e0d86a7b0430d8cdb78070b4c55a"
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toTypedArray()
val encrypted = Aes.encrypt(AesKey.Aes128Key(key), original)
assertTrue {
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toTypedArray())
}
val decrypted = Aes.decrypt(AesKey.Aes128Key(key), encrypted)
decrypted.contentDeepEquals(original)
} }
val aesDec = Aes(AesKey.Aes128Key(key), encrypted)
val decrypted = aesDec.decrypt()
assertTrue { assertTrue {
aesDec.expandedKey.contentDeepEquals(aes.expandedKey) val input = "00112233445566778899aabbccddeeff"
val key = "000102030405060708090a0b0c0d0e0f1011121314151617"
val expectedResult = "dda97ca4864cdfe06eaf70a0ec0d7191"
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toTypedArray()
val encrypted = Aes.encrypt(AesKey.Aes192Key(key), original)
assertTrue {
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toTypedArray())
}
val decrypted = Aes.decrypt(AesKey.Aes192Key(key), encrypted)
decrypted.contentDeepEquals(original)
} }
assertTrue { assertTrue {
val input = "00112233445566778899aabbccddeeff"
val key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
val expectedResult = "8ea2b7ca516745bfeafc49904b496089"
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toTypedArray()
val encrypted = Aes.encrypt(AesKey.Aes256Key(key), original)
assertTrue {
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toTypedArray())
}
val decrypted = Aes.decrypt(AesKey.Aes256Key(key), encrypted)
decrypted.contentDeepEquals(original) decrypted.contentDeepEquals(original)
} }
} }
} }

View File

@ -0,0 +1,28 @@
/*
* 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
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 21-Sep-2019
*/
actual object SRNG {
actual fun getRandomBytes(amount: Int): Array<UByte> {
TODO("not implemented yet")
}
}

View File

@ -0,0 +1,28 @@
/*
* 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
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 21-Sep-2019
*/
actual object SRNG {
actual fun getRandomBytes(amount: Int): Array<UByte> {
TODO("not implemented yet")
}
}

View File

@ -0,0 +1,28 @@
/*
* 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
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 21-Sep-2019
*/
actual object SRNG {
actual fun getRandomBytes(amount: Int): Array<UByte> {
TODO("not implemented yet")
}
}

View File

@ -0,0 +1,28 @@
/*
* 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
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 21-Sep-2019
*/
actual object SRNG {
actual fun getRandomBytes(amount: Int): Array<UByte> {
TODO("not implemented yet")
}
}