From 0b30215143d12a57c452a8ab2d3634d0ed3003b6 Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Sat, 13 Jun 2020 21:48:21 +0200 Subject: [PATCH] Initial AES-CTR API refactoring --- .../ionspin/kotlin/crypto/symmetric/Mode.kt | 0 .../kotlin/crypto/symmetric/aes/Aes.kt | 26 +++++++ .../kotlin/crypto/symmetric/aes/AesCtr.kt | 69 +++++++++++++++++++ .../kotlin/crypto/symmetric/AesCbcPure.kt | 43 ++++-------- .../kotlin/crypto/symmetric/AesCtrPure.kt | 23 ++++--- .../kotlin/crypto/symmetric/AesPure.kt | 26 ++----- .../kotlin/crypto/symmetric/AesCbcPure.kt | 1 + .../kotlin/crypto/symmetric/AesCtrPure.kt | 21 +----- .../kotlin/crypto/symmetric/AesPure.kt | 19 +---- .../ionspin/kotlin/crypto/symmetric/Mode.kt | 27 -------- 10 files changed, 127 insertions(+), 128 deletions(-) rename {multiplatform-crypto-delegated => multiplatform-crypto-api}/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/Mode.kt (100%) create mode 100644 multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/aes/Aes.kt create mode 100644 multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/aes/AesCtr.kt delete mode 100644 multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/Mode.kt diff --git a/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/Mode.kt b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/Mode.kt similarity index 100% rename from multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/Mode.kt rename to multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/Mode.kt diff --git a/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/aes/Aes.kt b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/aes/Aes.kt new file mode 100644 index 0000000..e1db995 --- /dev/null +++ b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/aes/Aes.kt @@ -0,0 +1,26 @@ +package com.ionspin.kotlin.crypto.symmetric.aes + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 13-Jun-2020 + */ +sealed class AesKey(val key: String, val keyLength: Int) { + val keyArray: UByteArray = key.chunked(2).map { it.toUByte(16) }.toUByteArray() + val numberOf32BitWords = keyLength / 32 + + class Aes128Key(key: String) : AesKey(key, 128) + class Aes192Key(key: String) : AesKey(key, 192) + class Aes256Key(key: String) : AesKey(key, 256) + + init { + checkKeyLength(key, keyLength) + } + + fun checkKeyLength(key: String, expectedLength: Int) { + if ((key.length / 2) != expectedLength / 8) { + throw RuntimeException("Invalid key length") + } + } +} + diff --git a/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/aes/AesCtr.kt b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/aes/AesCtr.kt new file mode 100644 index 0000000..fae3eda --- /dev/null +++ b/multiplatform-crypto-api/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/aes/AesCtr.kt @@ -0,0 +1,69 @@ +package com.ionspin.kotlin.crypto.symmetric.aes + +/** + * Created by Ugljesa Jovanovic + * ugljesa.jovanovic@ionspin.com + * on 13-Jun-2020 + */ +interface SimpleUpdateableAesCtr { + fun update(data: UByteArray) + + fun process() : UByteArray + +} + +interface AdvancedUpdateableAesCtr : SimpleUpdateableAesCtr { + fun update(data: UByteArray, counter : UByteArray) : UByteArray +} + +interface SimpleStatelessAesCtr { + + fun encrypt(aesKey: AesKey, data: UByteArray) : EncryptedDataAndInitialCounter + + fun decrypt(aesKey: AesKey, encryptedDataAndInitialCounter: EncryptedDataAndInitialCounter) : UByteArray + +} + +interface AdvancedStatelessAesCtr : SimpleStatelessAesCtr { + fun encrypt(aesKey: AesKey, data: UByteArray, initialCounter: UByteArray) : EncryptedDataAndInitialCounter +} + +data class EncryptedDataAndInitialCounter(val encryptedData : UByteArray, val initialCounter : UByteArray) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as EncryptedDataAndInitialCounter + + if (!encryptedData.contentEquals(other.encryptedData)) return false + if (!initialCounter.contentEquals(other.initialCounter)) return false + + return true + } + + override fun hashCode(): Int { + var result = encryptedData.contentHashCode() + result = 31 * result + initialCounter.contentHashCode() + return result + } +} + +data class EncryptedDataAndInitializationVector(val encryptedData : UByteArray, val initializationVector : UByteArray) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as EncryptedDataAndInitializationVector + + if (!encryptedData.contentEquals(other.encryptedData)) return false + if (!initializationVector.contentEquals(other.initializationVector)) return false + + return true + } + + override fun hashCode(): Int { + var result = encryptedData.contentHashCode() + result = 31 * result + initializationVector.contentHashCode() + return result + } +} diff --git a/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcPure.kt b/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcPure.kt index 134b671..0d58f8f 100644 --- a/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcPure.kt +++ b/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcPure.kt @@ -22,7 +22,7 @@ import com.ionspin.kotlin.crypto.util.xor /** * Advanced encryption standard with cipher block chaining and PKCS #5 * - * For bulk encryption/decryption use [AesCbcPure.encrypt] and [AesCbcPure.decrypt] + * For bulk encryption/decryption use [AesCbcDelegated.encrypt] and [AesCbcDelegated.decrypt] * * To get an instance of AesCbc and then feed it data sequentially with [addData] use [createEncryptor] and [createDecryptor] * @@ -31,7 +31,7 @@ import com.ionspin.kotlin.crypto.util.xor * on 21-Sep-2019 */ -class AesCbcPure internal constructor(val aesKey: AesKey, val mode: Mode, initializationVector: UByteArray? = null) { +class AesCbcDelegated internal constructor(val aesKey: AesKey, val mode: Mode, initializationVector: UByteArray? = null) { companion object { const val BLOCK_BYTES = 16 @@ -39,22 +39,22 @@ class AesCbcPure internal constructor(val aesKey: AesKey, val mode: Mode, initia * Creates and returns AesCbc instance that can be fed data using [addData]. Once you have submitted all * data call [encrypt] */ - fun createEncryptor(aesKey: AesKey) : AesCbcPure { - return AesCbcPure(aesKey, Mode.ENCRYPT) + fun createEncryptor(aesKey: AesKey) : AesCbcDelegated { + return AesCbcDelegated(aesKey, Mode.ENCRYPT) } /** * Creates and returns AesCbc instance that can be fed data using [addData]. Once you have submitted all * data call [decrypt] */ - fun createDecryptor(aesKey : AesKey) : AesCbcPure { - return AesCbcPure(aesKey, Mode.DECRYPT) + fun createDecryptor(aesKey : AesKey) : AesCbcDelegated { + return AesCbcDelegated(aesKey, Mode.DECRYPT) } /** * Bulk encryption, returns encrypted data and a random initialization vector */ fun encrypt(aesKey: AesKey, data: UByteArray): EncryptedDataAndInitializationVector { - val aesCbc = AesCbcPure(aesKey, Mode.ENCRYPT) + val aesCbc = AesCbcDelegated(aesKey, Mode.ENCRYPT) aesCbc.addData(data) return aesCbc.encrypt() } @@ -63,7 +63,7 @@ class AesCbcPure internal constructor(val aesKey: AesKey, val mode: Mode, initia * Bulk decryption, returns decrypted data */ fun decrypt(aesKey: AesKey, data: UByteArray, initialCounter: UByteArray? = null): UByteArray { - val aesCbc = AesCbcPure(aesKey, Mode.DECRYPT, initialCounter) + val aesCbc = AesCbcDelegated(aesKey, Mode.DECRYPT, initialCounter) aesCbc.addData(data) return aesCbc.decrypt() } @@ -198,17 +198,17 @@ class AesCbcPure internal constructor(val aesKey: AesKey, val mode: Mode, initia Mode.ENCRYPT -> { currentOutput = if (currentOutput.isEmpty()) { println("IV: $initVector") - AesPure.encrypt(aesKey, data xor initVector) + AesDelegated.encrypt(aesKey, data xor initVector) } else { - AesPure.encrypt(aesKey, data xor currentOutput) + AesDelegated.encrypt(aesKey, data xor currentOutput) } currentOutput } Mode.DECRYPT -> { if (currentOutput.isEmpty()) { - currentOutput = AesPure.decrypt(aesKey, data) xor initVector + currentOutput = AesDelegated.decrypt(aesKey, data) xor initVector } else { - currentOutput = AesPure.decrypt(aesKey, data) xor previousEncrypted + currentOutput = AesDelegated.decrypt(aesKey, data) xor previousEncrypted } previousEncrypted = data currentOutput @@ -220,22 +220,3 @@ class AesCbcPure internal constructor(val aesKey: AesKey, val mode: Mode, initia } -data class EncryptedDataAndInitializationVector(val encryptedData : UByteArray, val initilizationVector : UByteArray) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as EncryptedDataAndInitializationVector - - if (!encryptedData.contentEquals(other.encryptedData)) return false - if (!initilizationVector.contentEquals(other.initilizationVector)) return false - - return true - } - - override fun hashCode(): Int { - var result = encryptedData.contentHashCode() - result = 31 * result + initilizationVector.contentHashCode() - return result - } -} \ No newline at end of file diff --git a/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrPure.kt b/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrPure.kt index 6c2aa51..031412d 100644 --- a/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrPure.kt +++ b/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrPure.kt @@ -20,14 +20,15 @@ import com.ionspin.kotlin.bignum.Endianness import com.ionspin.kotlin.bignum.integer.BigInteger import com.ionspin.kotlin.bignum.modular.ModularBigInteger import com.ionspin.kotlin.crypto.SRNG -import com.ionspin.kotlin.crypto.symmetric.AesCtrPure.Companion.encrypt +import com.ionspin.kotlin.crypto.symmetric.AesCtrDelegated.Companion.encrypt +import com.ionspin.kotlin.crypto.symmetric.aes.AesKey import com.ionspin.kotlin.crypto.util.xor /** * * Advanced encryption standard with counter mode * - * For bulk encryption/decryption use [AesCtrPure.encrypt] and [AesCtrPure.decrypt] + * For bulk encryption/decryption use [AesCtrDelegated.encrypt] and [AesCtrDelegated.decrypt] * * To get an instance of AesCtr and then feed it data sequentially with [addData] use [createEncryptor] and [createDecryptor] * @@ -36,7 +37,7 @@ import com.ionspin.kotlin.crypto.util.xor * on 22-Sep-2019 */ -class AesCtrPure internal constructor(val aesKey: AesKey, val mode: Mode, initialCounter: UByteArray? = null) { +class AesCtrDelegated internal constructor(val aesKey: AesKey, val mode: Mode, initialCounter: UByteArray? = null) { companion object { const val BLOCK_BYTES = 16 @@ -46,21 +47,21 @@ class AesCtrPure internal constructor(val aesKey: AesKey, val mode: Mode, initia * Creates and returns AesCtr instance that can be fed data using [addData]. Once you have submitted all * data call [encrypt] */ - fun createEncryptor(aesKey: AesKey) : AesCtrPure { - return AesCtrPure(aesKey, Mode.ENCRYPT) + fun createEncryptor(aesKey: AesKey) : AesCtrDelegated { + return AesCtrDelegated(aesKey, Mode.ENCRYPT) } /** * Creates and returns AesCtr instance that can be fed data using [addData]. Once you have submitted all * data call [decrypt] */ - fun createDecryptor(aesKey : AesKey) : AesCtrPure { - return AesCtrPure(aesKey, Mode.DECRYPT) + fun createDecryptor(aesKey : AesKey) : AesCtrDelegated { + return AesCtrDelegated(aesKey, Mode.DECRYPT) } /** * Bulk encryption, returns encrypted data and a random initial counter */ fun encrypt(aesKey: AesKey, data: UByteArray): EncryptedDataAndInitialCounter { - val aesCtr = AesCtrPure(aesKey, Mode.ENCRYPT) + val aesCtr = AesCtrDelegated(aesKey, Mode.ENCRYPT) aesCtr.addData(data) return aesCtr.encrypt() } @@ -68,7 +69,7 @@ class AesCtrPure internal constructor(val aesKey: AesKey, val mode: Mode, initia * Bulk decryption, returns decrypted data */ fun decrypt(aesKey: AesKey, data: UByteArray, initialCounter: UByteArray? = null): UByteArray { - val aesCtr = AesCtrPure(aesKey, Mode.DECRYPT, initialCounter) + val aesCtr = AesCtrDelegated(aesKey, Mode.DECRYPT, initialCounter) aesCtr.addData(data) return aesCtr.decrypt() } @@ -164,10 +165,10 @@ class AesCtrPure internal constructor(val aesKey: AesKey, val mode: Mode, initia val blockCountAsByteArray = blockCount.toUByteArray(Endianness.BIG).toUByteArray().expandCounterTo16Bytes() return when (mode) { Mode.ENCRYPT -> { - AesPure.encrypt(aesKey, blockCountAsByteArray) xor data + AesDelegated.encrypt(aesKey, blockCountAsByteArray) xor data } Mode.DECRYPT -> { - AesPure.encrypt(aesKey, blockCountAsByteArray) xor data + AesDelegated.encrypt(aesKey, blockCountAsByteArray) xor data } } diff --git a/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesPure.kt b/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesPure.kt index 86ea0eb..955ced5 100644 --- a/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesPure.kt +++ b/multiplatform-crypto-delegated/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesPure.kt @@ -1,12 +1,13 @@ package com.ionspin.kotlin.crypto.symmetric +import com.ionspin.kotlin.crypto.symmetric.aes.AesKey import com.ionspin.kotlin.crypto.util.flattenToUByteArray /** * Created by Ugljesa Jovanovic (jovanovic.ugljesa@gmail.com) on 07/Sep/2019 */ -internal class AesPure internal constructor(val aesKey: AesKey, val input: UByteArray) { +internal class AesDelegated internal constructor(val aesKey: AesKey, val input: UByteArray) { companion object { private val debug = false @@ -57,11 +58,11 @@ internal class AesPure internal constructor(val aesKey: AesKey, val input: UByte val rcon: UByteArray = ubyteArrayOf(0x8DU, 0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U, 0x1BU, 0x36U) fun encrypt(aesKey: AesKey, input: UByteArray): UByteArray { - return AesPure(aesKey, input).encrypt() + return AesDelegated(aesKey, input).encrypt() } fun decrypt(aesKey: AesKey, input: UByteArray): UByteArray { - return AesPure(aesKey, input).decrypt() + return AesDelegated(aesKey, input).decrypt() } } @@ -356,23 +357,4 @@ internal class AesPure internal constructor(val aesKey: AesKey, val input: UByte } -sealed class AesKey(val key: String, val keyLength: Int) { - val keyArray: UByteArray = key.chunked(2).map { it.toUByte(16) }.toUByteArray() - val numberOf32BitWords = keyLength / 32 - - class Aes128Key(key: String) : AesKey(key, 128) - class Aes192Key(key: String) : AesKey(key, 192) - class Aes256Key(key: String) : AesKey(key, 256) - - init { - checkKeyLength(key, keyLength) - } - - fun checkKeyLength(key: String, expectedLength: Int) { - if ((key.length / 2) != expectedLength / 8) { - throw RuntimeException("Invalid key length") - } - } -} - diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcPure.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcPure.kt index 134b671..479f128 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcPure.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCbcPure.kt @@ -17,6 +17,7 @@ package com.ionspin.kotlin.crypto.symmetric import com.ionspin.kotlin.crypto.SRNG +import com.ionspin.kotlin.crypto.symmetric.aes.AesKey import com.ionspin.kotlin.crypto.util.xor /** diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrPure.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrPure.kt index 6c2aa51..963923d 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrPure.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesCtrPure.kt @@ -21,6 +21,8 @@ import com.ionspin.kotlin.bignum.integer.BigInteger import com.ionspin.kotlin.bignum.modular.ModularBigInteger import com.ionspin.kotlin.crypto.SRNG import com.ionspin.kotlin.crypto.symmetric.AesCtrPure.Companion.encrypt +import com.ionspin.kotlin.crypto.symmetric.aes.AesKey +import com.ionspin.kotlin.crypto.symmetric.aes.EncryptedDataAndInitialCounter import com.ionspin.kotlin.crypto.util.xor /** @@ -187,22 +189,3 @@ class AesCtrPure internal constructor(val aesKey: AesKey, val mode: Mode, initia } -data class EncryptedDataAndInitialCounter(val encryptedData : UByteArray, val initialCounter : UByteArray) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as EncryptedDataAndInitializationVector - - if (!encryptedData.contentEquals(other.encryptedData)) return false - if (!initialCounter.contentEquals(other.initilizationVector)) return false - - return true - } - - override fun hashCode(): Int { - var result = encryptedData.contentHashCode() - result = 31 * result + initialCounter.contentHashCode() - return result - } -} \ No newline at end of file diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesPure.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesPure.kt index 86ea0eb..2a47a24 100644 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesPure.kt +++ b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/AesPure.kt @@ -356,23 +356,6 @@ internal class AesPure internal constructor(val aesKey: AesKey, val input: UByte } -sealed class AesKey(val key: String, val keyLength: Int) { - val keyArray: UByteArray = key.chunked(2).map { it.toUByte(16) }.toUByteArray() - val numberOf32BitWords = keyLength / 32 - - class Aes128Key(key: String) : AesKey(key, 128) - class Aes192Key(key: String) : AesKey(key, 192) - class Aes256Key(key: String) : AesKey(key, 256) - - init { - checkKeyLength(key, keyLength) - } - - fun checkKeyLength(key: String, expectedLength: Int) { - if ((key.length / 2) != expectedLength / 8) { - throw RuntimeException("Invalid key length") - } - } -} + diff --git a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/Mode.kt b/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/Mode.kt deleted file mode 100644 index a0d43f9..0000000 --- a/multiplatform-crypto/src/commonMain/kotlin/com/ionspin/kotlin/crypto/symmetric/Mode.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 - -/** - * Created by Ugljesa Jovanovic - * ugljesa.jovanovic@ionspin.com - * on 18-Sep-2019 - */ - -enum class Mode { - ENCRYPT, DECRYPT -} \ No newline at end of file