Aes implemented
This commit is contained in:
parent
69c81ec8e9
commit
ec3b87db49
58
README.md
58
README.md
@ -7,6 +7,9 @@ Kotlin Multiplatform Crypto is a library for various cryptographic applications.
|
|||||||
|
|
||||||
This is an extremely early release, currently only consisting of Blake2b and SHA256 and 512.
|
This is an extremely early release, currently only consisting of Blake2b and SHA256 and 512.
|
||||||
|
|
||||||
|
API is very opinionated, ment to be used on both encrypting and decrypting side. The idea is that API leaves less room for
|
||||||
|
errors when using it.
|
||||||
|
|
||||||
## Notes & Roadmap
|
## Notes & Roadmap
|
||||||
|
|
||||||
**The API will move fast and break often until v1.0**
|
**The API will move fast and break often until v1.0**
|
||||||
@ -28,8 +31,6 @@ No.
|
|||||||
This is an experimental implementation, mostly for expanding personal understanding of cryptography.
|
This is an experimental implementation, mostly for expanding personal understanding of cryptography.
|
||||||
It's not peer reviewed, not guaranteed to be bug free, and not guaranteed to be secure.
|
It's not peer reviewed, not guaranteed to be bug free, and not guaranteed to be secure.
|
||||||
|
|
||||||
## Supported
|
|
||||||
|
|
||||||
## Hashing functions
|
## Hashing functions
|
||||||
* Blake2b
|
* Blake2b
|
||||||
* SHA512
|
* SHA512
|
||||||
@ -37,6 +38,7 @@ It's not peer reviewed, not guaranteed to be bug free, and not guaranteed to be
|
|||||||
|
|
||||||
## Symmetric cipher
|
## Symmetric cipher
|
||||||
* AES
|
* AES
|
||||||
|
* Modes: CBC, CTR
|
||||||
|
|
||||||
More to come.
|
More to come.
|
||||||
|
|
||||||
@ -129,6 +131,58 @@ val sha512 = Sha512()
|
|||||||
sha512.update("abc")
|
sha512.update("abc")
|
||||||
val result = sha512.digest()
|
val result = sha512.digest()
|
||||||
```
|
```
|
||||||
|
### Symmetric encryption
|
||||||
|
|
||||||
|
#### AES
|
||||||
|
|
||||||
|
Aes is available with CBC and CTR mode through `AesCbc` and `AesCtr` classes/objects.
|
||||||
|
Similarly to hashes you can either use stateless or updateable version.
|
||||||
|
|
||||||
|
Initialization vector, or counter states are chosen by the SDK automaticaly, and returned alongside encrypted data
|
||||||
|
|
||||||
|
##### Stateless AesCbc and AesCtr
|
||||||
|
|
||||||
|
AesCtr
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val keyString = "4278b840fb44aaa757c1bf04acbe1a3e"
|
||||||
|
val key = AesKey.Aes128Key(keyString)
|
||||||
|
val plainText = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
||||||
|
|
||||||
|
val encryptedDataAndInitializationVector = AesCtr.encrypt(key, plainText.hexStringToUByteArray())
|
||||||
|
val decrypted = AesCtr.decrypt(
|
||||||
|
key,
|
||||||
|
encryptedDataAndInitializationVector.encryptedData,
|
||||||
|
encryptedDataAndInitializationVector.initialCounter
|
||||||
|
)
|
||||||
|
plainText == decrypted.toHexString()
|
||||||
|
```
|
||||||
|
|
||||||
|
AesCbc
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
|
||||||
|
val keyString = "4278b840fb44aaa757c1bf04acbe1a3e"
|
||||||
|
val key = AesKey.Aes128Key(keyString)
|
||||||
|
|
||||||
|
val plainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
||||||
|
|
||||||
|
val encryptedDataAndInitializationVector = AesCbc.encrypt(key, plainText.hexStringToUByteArray())
|
||||||
|
val decrypted = AesCbc.decrypt(
|
||||||
|
key,
|
||||||
|
encryptedDataAndInitializationVector.encryptedData,
|
||||||
|
encryptedDataAndInitializationVector.initilizationVector
|
||||||
|
)
|
||||||
|
plainText == decrypted.toHexString()
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,6 +21,12 @@ import com.ionspin.kotlin.crypto.chunked
|
|||||||
import com.ionspin.kotlin.crypto.xor
|
import com.ionspin.kotlin.crypto.xor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Advanced encryption standard with cipher block chaining and PKCS #5
|
||||||
|
*
|
||||||
|
* For bulk encryption/decryption use [AesCbc.encrypt] and [AesCbc.decrypt]
|
||||||
|
*
|
||||||
|
* To get an instance of AesCbc and then feed it data sequentially with [addData] use [createEncryptor] and [createDecryptor]
|
||||||
|
*
|
||||||
* Created by Ugljesa Jovanovic
|
* Created by Ugljesa Jovanovic
|
||||||
* ugljesa.jovanovic@ionspin.com
|
* ugljesa.jovanovic@ionspin.com
|
||||||
* on 21-Sep-2019
|
* on 21-Sep-2019
|
||||||
@ -30,13 +36,39 @@ class AesCbc internal constructor(val aesKey: AesKey, val mode: Mode, initializa
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val BLOCK_BYTES = 16
|
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) : AesCbc {
|
||||||
|
return AesCbc(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) : AesCbc {
|
||||||
|
return AesCbc(aesKey, Mode.DECRYPT)
|
||||||
|
}
|
||||||
|
|
||||||
fun encrypt(aesKey: AesKey, data: Array<UByte>): Array<UByte> {
|
/**
|
||||||
|
* Bulk encryption, returns encrypted data and a random initialization vector
|
||||||
|
*/
|
||||||
|
fun encrypt(aesKey: AesKey, data: Array<UByte>): EncryptedDataAndInitializationVector {
|
||||||
val aesCbc = AesCbc(aesKey, Mode.ENCRYPT)
|
val aesCbc = AesCbc(aesKey, Mode.ENCRYPT)
|
||||||
aesCbc.addData(data)
|
aesCbc.addData(data)
|
||||||
return aesCbc.encrypt()
|
return aesCbc.encrypt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bulk decryption, returns decrypted data
|
||||||
|
*/
|
||||||
|
fun decrypt(aesKey: AesKey, data: Array<UByte>, initialCounter: Array<UByte>? = null): Array<UByte> {
|
||||||
|
val aesCbc = AesCbc(aesKey, Mode.DECRYPT, initialCounter)
|
||||||
|
aesCbc.addData(data)
|
||||||
|
return aesCbc.decrypt()
|
||||||
|
}
|
||||||
|
|
||||||
private fun padToBlock(unpadded: Array<UByte>): Array<UByte> {
|
private fun padToBlock(unpadded: Array<UByte>): Array<UByte> {
|
||||||
val paddingSize = 16 - unpadded.size
|
val paddingSize = 16 - unpadded.size
|
||||||
if (unpadded.size == BLOCK_BYTES) {
|
if (unpadded.size == BLOCK_BYTES) {
|
||||||
@ -109,7 +141,11 @@ class AesCbc internal constructor(val aesKey: AesKey, val mode: Mode, initializa
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun encrypt(): Array<UByte> {
|
/**
|
||||||
|
* Encrypt fed data and return it alongside the randomly chosen initialization vector
|
||||||
|
* @return Encrypted data and initialization vector
|
||||||
|
*/
|
||||||
|
fun encrypt(): EncryptedDataAndInitializationVector {
|
||||||
if (bufferCounter > 0) {
|
if (bufferCounter > 0) {
|
||||||
val lastBlockPadded = padToBlock(buffer)
|
val lastBlockPadded = padToBlock(buffer)
|
||||||
if (lastBlockPadded.size > BLOCK_BYTES) {
|
if (lastBlockPadded.size > BLOCK_BYTES) {
|
||||||
@ -120,9 +156,16 @@ class AesCbc internal constructor(val aesKey: AesKey, val mode: Mode, initializa
|
|||||||
output += consumeBlock(lastBlockPadded)
|
output += consumeBlock(lastBlockPadded)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return output.reversed().foldRight(Array<UByte>(0) { 0U }) { arrayOfUBytes, acc -> acc + arrayOfUBytes }
|
return EncryptedDataAndInitializationVector(
|
||||||
|
output.reversed().foldRight(Array<UByte>(0) { 0U }) { arrayOfUBytes, acc -> acc + arrayOfUBytes },
|
||||||
|
iv
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt data
|
||||||
|
* @return Decrypted data
|
||||||
|
*/
|
||||||
fun decrypt(): Array<UByte> {
|
fun decrypt(): Array<UByte> {
|
||||||
val removePaddingCount = output.last().last()
|
val removePaddingCount = output.last().last()
|
||||||
|
|
||||||
@ -170,3 +213,24 @@ class AesCbc internal constructor(val aesKey: AesKey, val mode: Mode, initializa
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
data class EncryptedDataAndInitializationVector(val encryptedData : Array<UByte>, val initilizationVector : Array<UByte>) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
@ -21,9 +21,17 @@ 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.chunked
|
import com.ionspin.kotlin.crypto.chunked
|
||||||
|
import com.ionspin.kotlin.crypto.symmetric.AesCtr.Companion.encrypt
|
||||||
import com.ionspin.kotlin.crypto.xor
|
import com.ionspin.kotlin.crypto.xor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
|
* Advanced encryption standard with counter mode
|
||||||
|
*
|
||||||
|
* For bulk encryption/decryption use [AesCtr.encrypt] and [AesCtr.decrypt]
|
||||||
|
*
|
||||||
|
* To get an instance of AesCtr and then feed it data sequentially with [addData] use [createEncryptor] and [createDecryptor]
|
||||||
|
*
|
||||||
* Created by Ugljesa Jovanovic
|
* Created by Ugljesa Jovanovic
|
||||||
* ugljesa.jovanovic@ionspin.com
|
* ugljesa.jovanovic@ionspin.com
|
||||||
* on 22-Sep-2019
|
* on 22-Sep-2019
|
||||||
@ -34,38 +42,38 @@ class AesCtr internal constructor(val aesKey: AesKey, val mode: Mode, initialCou
|
|||||||
companion object {
|
companion object {
|
||||||
const val BLOCK_BYTES = 16
|
const val BLOCK_BYTES = 16
|
||||||
|
|
||||||
val modularCreator = ModularBigInteger.creatorForModulo(BigInteger.ONE.shl(129) - 1)
|
val modularCreator = ModularBigInteger.creatorForModulo(BigInteger.ONE.shl(128) - 1)
|
||||||
|
/**
|
||||||
fun encrypt(aesKey: AesKey, data: Array<UByte>): Array<UByte> {
|
* Creates and returns AesCtr instance that can be fed data using [addData]. Once you have submitted all
|
||||||
val aesCbc = AesCbc(aesKey, Mode.ENCRYPT)
|
* data call [encrypt]
|
||||||
aesCbc.addData(data)
|
*/
|
||||||
return aesCbc.encrypt()
|
fun createEncryptor(aesKey: AesKey) : AesCtr {
|
||||||
|
return AesCtr(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) : AesCtr {
|
||||||
|
return AesCtr(aesKey, Mode.DECRYPT)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Bulk encryption, returns encrypted data and a random initial counter
|
||||||
|
*/
|
||||||
|
fun encrypt(aesKey: AesKey, data: Array<UByte>): EncryptedDataAndInitialCounter {
|
||||||
|
val aesCtr = AesCtr(aesKey, Mode.ENCRYPT)
|
||||||
|
aesCtr.addData(data)
|
||||||
|
return aesCtr.encrypt()
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Bulk decryption, returns decrypted data
|
||||||
|
*/
|
||||||
|
fun decrypt(aesKey: AesKey, data: Array<UByte>, initialCounter: Array<UByte>? = null): Array<UByte> {
|
||||||
|
val aesCtr = AesCtr(aesKey, Mode.DECRYPT, initialCounter)
|
||||||
|
aesCtr.addData(data)
|
||||||
|
return aesCtr.decrypt()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun padToBlock(unpadded: Array<UByte>): Array<UByte> {
|
|
||||||
val paddingSize = 16 - unpadded.size
|
|
||||||
if (unpadded.size == BLOCK_BYTES) {
|
|
||||||
return unpadded
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unpadded.size == BLOCK_BYTES) {
|
|
||||||
return Array(BLOCK_BYTES) {
|
|
||||||
BLOCK_BYTES.toUByte()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unpadded.size > BLOCK_BYTES) {
|
|
||||||
throw IllegalStateException("Block larger than 128 bytes")
|
|
||||||
}
|
|
||||||
|
|
||||||
return Array(BLOCK_BYTES) {
|
|
||||||
when (it) {
|
|
||||||
in unpadded.indices -> unpadded[it]
|
|
||||||
else -> paddingSize.toUByte()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentOutput: Array<UByte> = arrayOf()
|
var currentOutput: Array<UByte> = arrayOf()
|
||||||
@ -115,34 +123,32 @@ class AesCtr internal constructor(val aesKey: AesKey, val mode: Mode, initialCou
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
fun encrypt(): Array<UByte> {
|
* 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) {
|
if (bufferCounter > 0) {
|
||||||
val lastBlockPadded = padToBlock(buffer)
|
output += consumeBlock(buffer, blockCounter)
|
||||||
if (lastBlockPadded.size > BLOCK_BYTES) {
|
|
||||||
val chunks = lastBlockPadded.chunked(BLOCK_BYTES)
|
|
||||||
output += consumeBlock(chunks[0], blockCounter)
|
|
||||||
blockCounter += 1
|
|
||||||
output += consumeBlock(chunks[1], blockCounter)
|
|
||||||
} else {
|
|
||||||
output += consumeBlock(lastBlockPadded, blockCounter)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return output.reversed().foldRight(Array<UByte>(0) { 0U }) { arrayOfUBytes, acc -> acc + arrayOfUBytes }
|
return EncryptedDataAndInitialCounter(
|
||||||
|
output.reversed().foldRight(Array<UByte>(0) { 0U }) { arrayOfUBytes, acc -> acc + arrayOfUBytes },
|
||||||
|
counterStart
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Decrypt data
|
||||||
|
* @return Decrypted data
|
||||||
|
*/
|
||||||
fun decrypt(): Array<UByte> {
|
fun decrypt(): Array<UByte> {
|
||||||
val removePaddingCount = output.last().last()
|
if (bufferCounter > 0) {
|
||||||
val removedPadding = if (removePaddingCount > 0U && removePaddingCount < 16U) {
|
output += consumeBlock(buffer, blockCounter)
|
||||||
output.last().dropLast(removePaddingCount.toInt() and 0x7F)
|
|
||||||
} else {
|
|
||||||
output.last().toList()
|
|
||||||
}
|
}
|
||||||
val preparedOutput = output.dropLast(1).toTypedArray() + removedPadding.toTypedArray()
|
|
||||||
//JS compiler freaks out here if we don't supply exact type
|
//JS compiler freaks out here if we don't supply exact type
|
||||||
val reversed : List<Array<UByte>> = preparedOutput.reversed() as List<Array<UByte>>
|
val reversed: List<Array<UByte>> = output.reversed() as List<Array<UByte>>
|
||||||
val folded : Array<UByte> = reversed.foldRight(Array<UByte>(0) { 0U }) { arrayOfUBytes, acc ->
|
val folded: Array<UByte> = reversed.foldRight(Array<UByte>(0) { 0U }) { arrayOfUBytes, acc ->
|
||||||
acc + arrayOfUBytes }
|
acc + arrayOfUBytes
|
||||||
|
}
|
||||||
return folded
|
return folded
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,3 +170,24 @@ class AesCtr internal constructor(val aesKey: AesKey, val mode: Mode, initialCou
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
data class EncryptedDataAndInitialCounter(val encryptedData : Array<UByte>, val initialCounter : Array<UByte>) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
@ -31,43 +31,67 @@ class AesCbcTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testCbcEncryption() {
|
fun testCbcEncryption() {
|
||||||
val key = "4278b840fb44aaa757c1bf04acbe1a3e"
|
|
||||||
val iv = "57f02a5c5339daeb0a2908a06ac6393f"
|
|
||||||
val plaintext = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
|
||||||
val expectedCipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7"
|
|
||||||
val aesCbc = AesCbc(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initializationVector = iv.hexStringToUByteArray())
|
|
||||||
aesCbc.addData(plaintext.hexStringToUByteArray())
|
|
||||||
val encrypted = aesCbc.encrypt()
|
|
||||||
println("Encrypted: ${encrypted.toHexString()}")
|
|
||||||
assertTrue {
|
assertTrue {
|
||||||
expectedCipherText == encrypted.toHexString()
|
val key = "4278b840fb44aaa757c1bf04acbe1a3e"
|
||||||
|
val iv = "57f02a5c5339daeb0a2908a06ac6393f"
|
||||||
|
val plaintext = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
||||||
|
val expectedCipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7"
|
||||||
|
val aesCbc =
|
||||||
|
AesCbc(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initializationVector = iv.hexStringToUByteArray())
|
||||||
|
aesCbc.addData(plaintext.hexStringToUByteArray())
|
||||||
|
val encrypted = aesCbc.encrypt()
|
||||||
|
println("Encrypted: ${encrypted.encryptedData.toHexString()}")
|
||||||
|
|
||||||
|
expectedCipherText == encrypted.encryptedData.toHexString() &&
|
||||||
|
iv == encrypted.initilizationVector.toHexString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assertTrue {
|
||||||
|
val keyString = "4278b840fb44aaa757c1bf04acbe1a3e"
|
||||||
|
val key = AesKey.Aes128Key(keyString)
|
||||||
|
|
||||||
|
val plainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
||||||
|
|
||||||
|
val encryptedDataAndInitializationVector = AesCbc.encrypt(key, plainText.hexStringToUByteArray())
|
||||||
|
val decrypted = AesCbc.decrypt(
|
||||||
|
key,
|
||||||
|
encryptedDataAndInitializationVector.encryptedData,
|
||||||
|
encryptedDataAndInitializationVector.initilizationVector
|
||||||
|
)
|
||||||
|
plainText == decrypted.toHexString()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testCbcDecryption() {
|
fun testCbcDecryption() {
|
||||||
val key = "4278b840fb44aaa757c1bf04acbe1a3e"
|
|
||||||
val iv = "57f02a5c5339daeb0a2908a06ac6393f"
|
|
||||||
val cipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7"
|
|
||||||
val expectedPlainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
|
||||||
val aesCbc = AesCbc(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initializationVector = iv.hexStringToUByteArray())
|
|
||||||
aesCbc.addData(cipherText.hexStringToUByteArray())
|
|
||||||
val decrypted = aesCbc.decrypt()
|
|
||||||
println("Decrypted: ${decrypted.toHexString()}")
|
|
||||||
assertTrue {
|
assertTrue {
|
||||||
|
val key = "4278b840fb44aaa757c1bf04acbe1a3e"
|
||||||
|
val iv = "57f02a5c5339daeb0a2908a06ac6393f"
|
||||||
|
val cipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7"
|
||||||
|
val expectedPlainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
||||||
|
val aesCbc =
|
||||||
|
AesCbc(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initializationVector = iv.hexStringToUByteArray())
|
||||||
|
aesCbc.addData(cipherText.hexStringToUByteArray())
|
||||||
|
val decrypted = aesCbc.decrypt()
|
||||||
|
println("Decrypted: ${decrypted.toHexString()}")
|
||||||
|
|
||||||
|
expectedPlainText == decrypted.toHexString()
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue {
|
||||||
|
val key = "4278b840fb44aaa757c1bf04acbe1a3e"
|
||||||
|
val iv = "57f02a5c5339daeb0a2908a06ac6393f"
|
||||||
|
val cipherText = "479c89ec14bc98994e62b2c705b5014e175bd7832e7e60a1e92aac568a861eb7"
|
||||||
|
val expectedPlainText = "3c888bbbb1a8eb9f3e9b87acaad986c466e2f7071c83083b8a557971918850e5"
|
||||||
|
val decrypted = AesCbc.decrypt(AesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), iv.hexStringToUByteArray())
|
||||||
|
println("Decrypted: ${decrypted.toHexString()}")
|
||||||
|
|
||||||
expectedPlainText == decrypted.toHexString()
|
expectedPlainText == decrypted.toHexString()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -31,45 +31,67 @@ class AesCtrTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testCtrEncryption() {
|
fun testCtrEncryption() {
|
||||||
val key = "2b7e151628aed2a6abf7158809cf4f3c"
|
|
||||||
val ic = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
|
|
||||||
val plaintext = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
|
||||||
val expectedCipherText = "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"
|
|
||||||
val aesCbc = AesCtr(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initialCounter = ic.hexStringToUByteArray())
|
|
||||||
aesCbc.addData(
|
|
||||||
plaintext.hexStringToUByteArray()
|
|
||||||
)
|
|
||||||
val encrypted = aesCbc.encrypt()
|
|
||||||
println("Encrypted: ${encrypted.toHexString()}")
|
|
||||||
assertTrue {
|
assertTrue {
|
||||||
expectedCipherText == encrypted.toHexString()
|
val key = "2b7e151628aed2a6abf7158809cf4f3c"
|
||||||
|
val ic = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
|
||||||
|
val plaintext =
|
||||||
|
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
||||||
|
val expectedCipherText =
|
||||||
|
"874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"
|
||||||
|
val aesCtr = AesCtr(AesKey.Aes128Key(key), mode = Mode.ENCRYPT, initialCounter = ic.hexStringToUByteArray())
|
||||||
|
aesCtr.addData(
|
||||||
|
plaintext.hexStringToUByteArray()
|
||||||
|
)
|
||||||
|
val encrypted = aesCtr.encrypt()
|
||||||
|
println("Encrypted: ${encrypted.encryptedData.toHexString()}")
|
||||||
|
|
||||||
|
expectedCipherText == encrypted.encryptedData.toHexString() &&
|
||||||
|
ic == encrypted.initialCounter.toHexString()
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue {
|
||||||
|
val keyString = "4278b840fb44aaa757c1bf04acbe1a3e"
|
||||||
|
val key = AesKey.Aes128Key(keyString)
|
||||||
|
val plainText = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
||||||
|
|
||||||
|
val encryptedDataAndInitializationVector = AesCtr.encrypt(key, plainText.hexStringToUByteArray())
|
||||||
|
val decrypted = AesCtr.decrypt(
|
||||||
|
key,
|
||||||
|
encryptedDataAndInitializationVector.encryptedData,
|
||||||
|
encryptedDataAndInitializationVector.initialCounter
|
||||||
|
)
|
||||||
|
plainText == decrypted.toHexString()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testCtrDecryption() {
|
fun testCtrDecryption() {
|
||||||
val key = "2b7e151628aed2a6abf7158809cf4f3c"
|
|
||||||
val ic = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
|
|
||||||
val cipherText = "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"
|
|
||||||
val expectedPlainText = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
|
||||||
val aesCbc = AesCtr(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initialCounter = ic.hexStringToUByteArray())
|
|
||||||
aesCbc.addData(cipherText.hexStringToUByteArray())
|
|
||||||
val decrypted = aesCbc.decrypt()
|
|
||||||
println("Decrypted: ${decrypted.toHexString()}")
|
|
||||||
assertTrue {
|
assertTrue {
|
||||||
|
val key = "2b7e151628aed2a6abf7158809cf4f3c"
|
||||||
|
val ic = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
|
||||||
|
val cipherText =
|
||||||
|
"874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"
|
||||||
|
val expectedPlainText =
|
||||||
|
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
||||||
|
val aesCtr = AesCtr(AesKey.Aes128Key(key), mode = Mode.DECRYPT, initialCounter = ic.hexStringToUByteArray())
|
||||||
|
aesCtr.addData(cipherText.hexStringToUByteArray())
|
||||||
|
val decrypted = aesCtr.decrypt()
|
||||||
|
println("Decrypted: ${decrypted.toHexString()}")
|
||||||
|
expectedPlainText == decrypted.toHexString()
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue {
|
||||||
|
val key = "2b7e151628aed2a6abf7158809cf4f3c"
|
||||||
|
val ic = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
|
||||||
|
val cipherText =
|
||||||
|
"874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"
|
||||||
|
val expectedPlainText =
|
||||||
|
"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"
|
||||||
|
val decrypted = AesCtr.decrypt(AesKey.Aes128Key(key), cipherText.hexStringToUByteArray(), ic.hexStringToUByteArray())
|
||||||
|
println("Decrypted: ${decrypted.toHexString()}")
|
||||||
expectedPlainText == decrypted.toHexString()
|
expectedPlainText == decrypted.toHexString()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user