Removing direct aes cbc and ctr, to reduce foot shooting incidents, introducing aes256-gcm
This commit is contained in:
parent
0b30215143
commit
5c10d3abf4
11
README.md
11
README.md
@ -64,18 +64,14 @@ It's not peer reviewed, not guaranteed to be bug free, and not guaranteed to be
|
|||||||
* Blake2b
|
* Blake2b
|
||||||
* SHA512
|
* SHA512
|
||||||
* SHA256
|
* SHA256
|
||||||
|
|
||||||
### Symmetric cipher
|
|
||||||
* AES
|
|
||||||
* Modes: CBC, CTR
|
|
||||||
|
|
||||||
### Key Derivation
|
### Key Derivation
|
||||||
|
|
||||||
* Argon2
|
* Argon2
|
||||||
|
|
||||||
### AEAD
|
### Authenticated symmetric encryption (AEAD)
|
||||||
|
|
||||||
TODO()
|
* TODO
|
||||||
|
|
||||||
|
|
||||||
### Delegated flavor dependancy table
|
### Delegated flavor dependancy table
|
||||||
@ -86,8 +82,7 @@ The following table describes which library is used for particular cryptographic
|
|||||||
| Blake2b | LazySodium | libsodium.js | libsodium |
|
| Blake2b | LazySodium | libsodium.js | libsodium |
|
||||||
| SHA256 | LazySodium | libsodium.js | libsodium |
|
| SHA256 | LazySodium | libsodium.js | libsodium |
|
||||||
| SHA512 | LazySodium | libsodium.js | libsodium |
|
| SHA512 | LazySodium | libsodium.js | libsodium |
|
||||||
| AES-CBC | LazySodium | libsodium.js | libsodium |
|
|
||||||
| AES-CTR | LazySodium | libsodium.js | libsodium |
|
|
||||||
|
|
||||||
|
|
||||||
## Integration
|
## Integration
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.authenticated
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Ugljesa Jovanovic
|
||||||
|
* ugljesa.jovanovic@ionspin.com
|
||||||
|
* on 14-Jun-2020
|
||||||
|
*/
|
||||||
|
interface Aes256GcmStateless {
|
||||||
|
/**
|
||||||
|
* Nonce autogenerated, key autogenerated
|
||||||
|
*/
|
||||||
|
fun encrypt(message: UByteArray, additionalData: UByteArray, rawData : UByteArray) : Aes256GcmEncryptionResult
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Aes256GcmEncryptionResult(val cyphertext : UByteArray, val additionalData: UByteArray, val nonce: UByteArray, val tag: UByteArray) {
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (other == null || this::class != other::class) return false
|
||||||
|
|
||||||
|
other as Aes256GcmEncryptionResult
|
||||||
|
|
||||||
|
if (cyphertext != other.cyphertext) return false
|
||||||
|
if (additionalData != other.additionalData) return false
|
||||||
|
if (nonce != other.nonce) return false
|
||||||
|
if (tag != other.tag) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = cyphertext.hashCode()
|
||||||
|
result = 31 * result + additionalData.hashCode()
|
||||||
|
result = 31 * result + nonce.hashCode()
|
||||||
|
result = 31 * result + tag.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
@ -1,69 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.authenticated
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Ugljesa Jovanovic
|
||||||
|
* ugljesa.jovanovic@ionspin.com
|
||||||
|
* on 14-Jun-2020
|
||||||
|
*/
|
@ -1,222 +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
|
|
||||||
|
|
||||||
import com.ionspin.kotlin.crypto.SRNG
|
|
||||||
import com.ionspin.kotlin.crypto.util.xor
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Advanced encryption standard with cipher block chaining and PKCS #5
|
|
||||||
*
|
|
||||||
* 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]
|
|
||||||
*
|
|
||||||
* Created by Ugljesa Jovanovic
|
|
||||||
* ugljesa.jovanovic@ionspin.com
|
|
||||||
* on 21-Sep-2019
|
|
||||||
*/
|
|
||||||
|
|
||||||
class AesCbcDelegated internal constructor(val aesKey: AesKey, val mode: Mode, initializationVector: UByteArray? = null) {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val BLOCK_BYTES = 16
|
|
||||||
/**
|
|
||||||
* Creates and returns AesCbc instance that can be fed data using [addData]. Once you have submitted all
|
|
||||||
* data call [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) : 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 = AesCbcDelegated(aesKey, Mode.ENCRYPT)
|
|
||||||
aesCbc.addData(data)
|
|
||||||
return aesCbc.encrypt()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bulk decryption, returns decrypted data
|
|
||||||
*/
|
|
||||||
fun decrypt(aesKey: AesKey, data: UByteArray, initialCounter: UByteArray? = null): UByteArray {
|
|
||||||
val aesCbc = AesCbcDelegated(aesKey, Mode.DECRYPT, initialCounter)
|
|
||||||
aesCbc.addData(data)
|
|
||||||
return aesCbc.decrypt()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun padToBlock(unpadded: UByteArray): UByteArray {
|
|
||||||
val paddingSize = 16 - unpadded.size
|
|
||||||
if (unpadded.size == BLOCK_BYTES) {
|
|
||||||
return unpadded
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unpadded.size == BLOCK_BYTES) {
|
|
||||||
return UByteArray(BLOCK_BYTES) {
|
|
||||||
BLOCK_BYTES.toUByte()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unpadded.size > BLOCK_BYTES) {
|
|
||||||
throw IllegalStateException("Block larger than 128 bytes")
|
|
||||||
}
|
|
||||||
|
|
||||||
return UByteArray(BLOCK_BYTES) {
|
|
||||||
when (it) {
|
|
||||||
in unpadded.indices -> unpadded[it]
|
|
||||||
else -> paddingSize.toUByte()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var currentOutput: UByteArray = ubyteArrayOf()
|
|
||||||
var previousEncrypted: UByteArray = ubyteArrayOf()
|
|
||||||
val initVector = if (initializationVector.isNullOrEmpty()) {
|
|
||||||
SRNG.getRandomBytes(16)
|
|
||||||
} else {
|
|
||||||
initializationVector
|
|
||||||
}
|
|
||||||
|
|
||||||
val output = MutableList<UByteArray>(0) { ubyteArrayOf() }
|
|
||||||
|
|
||||||
var buffer: UByteArray = UByteArray(16) { 0U }
|
|
||||||
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.toUByteArray(), bufferCounter)
|
|
||||||
} else {
|
|
||||||
chunk.toUByteArray().copyInto(
|
|
||||||
destination = buffer,
|
|
||||||
destinationOffset = bufferCounter,
|
|
||||||
startIndex = 0,
|
|
||||||
endIndex = BLOCK_BYTES - bufferCounter
|
|
||||||
)
|
|
||||||
output += consumeBlock(buffer)
|
|
||||||
buffer = UByteArray(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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encrypt fed data and return it alongside the randomly chosen initialization vector
|
|
||||||
* @return Encrypted data and initialization vector
|
|
||||||
*/
|
|
||||||
fun encrypt(): EncryptedDataAndInitializationVector {
|
|
||||||
if (bufferCounter > 0) {
|
|
||||||
val lastBlockPadded = padToBlock(buffer)
|
|
||||||
if (lastBlockPadded.size > BLOCK_BYTES) {
|
|
||||||
val chunks = lastBlockPadded.chunked(BLOCK_BYTES).map { it.toUByteArray() }
|
|
||||||
output += consumeBlock(chunks[0])
|
|
||||||
output += consumeBlock(chunks[1])
|
|
||||||
} else {
|
|
||||||
output += consumeBlock(lastBlockPadded)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return EncryptedDataAndInitializationVector(
|
|
||||||
output.reversed().foldRight(UByteArray(0) { 0U }) { arrayOfUBytes, acc -> acc + arrayOfUBytes },
|
|
||||||
initVector
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrypt data
|
|
||||||
* @return Decrypted data
|
|
||||||
*/
|
|
||||||
fun decrypt(): UByteArray {
|
|
||||||
val removePaddingCount = output.last().last()
|
|
||||||
|
|
||||||
|
|
||||||
val removedPadding = if (removePaddingCount > 0U && removePaddingCount < 16U) {
|
|
||||||
output.last().dropLast(removePaddingCount.toInt() and 0x7F)
|
|
||||||
} else {
|
|
||||||
output.last().toList()
|
|
||||||
}.toUByteArray()
|
|
||||||
val preparedOutput = (output.dropLast(1) + listOf(removedPadding))
|
|
||||||
//JS compiler freaks out here if we don't supply exact type
|
|
||||||
val reversed : List<UByteArray> = preparedOutput.reversed() as List<UByteArray>
|
|
||||||
val folded : UByteArray = reversed.foldRight(UByteArray(0) { 0U }) { uByteArray, acc ->
|
|
||||||
acc + uByteArray
|
|
||||||
}
|
|
||||||
return folded
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun appendToBuffer(array: UByteArray, start: Int) {
|
|
||||||
array.copyInto(destination = buffer, destinationOffset = start, startIndex = 0, endIndex = array.size)
|
|
||||||
bufferCounter += array.size
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun consumeBlock(data: UByteArray): UByteArray {
|
|
||||||
return when (mode) {
|
|
||||||
Mode.ENCRYPT -> {
|
|
||||||
currentOutput = if (currentOutput.isEmpty()) {
|
|
||||||
println("IV: $initVector")
|
|
||||||
AesDelegated.encrypt(aesKey, data xor initVector)
|
|
||||||
} else {
|
|
||||||
AesDelegated.encrypt(aesKey, data xor currentOutput)
|
|
||||||
}
|
|
||||||
currentOutput
|
|
||||||
}
|
|
||||||
Mode.DECRYPT -> {
|
|
||||||
if (currentOutput.isEmpty()) {
|
|
||||||
currentOutput = AesDelegated.decrypt(aesKey, data) xor initVector
|
|
||||||
} else {
|
|
||||||
currentOutput = AesDelegated.decrypt(aesKey, data) xor previousEncrypted
|
|
||||||
}
|
|
||||||
previousEncrypted = data
|
|
||||||
currentOutput
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,209 +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
|
|
||||||
|
|
||||||
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.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 [AesCtrDelegated.encrypt] and [AesCtrDelegated.decrypt]
|
|
||||||
*
|
|
||||||
* To get an instance of AesCtr and then feed it data sequentially with [addData] use [createEncryptor] and [createDecryptor]
|
|
||||||
*
|
|
||||||
* Created by Ugljesa Jovanovic
|
|
||||||
* ugljesa.jovanovic@ionspin.com
|
|
||||||
* on 22-Sep-2019
|
|
||||||
*/
|
|
||||||
|
|
||||||
class AesCtrDelegated internal constructor(val aesKey: AesKey, val mode: Mode, initialCounter: UByteArray? = null) {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val BLOCK_BYTES = 16
|
|
||||||
|
|
||||||
val modularCreator = ModularBigInteger.creatorForModulo(BigInteger.ONE.shl(128) - 1)
|
|
||||||
/**
|
|
||||||
* Creates and returns AesCtr instance that can be fed data using [addData]. Once you have submitted all
|
|
||||||
* data call [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) : 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 = AesCtrDelegated(aesKey, Mode.ENCRYPT)
|
|
||||||
aesCtr.addData(data)
|
|
||||||
return aesCtr.encrypt()
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Bulk decryption, returns decrypted data
|
|
||||||
*/
|
|
||||||
fun decrypt(aesKey: AesKey, data: UByteArray, initialCounter: UByteArray? = null): UByteArray {
|
|
||||||
val aesCtr = AesCtrDelegated(aesKey, Mode.DECRYPT, initialCounter)
|
|
||||||
aesCtr.addData(data)
|
|
||||||
return aesCtr.decrypt()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var currentOutput: UByteArray = ubyteArrayOf()
|
|
||||||
var previousEncrypted: UByteArray = ubyteArrayOf()
|
|
||||||
val counterStart = if (initialCounter.isNullOrEmpty()) {
|
|
||||||
SRNG.getRandomBytes(16)
|
|
||||||
} else {
|
|
||||||
initialCounter
|
|
||||||
}
|
|
||||||
var blockCounter = modularCreator.fromBigInteger(BigInteger.fromUByteArray(counterStart.toTypedArray(), Endianness.BIG))
|
|
||||||
|
|
||||||
val output = MutableList<UByteArray>(0) { ubyteArrayOf() }
|
|
||||||
|
|
||||||
var buffer: UByteArray = UByteArray(16) { 0U }
|
|
||||||
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.toUByteArray(), bufferCounter)
|
|
||||||
} else {
|
|
||||||
chunk.toUByteArray().copyInto(
|
|
||||||
destination = buffer,
|
|
||||||
destinationOffset = bufferCounter,
|
|
||||||
startIndex = 0,
|
|
||||||
endIndex = BLOCK_BYTES - bufferCounter
|
|
||||||
)
|
|
||||||
output += consumeBlock(buffer, blockCounter)
|
|
||||||
blockCounter += 1
|
|
||||||
buffer = UByteArray(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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Encrypt fed data and return it alongside the randomly chosen initial counter state
|
|
||||||
* @return Encrypted data and initial counter state
|
|
||||||
*/
|
|
||||||
fun encrypt(): EncryptedDataAndInitialCounter {
|
|
||||||
if (bufferCounter > 0) {
|
|
||||||
output += consumeBlock(buffer, blockCounter)
|
|
||||||
}
|
|
||||||
return EncryptedDataAndInitialCounter(
|
|
||||||
output.reversed().foldRight(UByteArray(0) { 0U }) { arrayOfUBytes, acc -> acc + arrayOfUBytes },
|
|
||||||
counterStart
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Decrypt data
|
|
||||||
* @return Decrypted data
|
|
||||||
*/
|
|
||||||
fun decrypt(): UByteArray {
|
|
||||||
if (bufferCounter > 0) {
|
|
||||||
output += consumeBlock(buffer, blockCounter)
|
|
||||||
}
|
|
||||||
//JS compiler freaks out here if we don't supply exact type
|
|
||||||
val reversed: List<UByteArray> = output.reversed() as List<UByteArray>
|
|
||||||
val folded: UByteArray = reversed.foldRight(UByteArray(0) { 0U }) { arrayOfUBytes, acc ->
|
|
||||||
acc + arrayOfUBytes
|
|
||||||
}
|
|
||||||
return folded
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun appendToBuffer(array: UByteArray, start: Int) {
|
|
||||||
array.copyInto(destination = buffer, destinationOffset = start, startIndex = 0, endIndex = array.size)
|
|
||||||
bufferCounter += array.size
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun consumeBlock(data: UByteArray, blockCount: ModularBigInteger): UByteArray {
|
|
||||||
val blockCountAsByteArray = blockCount.toUByteArray(Endianness.BIG).toUByteArray().expandCounterTo16Bytes()
|
|
||||||
return when (mode) {
|
|
||||||
Mode.ENCRYPT -> {
|
|
||||||
AesDelegated.encrypt(aesKey, blockCountAsByteArray) xor data
|
|
||||||
}
|
|
||||||
Mode.DECRYPT -> {
|
|
||||||
AesDelegated.encrypt(aesKey, blockCountAsByteArray) xor data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun UByteArray.expandCounterTo16Bytes() : UByteArray {
|
|
||||||
return if (this.size < 16) {
|
|
||||||
println("Expanding")
|
|
||||||
val diff = 16 - this.size
|
|
||||||
val pad = UByteArray(diff) { 0U }
|
|
||||||
pad + this
|
|
||||||
} else {
|
|
||||||
this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,360 +0,0 @@
|
|||||||
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 AesDelegated internal constructor(val aesKey: AesKey, val input: UByteArray) {
|
|
||||||
companion object {
|
|
||||||
private val debug = false
|
|
||||||
|
|
||||||
private val sBox: UByteArray =
|
|
||||||
ubyteArrayOf(
|
|
||||||
// @formatter:off
|
|
||||||
0x63U, 0x7cU, 0x77U, 0x7bU, 0xf2U, 0x6bU, 0x6fU, 0xc5U, 0x30U, 0x01U, 0x67U, 0x2bU, 0xfeU, 0xd7U, 0xabU, 0x76U,
|
|
||||||
0xcaU, 0x82U, 0xc9U, 0x7dU, 0xfaU, 0x59U, 0x47U, 0xf0U, 0xadU, 0xd4U, 0xa2U, 0xafU, 0x9cU, 0xa4U, 0x72U, 0xc0U,
|
|
||||||
0xb7U, 0xfdU, 0x93U, 0x26U, 0x36U, 0x3fU, 0xf7U, 0xccU, 0x34U, 0xa5U, 0xe5U, 0xf1U, 0x71U, 0xd8U, 0x31U, 0x15U,
|
|
||||||
0x04U, 0xc7U, 0x23U, 0xc3U, 0x18U, 0x96U, 0x05U, 0x9aU, 0x07U, 0x12U, 0x80U, 0xe2U, 0xebU, 0x27U, 0xb2U, 0x75U,
|
|
||||||
0x09U, 0x83U, 0x2cU, 0x1aU, 0x1bU, 0x6eU, 0x5aU, 0xa0U, 0x52U, 0x3bU, 0xd6U, 0xb3U, 0x29U, 0xe3U, 0x2fU, 0x84U,
|
|
||||||
0x53U, 0xd1U, 0x00U, 0xedU, 0x20U, 0xfcU, 0xb1U, 0x5bU, 0x6aU, 0xcbU, 0xbeU, 0x39U, 0x4aU, 0x4cU, 0x58U, 0xcfU,
|
|
||||||
0xd0U, 0xefU, 0xaaU, 0xfbU, 0x43U, 0x4dU, 0x33U, 0x85U, 0x45U, 0xf9U, 0x02U, 0x7fU, 0x50U, 0x3cU, 0x9fU, 0xa8U,
|
|
||||||
0x51U, 0xa3U, 0x40U, 0x8fU, 0x92U, 0x9dU, 0x38U, 0xf5U, 0xbcU, 0xb6U, 0xdaU, 0x21U, 0x10U, 0xffU, 0xf3U, 0xd2U,
|
|
||||||
0xcdU, 0x0cU, 0x13U, 0xecU, 0x5fU, 0x97U, 0x44U, 0x17U, 0xc4U, 0xa7U, 0x7eU, 0x3dU, 0x64U, 0x5dU, 0x19U, 0x73U,
|
|
||||||
0x60U, 0x81U, 0x4fU, 0xdcU, 0x22U, 0x2aU, 0x90U, 0x88U, 0x46U, 0xeeU, 0xb8U, 0x14U, 0xdeU, 0x5eU, 0x0bU, 0xdbU,
|
|
||||||
0xe0U, 0x32U, 0x3aU, 0x0aU, 0x49U, 0x06U, 0x24U, 0x5cU, 0xc2U, 0xd3U, 0xacU, 0x62U, 0x91U, 0x95U, 0xe4U, 0x79U,
|
|
||||||
0xe7U, 0xc8U, 0x37U, 0x6dU, 0x8dU, 0xd5U, 0x4eU, 0xa9U, 0x6cU, 0x56U, 0xf4U, 0xeaU, 0x65U, 0x7aU, 0xaeU, 0x08U,
|
|
||||||
0xbaU, 0x78U, 0x25U, 0x2eU, 0x1cU, 0xa6U, 0xb4U, 0xc6U, 0xe8U, 0xddU, 0x74U, 0x1fU, 0x4bU, 0xbdU, 0x8bU, 0x8aU,
|
|
||||||
0x70U, 0x3eU, 0xb5U, 0x66U, 0x48U, 0x03U, 0xf6U, 0x0eU, 0x61U, 0x35U, 0x57U, 0xb9U, 0x86U, 0xc1U, 0x1dU, 0x9eU,
|
|
||||||
0xe1U, 0xf8U, 0x98U, 0x11U, 0x69U, 0xd9U, 0x8eU, 0x94U, 0x9bU, 0x1eU, 0x87U, 0xe9U, 0xceU, 0x55U, 0x28U, 0xdfU,
|
|
||||||
0x8cU, 0xa1U, 0x89U, 0x0dU, 0xbfU, 0xe6U, 0x42U, 0x68U, 0x41U, 0x99U, 0x2dU, 0x0fU, 0xb0U, 0x54U, 0xbbU, 0x16U
|
|
||||||
// @formatter:on
|
|
||||||
)
|
|
||||||
|
|
||||||
private val inverseSBox: UByteArray =
|
|
||||||
ubyteArrayOf(
|
|
||||||
// @formatter:off
|
|
||||||
0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU,
|
|
||||||
0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU,
|
|
||||||
0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU,
|
|
||||||
0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U,
|
|
||||||
0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U,
|
|
||||||
0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U,
|
|
||||||
0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U,
|
|
||||||
0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU,
|
|
||||||
0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U,
|
|
||||||
0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU,
|
|
||||||
0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU,
|
|
||||||
0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U,
|
|
||||||
0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU,
|
|
||||||
0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU,
|
|
||||||
0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U,
|
|
||||||
0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU
|
|
||||||
// @formatter:on
|
|
||||||
)
|
|
||||||
|
|
||||||
val rcon: UByteArray = ubyteArrayOf(0x8DU, 0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U, 0x1BU, 0x36U)
|
|
||||||
|
|
||||||
fun encrypt(aesKey: AesKey, input: UByteArray): UByteArray {
|
|
||||||
return AesDelegated(aesKey, input).encrypt()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun decrypt(aesKey: AesKey, input: UByteArray): UByteArray {
|
|
||||||
return AesDelegated(aesKey, input).decrypt()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
val state: Array<UByteArray> = (0 until 4).map { outerCounter ->
|
|
||||||
UByteArray(4) { innerCounter -> input[innerCounter * 4 + outerCounter] }
|
|
||||||
}.toTypedArray()
|
|
||||||
|
|
||||||
val numberOfRounds = when (aesKey) {
|
|
||||||
is AesKey.Aes128Key -> 10
|
|
||||||
is AesKey.Aes192Key -> 12
|
|
||||||
is AesKey.Aes256Key -> 14
|
|
||||||
}
|
|
||||||
|
|
||||||
val expandedKey: Array<UByteArray> = expandKey()
|
|
||||||
|
|
||||||
|
|
||||||
var round = 0
|
|
||||||
var completed : Boolean = false
|
|
||||||
private set
|
|
||||||
|
|
||||||
fun subBytes() {
|
|
||||||
state.forEachIndexed { indexRow, row ->
|
|
||||||
row.forEachIndexed { indexColumn, element ->
|
|
||||||
state[indexRow][indexColumn] = getSBoxValue(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getSBoxValue(element: UByte): UByte {
|
|
||||||
val firstDigit = (element / 16U).toInt()
|
|
||||||
val secondDigit = (element % 16U).toInt()
|
|
||||||
return sBox[firstDigit * 16 + secondDigit]
|
|
||||||
}
|
|
||||||
|
|
||||||
fun inverseSubBytes() {
|
|
||||||
state.forEachIndexed { indexRow, row ->
|
|
||||||
row.forEachIndexed { indexColumn, element ->
|
|
||||||
state[indexRow][indexColumn] = getInverseSBoxValue(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getInverseSBoxValue(element: UByte): UByte {
|
|
||||||
val firstDigit = (element / 16U).toInt()
|
|
||||||
val secondDigit = (element % 16U).toInt()
|
|
||||||
return inverseSBox[firstDigit * 16 + secondDigit]
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shiftRows() {
|
|
||||||
state[0] = ubyteArrayOf(state[0][0], state[0][1], state[0][2], state[0][3])
|
|
||||||
state[1] = ubyteArrayOf(state[1][1], state[1][2], state[1][3], state[1][0])
|
|
||||||
state[2] = ubyteArrayOf(state[2][2], state[2][3], state[2][0], state[2][1])
|
|
||||||
state[3] = ubyteArrayOf(state[3][3], state[3][0], state[3][1], state[3][2])
|
|
||||||
}
|
|
||||||
|
|
||||||
fun inversShiftRows() {
|
|
||||||
state[0] = ubyteArrayOf(state[0][0], state[0][1], state[0][2], state[0][3])
|
|
||||||
state[1] = ubyteArrayOf(state[1][3], state[1][0], state[1][1], state[1][2])
|
|
||||||
state[2] = ubyteArrayOf(state[2][2], state[2][3], state[2][0], state[2][1])
|
|
||||||
state[3] = ubyteArrayOf(state[3][1], state[3][2], state[3][3], state[3][0])
|
|
||||||
}
|
|
||||||
|
|
||||||
fun mixColumns() {
|
|
||||||
val stateMixed: Array<UByteArray> = (0 until 4).map {
|
|
||||||
UByteArray(4) { 0U }
|
|
||||||
}.toTypedArray()
|
|
||||||
for (c in 0..3) {
|
|
||||||
|
|
||||||
stateMixed[0][c] = (2U gfm state[0][c]) xor (3U gfm state[1][c]) xor state[2][c] xor state[3][c]
|
|
||||||
stateMixed[1][c] = state[0][c] xor (2U gfm state[1][c]) xor (3U gfm state[2][c]) xor state[3][c]
|
|
||||||
stateMixed[2][c] = state[0][c] xor state[1][c] xor (2U gfm state[2][c]) xor (3U gfm state[3][c])
|
|
||||||
stateMixed[3][c] = 3U gfm state[0][c] xor state[1][c] xor state[2][c] xor (2U gfm state[3][c])
|
|
||||||
}
|
|
||||||
stateMixed.copyInto(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun inverseMixColumns() {
|
|
||||||
val stateMixed: Array<UByteArray> = (0 until 4).map {
|
|
||||||
UByteArray(4) { 0U }
|
|
||||||
}.toTypedArray()
|
|
||||||
for (c in 0..3) {
|
|
||||||
stateMixed[0][c] =
|
|
||||||
(0x0eU gfm state[0][c]) xor (0x0bU gfm state[1][c]) xor (0x0dU gfm state[2][c]) xor (0x09U gfm state[3][c])
|
|
||||||
stateMixed[1][c] =
|
|
||||||
(0x09U gfm state[0][c]) xor (0x0eU gfm state[1][c]) xor (0x0bU gfm state[2][c]) xor (0x0dU gfm state[3][c])
|
|
||||||
stateMixed[2][c] =
|
|
||||||
(0x0dU gfm state[0][c]) xor (0x09U gfm state[1][c]) xor (0x0eU gfm state[2][c]) xor (0x0bU gfm state[3][c])
|
|
||||||
stateMixed[3][c] =
|
|
||||||
(0x0bU gfm state[0][c]) xor (0x0dU gfm state[1][c]) xor (0x09U gfm state[2][c]) xor (0x0eU gfm state[3][c])
|
|
||||||
}
|
|
||||||
stateMixed.copyInto(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun galoisFieldAdd(first: UByte, second: UByte): UByte {
|
|
||||||
return first xor second
|
|
||||||
}
|
|
||||||
|
|
||||||
fun galoisFieldMultiply(first: UByte, second: UByte): UByte {
|
|
||||||
var result: UInt = 0U
|
|
||||||
var firstInt = first.toUInt()
|
|
||||||
var secondInt = second.toUInt()
|
|
||||||
var carry: UInt = 0U
|
|
||||||
for (i in 0..7) {
|
|
||||||
if (secondInt and 0x01U == 1U) {
|
|
||||||
result = result xor firstInt
|
|
||||||
}
|
|
||||||
carry = firstInt and 0x80U
|
|
||||||
firstInt = firstInt shl 1
|
|
||||||
if (carry == 0x80U) {
|
|
||||||
firstInt = firstInt xor 0x001BU
|
|
||||||
}
|
|
||||||
secondInt = secondInt shr 1
|
|
||||||
firstInt = firstInt and 0xFFU
|
|
||||||
}
|
|
||||||
return result.toUByte()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addRoundKey() {
|
|
||||||
|
|
||||||
for (i in 0 until 4) {
|
|
||||||
state[0][i] = state[0][i] xor expandedKey[round * 4 + i][0]
|
|
||||||
state[1][i] = state[1][i] xor expandedKey[round * 4 + i][1]
|
|
||||||
state[2][i] = state[2][i] xor expandedKey[round * 4 + i][2]
|
|
||||||
state[3][i] = state[3][i] xor expandedKey[round * 4 + i][3]
|
|
||||||
}
|
|
||||||
round++
|
|
||||||
}
|
|
||||||
|
|
||||||
fun inverseAddRoundKey() {
|
|
||||||
for (i in 0 until 4) {
|
|
||||||
state[0][i] = state[0][i] xor expandedKey[round * 4 + i][0]
|
|
||||||
state[1][i] = state[1][i] xor expandedKey[round * 4 + i][1]
|
|
||||||
state[2][i] = state[2][i] xor expandedKey[round * 4 + i][2]
|
|
||||||
state[3][i] = state[3][i] xor expandedKey[round * 4 + i][3]
|
|
||||||
}
|
|
||||||
round--
|
|
||||||
}
|
|
||||||
|
|
||||||
infix fun UInt.gfm(second: UByte): UByte {
|
|
||||||
return galoisFieldMultiply(this.toUByte(), second)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun expandKey(): Array<UByteArray> {
|
|
||||||
val expandedKey = (0 until 4 * (numberOfRounds + 1)).map {
|
|
||||||
UByteArray(4) { 0U }
|
|
||||||
}.toTypedArray()
|
|
||||||
// First round
|
|
||||||
for (i in 0 until aesKey.numberOf32BitWords) {
|
|
||||||
expandedKey[i][0] = aesKey.keyArray[i * 4 + 0]
|
|
||||||
expandedKey[i][1] = aesKey.keyArray[i * 4 + 1]
|
|
||||||
expandedKey[i][2] = aesKey.keyArray[i * 4 + 2]
|
|
||||||
expandedKey[i][3] = aesKey.keyArray[i * 4 + 3]
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i in aesKey.numberOf32BitWords until 4 * (numberOfRounds + 1)) {
|
|
||||||
val temp = expandedKey[i - 1].copyOf()
|
|
||||||
if (i % aesKey.numberOf32BitWords == 0) {
|
|
||||||
//RotWord
|
|
||||||
val tempTemp = temp[0]
|
|
||||||
temp[0] = temp[1]
|
|
||||||
temp[1] = temp[2]
|
|
||||||
temp[2] = temp[3]
|
|
||||||
temp[3] = tempTemp
|
|
||||||
|
|
||||||
//SubWord
|
|
||||||
temp[0] = getSBoxValue(temp[0])
|
|
||||||
temp[1] = getSBoxValue(temp[1])
|
|
||||||
temp[2] = getSBoxValue(temp[2])
|
|
||||||
temp[3] = getSBoxValue(temp[3])
|
|
||||||
|
|
||||||
temp[0] = temp[0] xor rcon[i / aesKey.numberOf32BitWords]
|
|
||||||
|
|
||||||
} else if (aesKey is AesKey.Aes256Key && i % aesKey.numberOf32BitWords == 4) {
|
|
||||||
temp[0] = getSBoxValue(temp[0])
|
|
||||||
temp[1] = getSBoxValue(temp[1])
|
|
||||||
temp[2] = getSBoxValue(temp[2])
|
|
||||||
temp[3] = getSBoxValue(temp[3])
|
|
||||||
}
|
|
||||||
expandedKey[i] = expandedKey[i - aesKey.numberOf32BitWords].mapIndexed { index, it ->
|
|
||||||
it xor temp[index]
|
|
||||||
}.toUByteArray()
|
|
||||||
clearArray(temp)
|
|
||||||
}
|
|
||||||
return expandedKey
|
|
||||||
}
|
|
||||||
|
|
||||||
fun encrypt(): UByteArray {
|
|
||||||
if (completed) {
|
|
||||||
throw RuntimeException("Encrypt can only be called once per Aes instance, since the state is cleared at the " +
|
|
||||||
"end of the operation")
|
|
||||||
}
|
|
||||||
printState()
|
|
||||||
addRoundKey()
|
|
||||||
printState()
|
|
||||||
for (i in 0 until numberOfRounds - 1) {
|
|
||||||
subBytes()
|
|
||||||
printState()
|
|
||||||
shiftRows()
|
|
||||||
printState()
|
|
||||||
mixColumns()
|
|
||||||
printState()
|
|
||||||
addRoundKey()
|
|
||||||
printState()
|
|
||||||
}
|
|
||||||
|
|
||||||
subBytes()
|
|
||||||
printState()
|
|
||||||
shiftRows()
|
|
||||||
printState()
|
|
||||||
addRoundKey()
|
|
||||||
printState()
|
|
||||||
val transposedMatrix = (0 until 4).map { outerCounter ->
|
|
||||||
UByteArray(4) { 0U }
|
|
||||||
}
|
|
||||||
for (i in 0 until 4) {
|
|
||||||
for (j in 0 until 4) {
|
|
||||||
transposedMatrix[i][j] = state[j][i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state.forEach { clearArray(it) }
|
|
||||||
completed = true
|
|
||||||
return transposedMatrix.flattenToUByteArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun decrypt(): UByteArray {
|
|
||||||
if (completed) {
|
|
||||||
throw RuntimeException("Decrypt can only be called once per Aes instance, since the state is cleared at the " +
|
|
||||||
"end of the operation")
|
|
||||||
}
|
|
||||||
round = numberOfRounds
|
|
||||||
printState()
|
|
||||||
inverseAddRoundKey()
|
|
||||||
printState()
|
|
||||||
for (i in 0 until numberOfRounds - 1) {
|
|
||||||
inversShiftRows()
|
|
||||||
printState()
|
|
||||||
inverseSubBytes()
|
|
||||||
printState()
|
|
||||||
inverseAddRoundKey()
|
|
||||||
printState()
|
|
||||||
inverseMixColumns()
|
|
||||||
printState()
|
|
||||||
}
|
|
||||||
|
|
||||||
inversShiftRows()
|
|
||||||
printState()
|
|
||||||
inverseSubBytes()
|
|
||||||
printState()
|
|
||||||
inverseAddRoundKey()
|
|
||||||
printState()
|
|
||||||
|
|
||||||
val transposedMatrix = (0 until 4).map { outerCounter ->
|
|
||||||
UByteArray(4) { 0U }
|
|
||||||
}
|
|
||||||
for (i in 0 until 4) {
|
|
||||||
for (j in 0 until 4) {
|
|
||||||
transposedMatrix[i][j] = state[j][i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state.forEach { clearArray(it) }
|
|
||||||
completed = true
|
|
||||||
return transposedMatrix.flattenToUByteArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun clearArray(array : UByteArray) {
|
|
||||||
array.indices.forEach { array[it] = 0U }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private fun printState() {
|
|
||||||
if (!debug) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
println()
|
|
||||||
state.forEach {
|
|
||||||
println(it.joinToString(separator = " ") { it.toString(16) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun printState(specific : List<UByteArray>) {
|
|
||||||
if (!debug) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
println()
|
|
||||||
specific.forEach {
|
|
||||||
println(it.joinToString(separator = " ") { it.toString(16) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.authenticated
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Ugljesa Jovanovic
|
||||||
|
* ugljesa.jovanovic@ionspin.com
|
||||||
|
* on 14-Jun-2020
|
||||||
|
*/
|
||||||
|
class Aes256GcmStatelessPure : Aes256GcmStateless {
|
||||||
|
/**
|
||||||
|
* Nonce autogenerated
|
||||||
|
*/
|
||||||
|
override fun encrypt(message: UByteArray, additionalData: UByteArray, rawData : UByteArray, key:) : Aes256GcmEncryptionResult {
|
||||||
|
|
||||||
|
TODO()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,17 +1,17 @@
|
|||||||
package com.ionspin.kotlin.crypto.symmetric.aes
|
package com.ionspin.kotlin.crypto.symmetric
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Ugljesa Jovanovic
|
* Created by Ugljesa Jovanovic
|
||||||
* ugljesa.jovanovic@ionspin.com
|
* ugljesa.jovanovic@ionspin.com
|
||||||
* on 13-Jun-2020
|
* on 13-Jun-2020
|
||||||
*/
|
*/
|
||||||
sealed class AesKey(val key: String, val keyLength: Int) {
|
internal sealed class InternalAesKey(val key: String, val keyLength: Int) {
|
||||||
val keyArray: UByteArray = key.chunked(2).map { it.toUByte(16) }.toUByteArray()
|
val keyArray: UByteArray = key.chunked(2).map { it.toUByte(16) }.toUByteArray()
|
||||||
val numberOf32BitWords = keyLength / 32
|
val numberOf32BitWords = keyLength / 32
|
||||||
|
|
||||||
class Aes128Key(key: String) : AesKey(key, 128)
|
class Aes128Key(key: String) : InternalAesKey(key, 128)
|
||||||
class Aes192Key(key: String) : AesKey(key, 192)
|
class Aes192Key(key: String) : InternalAesKey(key, 192)
|
||||||
class Aes256Key(key: String) : AesKey(key, 256)
|
class Aes256Key(key: String) : InternalAesKey(key, 256)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
checkKeyLength(key, keyLength)
|
checkKeyLength(key, keyLength)
|
@ -17,7 +17,6 @@
|
|||||||
package com.ionspin.kotlin.crypto.symmetric
|
package com.ionspin.kotlin.crypto.symmetric
|
||||||
|
|
||||||
import com.ionspin.kotlin.crypto.SRNG
|
import com.ionspin.kotlin.crypto.SRNG
|
||||||
import com.ionspin.kotlin.crypto.symmetric.aes.AesKey
|
|
||||||
import com.ionspin.kotlin.crypto.util.xor
|
import com.ionspin.kotlin.crypto.util.xor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,7 +31,7 @@ import com.ionspin.kotlin.crypto.util.xor
|
|||||||
* on 21-Sep-2019
|
* on 21-Sep-2019
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class AesCbcPure internal constructor(val aesKey: AesKey, val mode: Mode, initializationVector: UByteArray? = null) {
|
internal class AesCbcPure internal constructor(val aesKey: InternalAesKey, val mode: Mode, initializationVector: UByteArray? = null) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val BLOCK_BYTES = 16
|
const val BLOCK_BYTES = 16
|
||||||
@ -40,21 +39,21 @@ 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
|
* Creates and returns AesCbc instance that can be fed data using [addData]. Once you have submitted all
|
||||||
* data call [encrypt]
|
* data call [encrypt]
|
||||||
*/
|
*/
|
||||||
fun createEncryptor(aesKey: AesKey) : AesCbcPure {
|
fun createEncryptor(aesKey: InternalAesKey) : AesCbcPure {
|
||||||
return AesCbcPure(aesKey, Mode.ENCRYPT)
|
return AesCbcPure(aesKey, Mode.ENCRYPT)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Creates and returns AesCbc instance that can be fed data using [addData]. Once you have submitted all
|
* Creates and returns AesCbc instance that can be fed data using [addData]. Once you have submitted all
|
||||||
* data call [decrypt]
|
* data call [decrypt]
|
||||||
*/
|
*/
|
||||||
fun createDecryptor(aesKey : AesKey) : AesCbcPure {
|
fun createDecryptor(aesKey : InternalAesKey) : AesCbcPure {
|
||||||
return AesCbcPure(aesKey, Mode.DECRYPT)
|
return AesCbcPure(aesKey, Mode.DECRYPT)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bulk encryption, returns encrypted data and a random initialization vector
|
* Bulk encryption, returns encrypted data and a random initialization vector
|
||||||
*/
|
*/
|
||||||
fun encrypt(aesKey: AesKey, data: UByteArray): EncryptedDataAndInitializationVector {
|
fun encrypt(aesKey: InternalAesKey, data: UByteArray): EncryptedDataAndInitializationVector {
|
||||||
val aesCbc = AesCbcPure(aesKey, Mode.ENCRYPT)
|
val aesCbc = AesCbcPure(aesKey, Mode.ENCRYPT)
|
||||||
aesCbc.addData(data)
|
aesCbc.addData(data)
|
||||||
return aesCbc.encrypt()
|
return aesCbc.encrypt()
|
||||||
@ -63,7 +62,7 @@ class AesCbcPure internal constructor(val aesKey: AesKey, val mode: Mode, initia
|
|||||||
/**
|
/**
|
||||||
* Bulk decryption, returns decrypted data
|
* Bulk decryption, returns decrypted data
|
||||||
*/
|
*/
|
||||||
fun decrypt(aesKey: AesKey, data: UByteArray, initialCounter: UByteArray? = null): UByteArray {
|
fun decrypt(aesKey: InternalAesKey, data: UByteArray, initialCounter: UByteArray? = null): UByteArray {
|
||||||
val aesCbc = AesCbcPure(aesKey, Mode.DECRYPT, initialCounter)
|
val aesCbc = AesCbcPure(aesKey, Mode.DECRYPT, initialCounter)
|
||||||
aesCbc.addData(data)
|
aesCbc.addData(data)
|
||||||
return aesCbc.decrypt()
|
return aesCbc.decrypt()
|
||||||
@ -221,7 +220,7 @@ class AesCbcPure internal constructor(val aesKey: AesKey, val mode: Mode, initia
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
data class EncryptedDataAndInitializationVector(val encryptedData : UByteArray, val initilizationVector : UByteArray) {
|
data class EncryptedDataAndInitializationVector(val encryptedData : UByteArray, val initializationVector : UByteArray) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other == null || this::class != other::class) return false
|
if (other == null || this::class != other::class) return false
|
||||||
@ -229,14 +228,14 @@ data class EncryptedDataAndInitializationVector(val encryptedData : UByteArray,
|
|||||||
other as EncryptedDataAndInitializationVector
|
other as EncryptedDataAndInitializationVector
|
||||||
|
|
||||||
if (!encryptedData.contentEquals(other.encryptedData)) return false
|
if (!encryptedData.contentEquals(other.encryptedData)) return false
|
||||||
if (!initilizationVector.contentEquals(other.initilizationVector)) return false
|
if (!initializationVector.contentEquals(other.initializationVector)) return false
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
var result = encryptedData.contentHashCode()
|
var result = encryptedData.contentHashCode()
|
||||||
result = 31 * result + initilizationVector.contentHashCode()
|
result = 31 * result + initializationVector.contentHashCode()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,8 +21,6 @@ import com.ionspin.kotlin.bignum.integer.BigInteger
|
|||||||
import com.ionspin.kotlin.bignum.modular.ModularBigInteger
|
import com.ionspin.kotlin.bignum.modular.ModularBigInteger
|
||||||
import com.ionspin.kotlin.crypto.SRNG
|
import com.ionspin.kotlin.crypto.SRNG
|
||||||
import com.ionspin.kotlin.crypto.symmetric.AesCtrPure.Companion.encrypt
|
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
|
import com.ionspin.kotlin.crypto.util.xor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,7 +36,7 @@ import com.ionspin.kotlin.crypto.util.xor
|
|||||||
* on 22-Sep-2019
|
* on 22-Sep-2019
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class AesCtrPure internal constructor(val aesKey: AesKey, val mode: Mode, initialCounter: UByteArray? = null) {
|
internal class AesCtrPure internal constructor(val aesKey: InternalAesKey, val mode: Mode, initialCounter: UByteArray? = null) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val BLOCK_BYTES = 16
|
const val BLOCK_BYTES = 16
|
||||||
@ -48,20 +46,20 @@ 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
|
* Creates and returns AesCtr instance that can be fed data using [addData]. Once you have submitted all
|
||||||
* data call [encrypt]
|
* data call [encrypt]
|
||||||
*/
|
*/
|
||||||
fun createEncryptor(aesKey: AesKey) : AesCtrPure {
|
fun createEncryptor(aesKey: InternalAesKey) : AesCtrPure {
|
||||||
return AesCtrPure(aesKey, Mode.ENCRYPT)
|
return AesCtrPure(aesKey, Mode.ENCRYPT)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Creates and returns AesCtr instance that can be fed data using [addData]. Once you have submitted all
|
* Creates and returns AesCtr instance that can be fed data using [addData]. Once you have submitted all
|
||||||
* data call [decrypt]
|
* data call [decrypt]
|
||||||
*/
|
*/
|
||||||
fun createDecryptor(aesKey : AesKey) : AesCtrPure {
|
fun createDecryptor(aesKey : InternalAesKey) : AesCtrPure {
|
||||||
return AesCtrPure(aesKey, Mode.DECRYPT)
|
return AesCtrPure(aesKey, Mode.DECRYPT)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Bulk encryption, returns encrypted data and a random initial counter
|
* Bulk encryption, returns encrypted data and a random initial counter
|
||||||
*/
|
*/
|
||||||
fun encrypt(aesKey: AesKey, data: UByteArray): EncryptedDataAndInitialCounter {
|
fun encrypt(aesKey: InternalAesKey, data: UByteArray): EncryptedDataAndInitialCounter {
|
||||||
val aesCtr = AesCtrPure(aesKey, Mode.ENCRYPT)
|
val aesCtr = AesCtrPure(aesKey, Mode.ENCRYPT)
|
||||||
aesCtr.addData(data)
|
aesCtr.addData(data)
|
||||||
return aesCtr.encrypt()
|
return aesCtr.encrypt()
|
||||||
@ -69,7 +67,7 @@ class AesCtrPure internal constructor(val aesKey: AesKey, val mode: Mode, initia
|
|||||||
/**
|
/**
|
||||||
* Bulk decryption, returns decrypted data
|
* Bulk decryption, returns decrypted data
|
||||||
*/
|
*/
|
||||||
fun decrypt(aesKey: AesKey, data: UByteArray, initialCounter: UByteArray? = null): UByteArray {
|
fun decrypt(aesKey: InternalAesKey, data: UByteArray, initialCounter: UByteArray? = null): UByteArray {
|
||||||
val aesCtr = AesCtrPure(aesKey, Mode.DECRYPT, initialCounter)
|
val aesCtr = AesCtrPure(aesKey, Mode.DECRYPT, initialCounter)
|
||||||
aesCtr.addData(data)
|
aesCtr.addData(data)
|
||||||
return aesCtr.decrypt()
|
return aesCtr.decrypt()
|
||||||
@ -188,4 +186,23 @@ 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 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import com.ionspin.kotlin.crypto.util.flattenToUByteArray
|
|||||||
* Created by Ugljesa Jovanovic (jovanovic.ugljesa@gmail.com) on 07/Sep/2019
|
* 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 AesPure internal constructor(val aesKey: InternalAesKey, val input: UByteArray) {
|
||||||
companion object {
|
companion object {
|
||||||
private val debug = false
|
private val debug = false
|
||||||
|
|
||||||
@ -56,11 +56,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)
|
val rcon: UByteArray = ubyteArrayOf(0x8DU, 0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U, 0x1BU, 0x36U)
|
||||||
|
|
||||||
fun encrypt(aesKey: AesKey, input: UByteArray): UByteArray {
|
fun encrypt(aesKey: InternalAesKey, input: UByteArray): UByteArray {
|
||||||
return AesPure(aesKey, input).encrypt()
|
return AesPure(aesKey, input).encrypt()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decrypt(aesKey: AesKey, input: UByteArray): UByteArray {
|
fun decrypt(aesKey: InternalAesKey, input: UByteArray): UByteArray {
|
||||||
return AesPure(aesKey, input).decrypt()
|
return AesPure(aesKey, input).decrypt()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,9 +71,9 @@ internal class AesPure internal constructor(val aesKey: AesKey, val input: UByte
|
|||||||
}.toTypedArray()
|
}.toTypedArray()
|
||||||
|
|
||||||
val numberOfRounds = when (aesKey) {
|
val numberOfRounds = when (aesKey) {
|
||||||
is AesKey.Aes128Key -> 10
|
is InternalAesKey.Aes128Key -> 10
|
||||||
is AesKey.Aes192Key -> 12
|
is InternalAesKey.Aes192Key -> 12
|
||||||
is AesKey.Aes256Key -> 14
|
is InternalAesKey.Aes256Key -> 14
|
||||||
}
|
}
|
||||||
|
|
||||||
val expandedKey: Array<UByteArray> = expandKey()
|
val expandedKey: Array<UByteArray> = expandKey()
|
||||||
@ -235,7 +235,7 @@ internal class AesPure internal constructor(val aesKey: AesKey, val input: UByte
|
|||||||
|
|
||||||
temp[0] = temp[0] xor rcon[i / aesKey.numberOf32BitWords]
|
temp[0] = temp[0] xor rcon[i / aesKey.numberOf32BitWords]
|
||||||
|
|
||||||
} else if (aesKey is AesKey.Aes256Key && i % aesKey.numberOf32BitWords == 4) {
|
} else if (aesKey is InternalAesKey.Aes256Key && i % aesKey.numberOf32BitWords == 4) {
|
||||||
temp[0] = getSBoxValue(temp[0])
|
temp[0] = getSBoxValue(temp[0])
|
||||||
temp[1] = getSBoxValue(temp[1])
|
temp[1] = getSBoxValue(temp[1])
|
||||||
temp[2] = getSBoxValue(temp[2])
|
temp[2] = getSBoxValue(temp[2])
|
||||||
|
@ -37,7 +37,7 @@ class AesCbcTest {
|
|||||||
val plaintext = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
val plaintext = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
||||||
val expectedCipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7"
|
val expectedCipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7"
|
||||||
val aesCbc =
|
val aesCbc =
|
||||||
AesCbcPure(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initializationVector = iv.hexStringToUByteArray())
|
AesCbcPure(InternalAesKey.Aes128Key(key), mode = Mode.ENCRYPT, initializationVector = iv.hexStringToUByteArray())
|
||||||
aesCbc.addData(plaintext.hexStringToUByteArray())
|
aesCbc.addData(plaintext.hexStringToUByteArray())
|
||||||
val encrypted = aesCbc.encrypt()
|
val encrypted = aesCbc.encrypt()
|
||||||
println("Encrypted: ${encrypted.encryptedData.toHexString()}")
|
println("Encrypted: ${encrypted.encryptedData.toHexString()}")
|
||||||
@ -54,7 +54,7 @@ class AesCbcTest {
|
|||||||
fun testEncryptionApi() {
|
fun testEncryptionApi() {
|
||||||
assertTrue {
|
assertTrue {
|
||||||
val keyString = "4278b840fb44aaa757c1bf04acbe1a3e"
|
val keyString = "4278b840fb44aaa757c1bf04acbe1a3e"
|
||||||
val key = AesKey.Aes128Key(keyString)
|
val key = InternalAesKey.Aes128Key(keyString)
|
||||||
|
|
||||||
val plainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
val plainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ class AesCbcTest {
|
|||||||
val cipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7"
|
val cipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7"
|
||||||
val expectedPlainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
val expectedPlainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
||||||
val aesCbc =
|
val aesCbc =
|
||||||
AesCbcPure(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initializationVector = iv.hexStringToUByteArray())
|
AesCbcPure(InternalAesKey.Aes128Key(key), mode = Mode.DECRYPT, initializationVector = iv.hexStringToUByteArray())
|
||||||
aesCbc.addData(cipherText.hexStringToUByteArray())
|
aesCbc.addData(cipherText.hexStringToUByteArray())
|
||||||
val decrypted = aesCbc.decrypt()
|
val decrypted = aesCbc.decrypt()
|
||||||
println("Decrypted: ${decrypted.toHexString()}")
|
println("Decrypted: ${decrypted.toHexString()}")
|
||||||
@ -95,7 +95,7 @@ class AesCbcTest {
|
|||||||
val iv = "57f02a5c5339daeb0a2908a06ac6393f"
|
val iv = "57f02a5c5339daeb0a2908a06ac6393f"
|
||||||
val cipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7"
|
val cipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7"
|
||||||
val expectedPlainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
val expectedPlainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
||||||
val decrypted = AesCbcPure.decrypt(AesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), iv.hexStringToUByteArray())
|
val decrypted = AesCbcPure.decrypt(InternalAesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), iv.hexStringToUByteArray())
|
||||||
println("Decrypted: ${decrypted.toHexString()}")
|
println("Decrypted: ${decrypted.toHexString()}")
|
||||||
|
|
||||||
expectedPlainText == decrypted.toHexString()
|
expectedPlainText == decrypted.toHexString()
|
||||||
|
@ -38,7 +38,7 @@ class AesCtrTest {
|
|||||||
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
||||||
val expectedCipherText =
|
val expectedCipherText =
|
||||||
"874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"
|
"874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"
|
||||||
val aesCtr = AesCtrPure(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initialCounter = ic.hexStringToUByteArray())
|
val aesCtr = AesCtrPure(InternalAesKey.Aes128Key(key), mode = Mode.ENCRYPT, initialCounter = ic.hexStringToUByteArray())
|
||||||
aesCtr.addData(
|
aesCtr.addData(
|
||||||
plaintext.hexStringToUByteArray()
|
plaintext.hexStringToUByteArray()
|
||||||
)
|
)
|
||||||
@ -54,7 +54,7 @@ class AesCtrTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testEncryptionApi() {
|
fun testEncryptionApi() {
|
||||||
val keyString = "4278b840fb44aaa757c1bf04acbe1a3e"
|
val keyString = "4278b840fb44aaa757c1bf04acbe1a3e"
|
||||||
val key = AesKey.Aes128Key(keyString)
|
val key = InternalAesKey.Aes128Key(keyString)
|
||||||
val plainText = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
val plainText = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
||||||
|
|
||||||
val encryptedDataAndInitializationVector = AesCtrPure.encrypt(key, plainText.hexStringToUByteArray())
|
val encryptedDataAndInitializationVector = AesCtrPure.encrypt(key, plainText.hexStringToUByteArray())
|
||||||
@ -77,7 +77,7 @@ class AesCtrTest {
|
|||||||
"874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"
|
"874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"
|
||||||
val expectedPlainText =
|
val expectedPlainText =
|
||||||
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
||||||
val aesCtr = AesCtrPure(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initialCounter = ic.hexStringToUByteArray())
|
val aesCtr = AesCtrPure(InternalAesKey.Aes128Key(key), mode = Mode.DECRYPT, initialCounter = ic.hexStringToUByteArray())
|
||||||
aesCtr.addData(cipherText.hexStringToUByteArray())
|
aesCtr.addData(cipherText.hexStringToUByteArray())
|
||||||
val decrypted = aesCtr.decrypt()
|
val decrypted = aesCtr.decrypt()
|
||||||
println("Decrypted: ${decrypted.toHexString()}")
|
println("Decrypted: ${decrypted.toHexString()}")
|
||||||
@ -97,7 +97,7 @@ class AesCtrTest {
|
|||||||
"874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"
|
"874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"
|
||||||
val expectedPlainText =
|
val expectedPlainText =
|
||||||
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
||||||
val decrypted = AesCtrPure.decrypt(AesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), ic.hexStringToUByteArray())
|
val decrypted = AesCtrPure.decrypt(InternalAesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), ic.hexStringToUByteArray())
|
||||||
println("Decrypted: ${decrypted.toHexString()}")
|
println("Decrypted: ${decrypted.toHexString()}")
|
||||||
expectedPlainText == decrypted.toHexString()
|
expectedPlainText == decrypted.toHexString()
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ class AesTest {
|
|||||||
ubyteArrayOf(0U, 0U, 0U, 0U),
|
ubyteArrayOf(0U, 0U, 0U, 0U),
|
||||||
ubyteArrayOf(0U, 0U, 0U, 0U)
|
ubyteArrayOf(0U, 0U, 0U, 0U)
|
||||||
)
|
)
|
||||||
val aes = AesPure(AesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
val aes = AesPure(InternalAesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
||||||
fakeState.copyInto(aes.state)
|
fakeState.copyInto(aes.state)
|
||||||
aes.subBytes()
|
aes.subBytes()
|
||||||
assertTrue {
|
assertTrue {
|
||||||
@ -42,7 +42,7 @@ class AesTest {
|
|||||||
ubyteArrayOf(2U, 3U, 0U, 1U),
|
ubyteArrayOf(2U, 3U, 0U, 1U),
|
||||||
ubyteArrayOf(3U, 0U, 1U, 2U)
|
ubyteArrayOf(3U, 0U, 1U, 2U)
|
||||||
)
|
)
|
||||||
val aes = AesPure(AesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
val aes = AesPure(InternalAesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
||||||
fakeState.copyInto(aes.state)
|
fakeState.copyInto(aes.state)
|
||||||
aes.shiftRows()
|
aes.shiftRows()
|
||||||
assertTrue {
|
assertTrue {
|
||||||
@ -56,7 +56,7 @@ class AesTest {
|
|||||||
assertTrue {
|
assertTrue {
|
||||||
val a = 0x57U
|
val a = 0x57U
|
||||||
val b = 0x83U
|
val b = 0x83U
|
||||||
val aes = AesPure(AesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
val aes = AesPure(InternalAesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
||||||
val c = aes.galoisFieldMultiply(a.toUByte(), b.toUByte())
|
val c = aes.galoisFieldMultiply(a.toUByte(), b.toUByte())
|
||||||
c == 0xC1U.toUByte()
|
c == 0xC1U.toUByte()
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@ class AesTest {
|
|||||||
assertTrue {
|
assertTrue {
|
||||||
val a = 0x57U
|
val a = 0x57U
|
||||||
val b = 0x13U
|
val b = 0x13U
|
||||||
val aes = AesPure(AesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
val aes = AesPure(InternalAesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
||||||
val c = aes.galoisFieldMultiply(a.toUByte(), b.toUByte())
|
val c = aes.galoisFieldMultiply(a.toUByte(), b.toUByte())
|
||||||
c == 0xFEU.toUByte()
|
c == 0xFEU.toUByte()
|
||||||
}
|
}
|
||||||
@ -89,7 +89,7 @@ class AesTest {
|
|||||||
ubyteArrayOf(0xbcU, 0x9dU, 0x01U, 0xc6U)
|
ubyteArrayOf(0xbcU, 0x9dU, 0x01U, 0xc6U)
|
||||||
)
|
)
|
||||||
|
|
||||||
val aes = AesPure(AesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
val aes = AesPure(InternalAesKey.Aes128Key(irrelevantKey), irrelevantInput)
|
||||||
fakeState.copyInto(aes.state)
|
fakeState.copyInto(aes.state)
|
||||||
aes.mixColumns()
|
aes.mixColumns()
|
||||||
assertTrue {
|
assertTrue {
|
||||||
@ -116,7 +116,7 @@ class AesTest {
|
|||||||
).toTypedArray()
|
).toTypedArray()
|
||||||
|
|
||||||
|
|
||||||
val aes = AesPure(AesKey.Aes128Key(key), irrelevantInput)
|
val aes = AesPure(InternalAesKey.Aes128Key(key), irrelevantInput)
|
||||||
val result = aes.expandedKey.map {
|
val result = aes.expandedKey.map {
|
||||||
it.foldIndexed(0U) { index, acc, uByte ->
|
it.foldIndexed(0U) { index, acc, uByte ->
|
||||||
acc + (uByte.toUInt() shl (24 - index * 8))
|
acc + (uByte.toUInt() shl (24 - index * 8))
|
||||||
@ -140,7 +140,7 @@ class AesTest {
|
|||||||
).toTypedArray()
|
).toTypedArray()
|
||||||
|
|
||||||
|
|
||||||
val aes = AesPure(AesKey.Aes192Key(key), irrelevantInput)
|
val aes = AesPure(InternalAesKey.Aes192Key(key), irrelevantInput)
|
||||||
val result = aes.expandedKey.map {
|
val result = aes.expandedKey.map {
|
||||||
it.foldIndexed(0U) { index, acc, uByte ->
|
it.foldIndexed(0U) { index, acc, uByte ->
|
||||||
acc + (uByte.toUInt() shl (24 - index * 8))
|
acc + (uByte.toUInt() shl (24 - index * 8))
|
||||||
@ -166,7 +166,7 @@ class AesTest {
|
|||||||
).toTypedArray()
|
).toTypedArray()
|
||||||
|
|
||||||
|
|
||||||
val aes = AesPure(AesKey.Aes256Key(key), irrelevantInput)
|
val aes = AesPure(InternalAesKey.Aes256Key(key), irrelevantInput)
|
||||||
val result = aes.expandedKey.map {
|
val result = aes.expandedKey.map {
|
||||||
it.foldIndexed(0U) { index, acc, uByte ->
|
it.foldIndexed(0U) { index, acc, uByte ->
|
||||||
acc + (uByte.toUInt() shl (24 - index * 8))
|
acc + (uByte.toUInt() shl (24 - index * 8))
|
||||||
@ -183,7 +183,7 @@ class AesTest {
|
|||||||
val key = "2b7e151628aed2a6abf7158809cf4f3c"
|
val key = "2b7e151628aed2a6abf7158809cf4f3c"
|
||||||
val expectedResult = "3925841d02dc09fbdc118597196a0b32"
|
val expectedResult = "3925841d02dc09fbdc118597196a0b32"
|
||||||
|
|
||||||
val aes = AesPure(AesKey.Aes128Key(key), input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
val aes = AesPure(InternalAesKey.Aes128Key(key), input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
||||||
val result = aes.encrypt()
|
val result = aes.encrypt()
|
||||||
assertTrue {
|
assertTrue {
|
||||||
result.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
result.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
||||||
@ -197,12 +197,12 @@ class AesTest {
|
|||||||
val key = "2b7e151628aed2a6abf7158809cf4f3c"
|
val key = "2b7e151628aed2a6abf7158809cf4f3c"
|
||||||
val expectedResult = "3925841d02dc09fbdc118597196a0b32"
|
val expectedResult = "3925841d02dc09fbdc118597196a0b32"
|
||||||
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()
|
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()
|
||||||
val aes = AesPure(AesKey.Aes128Key(key), original)
|
val aes = AesPure(InternalAesKey.Aes128Key(key), original)
|
||||||
val encrypted = aes.encrypt()
|
val encrypted = aes.encrypt()
|
||||||
assertTrue {
|
assertTrue {
|
||||||
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
||||||
}
|
}
|
||||||
val decrypted = AesPure.decrypt(AesKey.Aes128Key(key), encrypted)
|
val decrypted = AesPure.decrypt(InternalAesKey.Aes128Key(key), encrypted)
|
||||||
|
|
||||||
decrypted.contentEquals(original)
|
decrypted.contentEquals(original)
|
||||||
}
|
}
|
||||||
@ -211,12 +211,12 @@ class AesTest {
|
|||||||
val key = "000102030405060708090a0b0c0d0e0f"
|
val key = "000102030405060708090a0b0c0d0e0f"
|
||||||
val expectedResult = "69c4e0d86a7b0430d8cdb78070b4c55a"
|
val expectedResult = "69c4e0d86a7b0430d8cdb78070b4c55a"
|
||||||
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()
|
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()
|
||||||
val aes = AesPure(AesKey.Aes128Key(key), original)
|
val aes = AesPure(InternalAesKey.Aes128Key(key), original)
|
||||||
val encrypted = aes.encrypt()
|
val encrypted = aes.encrypt()
|
||||||
assertTrue {
|
assertTrue {
|
||||||
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
||||||
}
|
}
|
||||||
val aesDec = AesPure(AesKey.Aes128Key(key), encrypted)
|
val aesDec = AesPure(InternalAesKey.Aes128Key(key), encrypted)
|
||||||
val decrypted = aesDec.decrypt()
|
val decrypted = aesDec.decrypt()
|
||||||
assertTrue {
|
assertTrue {
|
||||||
aesDec.expandedKey.contentDeepEquals(aes.expandedKey)
|
aesDec.expandedKey.contentDeepEquals(aes.expandedKey)
|
||||||
@ -229,11 +229,11 @@ class AesTest {
|
|||||||
val key = "000102030405060708090a0b0c0d0e0f"
|
val key = "000102030405060708090a0b0c0d0e0f"
|
||||||
val expectedResult = "69c4e0d86a7b0430d8cdb78070b4c55a"
|
val expectedResult = "69c4e0d86a7b0430d8cdb78070b4c55a"
|
||||||
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()
|
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()
|
||||||
val encrypted = AesPure.encrypt(AesKey.Aes128Key(key), original)
|
val encrypted = AesPure.encrypt(InternalAesKey.Aes128Key(key), original)
|
||||||
assertTrue {
|
assertTrue {
|
||||||
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
||||||
}
|
}
|
||||||
val decrypted = AesPure.decrypt(AesKey.Aes128Key(key), encrypted)
|
val decrypted = AesPure.decrypt(InternalAesKey.Aes128Key(key), encrypted)
|
||||||
decrypted.contentEquals(original)
|
decrypted.contentEquals(original)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,11 +242,11 @@ class AesTest {
|
|||||||
val key = "000102030405060708090a0b0c0d0e0f1011121314151617"
|
val key = "000102030405060708090a0b0c0d0e0f1011121314151617"
|
||||||
val expectedResult = "dda97ca4864cdfe06eaf70a0ec0d7191"
|
val expectedResult = "dda97ca4864cdfe06eaf70a0ec0d7191"
|
||||||
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()
|
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()
|
||||||
val encrypted = AesPure.encrypt(AesKey.Aes192Key(key), original)
|
val encrypted = AesPure.encrypt(InternalAesKey.Aes192Key(key), original)
|
||||||
assertTrue {
|
assertTrue {
|
||||||
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
||||||
}
|
}
|
||||||
val decrypted = AesPure.decrypt(AesKey.Aes192Key(key), encrypted)
|
val decrypted = AesPure.decrypt(InternalAesKey.Aes192Key(key), encrypted)
|
||||||
decrypted.contentEquals(original)
|
decrypted.contentEquals(original)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,11 +255,11 @@ class AesTest {
|
|||||||
val key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
|
val key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
|
||||||
val expectedResult = "8ea2b7ca516745bfeafc49904b496089"
|
val expectedResult = "8ea2b7ca516745bfeafc49904b496089"
|
||||||
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()
|
val original = input.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray()
|
||||||
val encrypted = AesPure.encrypt(AesKey.Aes256Key(key), original)
|
val encrypted = AesPure.encrypt(InternalAesKey.Aes256Key(key), original)
|
||||||
assertTrue {
|
assertTrue {
|
||||||
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
encrypted.contentEquals(expectedResult.chunked(2).map { it.toInt(16).toUByte() }.toUByteArray())
|
||||||
}
|
}
|
||||||
val decrypted = AesPure.decrypt(AesKey.Aes256Key(key), encrypted)
|
val decrypted = AesPure.decrypt(InternalAesKey.Aes256Key(key), encrypted)
|
||||||
decrypted.contentEquals(original)
|
decrypted.contentEquals(original)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user