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>
|
||||
}
|
@ -63,4 +63,12 @@ infix fun UInt.rotateRight(places: Int): UInt {
|
||||
@ExperimentalUnsignedTypes
|
||||
infix fun ULong.rotateRight(places: Int): ULong {
|
||||
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
|
||||
internal class Aes internal constructor(val aesKey: AesKey, val input: Array<UByte>) {
|
||||
companion object {
|
||||
private val debug = false
|
||||
|
||||
private val sBox: UByteArray =
|
||||
ubyteArrayOf(
|
||||
// @formatter:off
|
||||
@ -317,14 +319,22 @@ internal class Aes internal constructor(val aesKey: AesKey, val input: Array<UBy
|
||||
return transposedMatrix.flatten().toTypedArray()
|
||||
}
|
||||
|
||||
fun printState() {
|
||||
|
||||
|
||||
private fun printState() {
|
||||
if (!debug) {
|
||||
return
|
||||
}
|
||||
println()
|
||||
state.forEach {
|
||||
println(it.joinToString(separator = " ") { it.toString(16) })
|
||||
}
|
||||
}
|
||||
|
||||
fun printState(specific : Array<Array<UByte>>) {
|
||||
private fun printState(specific : Array<Array<UByte>>) {
|
||||
if (!debug) {
|
||||
return
|
||||
}
|
||||
println()
|
||||
specific.forEach {
|
||||
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
|
||||
fun testDecryption() {
|
||||
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)
|
||||
fun testEncryptionAndDecryption() {
|
||||
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)
|
||||
}
|
||||
}
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -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