Adding cbc, added tests
This commit is contained in:
parent
1a91d90f41
commit
d3ed17b1c0
@ -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>
|
||||||
|
}
|
@ -64,3 +64,11 @@ infix fun UInt.rotateRight(places: Int): UInt {
|
|||||||
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()
|
||||||
|
}
|
@ -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) })
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user